#
|
# Copyright 2018 - The Android Open Source Project
|
#
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
# you may not use this file except in compliance with the License.
|
# You may obtain a copy of the License at
|
#
|
# http://www.apache.org/licenses/LICENSE-2.0
|
#
|
# Unless required by applicable law or agreed to in writing, software
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# See the License for the specific language governing permissions and
|
# limitations under the License.
|
#
|
|
import imp
|
import os
|
import sys
|
import time
|
|
from fabric.api import env
|
from fabric.api import local
|
from fabric.api import run
|
from fabric.api import settings
|
from fabric.api import sudo
|
from fabric.contrib.files import contains
|
from fabric.contrib.files import exists
|
from fabric.context_managers import cd
|
|
_PIP_REQUIREMENTS_PATHS = [
|
"test/vts/script/pip_requirements.txt",
|
"test/framework/harnesses/host_controller/script/pip_requirements.txt"
|
]
|
|
# Path to the file that contains the abs path to the deployed vtslab pakcage.
|
_VTSLAB_PACKAGE_PATH_FILENAME = ".vtslab_package_path"
|
|
# Zone filter list for GCE instances.
|
_DEFAULT_GCE_ZONE_LIST = [
|
"us-east1-b",
|
"asia-northeast1-a",
|
]
|
|
|
def SetPassword(password):
|
"""Sets password for hosts to access through ssh and to run sudo commands
|
|
usage: $ fab SetPassword:<password for hosts>
|
|
Args:
|
password: string, password for hosts.
|
"""
|
env.password = password
|
|
|
def GetHosts(hosts_file_path, gce_instance_name=None, account=None):
|
"""Configures env.hosts to a given list of hosts.
|
|
usage: $ fab GetHosts:<path to a source file contains hosts info>
|
|
Args:
|
hosts_file_path: string, path to a python file passed from command file
|
input.
|
gce_instance_name: string, GCE instance name.
|
account: string, account name used for the ssh connection.
|
"""
|
if hosts_file_path.endswith(".py"):
|
hosts_module = imp.load_source('hosts_module', hosts_file_path)
|
env.hosts = hosts_module.EmitHostList()
|
else:
|
if not gce_instance_name or not account:
|
print(
|
"Please specify gce_instance_name and account using -H option. "
|
"Example: -H <Google_Cloud_project>,<GCE_instance>,<account>")
|
sys.exit(0)
|
env.key_filename = "~/.ssh/google_compute_engine"
|
gce_list_out = local(
|
"gcloud compute instances list --project=%s --filter=\"zone:(%s)\""
|
% (hosts_file_path, " ".join(_DEFAULT_GCE_ZONE_LIST)),
|
capture=True)
|
for line in gce_list_out.split("\n")[1:]:
|
if line.startswith(gce_instance_name):
|
env.hosts.append("%s@%s" % (account, line.strip().split()[-2]))
|
|
|
def SetupIptables(ip_address_file_path):
|
"""Configures iptables setting for all hosts listed.
|
|
usage: $ fab SetupIptables:<path to a source file contains ip addresses of
|
certified machines>
|
|
Args:
|
ip_address_file_path: string, path to a python file passed from command
|
file input.
|
"""
|
ip_addresses_module = imp.load_source('ip_addresses_module',
|
ip_address_file_path)
|
ip_address_list = ip_addresses_module.EmitIPAddressList()
|
|
sudo("apt-get install -y iptables-persistent")
|
sudo("iptables -P INPUT ACCEPT")
|
sudo("iptables -P FORWARD ACCEPT")
|
sudo("iptables -F")
|
|
for ip_address in ip_address_list:
|
sudo(
|
"iptables -A INPUT -p tcp -s %s --dport 22 -j ACCEPT" % ip_address)
|
|
sudo("iptables -P INPUT DROP")
|
sudo("iptables -P FORWARD DROP")
|
sudo("iptables -A INPUT -p icmp -j ACCEPT")
|
sudo("netfilter-persistent save")
|
sudo("netfilter-persistent reload")
|
|
|
def SetupSudoers():
|
"""Append sudo rules for vtslab user.
|
|
usage: $ fab SetupSudoers
|
"""
|
if not contains("/etc/sudoers", "vtslab", use_sudo=True):
|
sudo("echo '' | sudo tee -a /etc/sudoers")
|
sudo("echo '# Let vtslab account have all authorization' | "
|
"sudo tee -a /etc/sudoers")
|
sudo("echo 'vtslab ALL=(ALL:ALL) ALL' | sudo tee -a /etc/sudoers")
|
|
|
def SetupUSBPermission():
|
"""Sets up the USB permission for adb and fastboot.
|
|
usage: $ fab SetupUSBPermission
|
"""
|
sudo("curl --create-dirs -L -o /etc/udev/rules.d/51-android.rules -O -L "
|
"https://raw.githubusercontent.com/snowdream/51-android/master/"
|
"51-android.rules")
|
sudo("chmod a+r /etc/udev/rules.d/51-android.rules")
|
sudo("service udev restart")
|
|
|
def SetupADBVendorKeysEnvVar():
|
"""Appends scripts for ADB_VENDOR_KEYS path setup.
|
|
In setup step, this function looks into .bashrc file for this script, and
|
if there is not then appends the below scripts to .bashrc.
|
Later when shell env created (through ssh or screen instance creation time),
|
.bashrc file will look for _VTSLAB_PACKAGE_PATH_FILENAME and use the
|
contents of the file to set ADB_VENDOR_KEYS.
|
|
usage: $ fab SetupADBVendorKeysEnvVar
|
"""
|
if not contains("~/.bashrc", _VTSLAB_PACKAGE_PATH_FILENAME):
|
run("echo '' >> ~/.bashrc", )
|
run("echo '# Set $ADB_VENDOR_KEYS as paths to adb private key files "
|
"within the vtslab-package' >> ~/.bashrc")
|
run("echo 'if [ -f ~/%s ]; then' >> ~/.bashrc" %
|
_VTSLAB_PACKAGE_PATH_FILENAME)
|
run("echo ' export ADB_VENDOR_KEYS=$(find $(cat ~/%s)/android-vtslab/"
|
"testcases/DATA/ak -name \".*.ak\" | tr \"\\n\" \":\")' "
|
">> ~/.bashrc" % _VTSLAB_PACKAGE_PATH_FILENAME)
|
run("echo 'fi' >> ~/.bashrc")
|
|
|
def _CheckADBVendorKeysEnvVar(vtslab_package_file_name=""):
|
"""Checks if there is a change in ADB_VENDOR_KEYS env variable.
|
|
if there is, then the adbd needs to be restarted in the screen context
|
before running the HC.
|
|
Args:
|
vtslab_package_file_name: string, the HC package file name that is about
|
to be deployed.
|
|
Returns:
|
True if the list of the adb vendor key files have changed,
|
False otherwise.
|
"""
|
former_key_set = set()
|
current_key_set = set()
|
set_keyfile_set = lambda set, path_list: map(set.add, map(os.path.basename,
|
path_list))
|
vtslab_package_path_filepath = "~/%s" % _VTSLAB_PACKAGE_PATH_FILENAME
|
|
if exists(vtslab_package_path_filepath):
|
former_HC_package_path = run("cat %s" % vtslab_package_path_filepath)
|
former_HC_package_adbkey_path = os.path.join(
|
former_HC_package_path, "android-vtslab/testcases/DATA/ak")
|
if exists(former_HC_package_adbkey_path):
|
adb_vendor_keys_list = run("find %s -name \".*.ak\"" %
|
former_HC_package_adbkey_path).split()
|
set_keyfile_set(former_key_set, adb_vendor_keys_list)
|
|
if exists("~/run/%s.dir/android-vtslab/testcases/DATA/ak" %
|
vtslab_package_file_name):
|
adb_vendor_keys_list = run(
|
"find ~/run/%s.dir/android-vtslab/testcases/DATA/ak -name \".*.ak\""
|
% vtslab_package_file_name).split()
|
set_keyfile_set(current_key_set, adb_vendor_keys_list)
|
|
return former_key_set != current_key_set
|
|
|
def SetupPackages(ip_address_file_path=None):
|
"""Sets up the execution environment for vts `run` command.
|
|
Need to temporarily open the ports for apt-get and pip commands.
|
|
usage: $ fab SetupPackages
|
|
Args:
|
ip_address_file_path: string, path to a python file passed from command
|
file input. Will be passed to SetupIptables().
|
"""
|
sudo("iptables -P INPUT ACCEPT")
|
|
# todo : replace "kr.ubuntu." to "ubuntu" in /etc/apt/sources.list
|
sudo("apt-get upgrade -y")
|
sudo("apt-get update -y")
|
sudo("apt-get install -y git-core gnupg flex bison gperf build-essential "
|
"zip curl zlib1g-dev gcc-multilib g++-multilib x11proto-core-dev "
|
"libx11-dev lib32z-dev ccache libgl1-mesa-dev libxml2-utils xsltproc "
|
"unzip liblz4-tool udev screen")
|
|
sudo("apt-get install -y android-tools-adb")
|
sudo("usermod -aG plugdev $LOGNAME")
|
|
SetupUSBPermission()
|
|
sudo("apt-get update")
|
sudo("apt-get install -y python2.7")
|
sudo("apt-get install -y python-pip")
|
run("pip install --upgrade pip")
|
sudo("apt-get install -y python-virtualenv")
|
|
sudo("apt-get install -y python-dev python-protobuf protobuf-compiler "
|
"python-setuptools")
|
|
for req_path in _PIP_REQUIREMENTS_PATHS:
|
full_path = os.path.join(os.environ["ANDROID_BUILD_TOP"], req_path)
|
pip_requirement_list = []
|
try:
|
requirements_fd = open(full_path, "r")
|
lines = requirements_fd.readlines()
|
for line in lines:
|
req = line.rstrip()
|
if req != "" and not req.startswith("#"):
|
pip_requirement_list.append(req)
|
except IOError as e:
|
print("%s: %s" % (e.strerror, full_path))
|
return
|
sudo("pip install %s" % " ".join(pip_requirement_list))
|
|
sudo("pip install --upgrade protobuf")
|
|
lsb_result = run("lsb_release -c -s")
|
sudo("echo \"deb http://packages.cloud.google.com/apt cloud-sdk-%s "
|
"main\" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list" %
|
lsb_result)
|
sudo("curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | "
|
"sudo apt-key add -")
|
sudo("apt-get update && sudo apt-get install -y google-cloud-sdk")
|
sudo("apt-get install -y google-cloud-sdk-app-engine-java "
|
"google-cloud-sdk-app-engine-python kubectl")
|
|
sudo("apt-get install -y m4 bison")
|
|
if ip_address_file_path is not None:
|
SetupIptables(ip_address_file_path)
|
|
SetupADBVendorKeysEnvVar()
|
|
|
def DeployVtslab(vtslab_package_gcs_url=None):
|
"""Deploys vtslab package.
|
|
Fetches and deploy vtslab by going through the processes described below
|
1. Send the "exit --wait_for_jobs=True" command to all detached screen.
|
And let the screen to terminate itself.
|
2. Create a new screen instance that downloads and runs the new HC,
|
give password and device command to the HC without actually attaching it
|
|
usage: $ fab DeployVtslab -p <password> -H hosts.py -f <gs://vtslab-release/...>
|
|
Args:
|
vtslab_package_gcs_url: string, URL to a certain vtslab package file.
|
"""
|
if not vtslab_package_gcs_url:
|
print("Please specify vtslab package file URL using -f option.")
|
return
|
elif not vtslab_package_gcs_url.startswith("gs://vtslab-release/"):
|
print("Please spcify a valid URL for the vtslab package.")
|
return
|
else:
|
vti = "vtslab-schedule-" + vtslab_package_gcs_url[len(
|
"gs://vtslab-release/"):].split("/")[0] + ".appspot.com"
|
with settings(warn_only=True):
|
screen_list_result = run("screen -list")
|
lines = screen_list_result.split("\n")
|
for line in lines:
|
if "(Detached)" in line:
|
screen_name = line.split("\t")[1]
|
print(screen_name)
|
with settings(warn_only=True):
|
run("screen -S %s -X stuff \"exit --wait_for_jobs=True\"" %
|
screen_name)
|
run("screen -S %s -X stuff \"^M\"" % screen_name)
|
run("screen -S %s -X stuff \"exit\"" % screen_name)
|
run("screen -S %s -X stuff \"^M\"" % screen_name)
|
|
vtslab_package_file_name = os.path.basename(vtslab_package_gcs_url)
|
run("mkdir -p ~/run/%s.dir/" % vtslab_package_file_name)
|
with cd("~/run/%s.dir" % vtslab_package_file_name):
|
run("gsutil cp %s ./" % vtslab_package_gcs_url)
|
run("unzip -o %s" % vtslab_package_file_name)
|
adb_vendor_keys_changed = _CheckADBVendorKeysEnvVar(
|
vtslab_package_file_name)
|
run("pwd > ~/%s" % _VTSLAB_PACKAGE_PATH_FILENAME)
|
|
with cd("~/run/%s.dir/android-vtslab/tools" % vtslab_package_file_name):
|
new_screen_name = run("cat ../testcases/version.txt")
|
|
with cd("~/run/%s.dir/android-vtslab/tools" % vtslab_package_file_name):
|
run("./make_screen %s ; sleep 1" % new_screen_name)
|
|
if adb_vendor_keys_changed:
|
reset_adbd = ""
|
while reset_adbd.lower() not in ["y", "n"]:
|
if reset_adbd:
|
print("Please type 'y' or 'n'")
|
reset_adbd = raw_input(
|
"Reset adb server daemon on host %s (y/n)? " % env.host)
|
if reset_adbd.lower() == "y":
|
run("screen -S %s -X stuff \"adb kill-server^M\"" %
|
new_screen_name)
|
run("screen -S %s -X stuff \"adb start-server^M\"" %
|
new_screen_name)
|
run("screen -S %s -X stuff \"./run --vti=%s\"" % (new_screen_name, vti))
|
run("screen -S %s -X stuff \"^M\"" % new_screen_name)
|
time.sleep(5)
|
run("screen -S %s -X stuff \"password\"" % new_screen_name)
|
run("screen -S %s -X stuff \"^M\"" % new_screen_name)
|
run("screen -S %s -X stuff \"%s\"" % (new_screen_name, env.password))
|
run("screen -S %s -X stuff \"^M\"" % new_screen_name)
|
run("screen -S %s -X stuff \"device --lease=True\"" % new_screen_name)
|
run("screen -S %s -X stuff \"^M\"" % new_screen_name)
|
|
with cd("~/run/%s.dir" % vtslab_package_file_name):
|
run("rm %s" % vtslab_package_file_name)
|
|
|
def DeployGCE(vtslab_package_gcs_url=None):
|
"""Deploys a vtslab package to GCE nodes.
|
|
Fetches and deploy vtslab on monitor-hc by doing;
|
1. Download android-vtslab-<>.zip from GCS using the given URL and upzip it.
|
2. Send the Ctrl-c key input to all detached screen, then cursor-up
|
key input and enter key input, making the screen to execute
|
the last run command.
|
|
usage: $ fab DeployVtslab -p <password> -H <Google Cloud Platform project name> -f <gs://vtslab-release/...>
|
|
Args:
|
vtslab_package_gcs_url: string, URL to a certain vtslab package file.
|
"""
|
if not vtslab_package_gcs_url:
|
print("Please specify vtslab package file URL using -f option.")
|
return
|
elif not vtslab_package_gcs_url.startswith("gs://"):
|
print("Please spcify a valid URL for the vtslab package.")
|
return
|
|
vtslab_package_file_name = os.path.basename(vtslab_package_gcs_url)
|
with cd("~/run"):
|
run("gsutil cp %s ./" % vtslab_package_gcs_url)
|
run("unzip -o %s" % vtslab_package_file_name)
|
run("rm %s" % vtslab_package_file_name)
|
|
with settings(warn_only=True):
|
screen_list_result = run("screen -list")
|
lines = screen_list_result.split("\n")
|
for line in lines:
|
if "(Detached)" in line:
|
screen_name = line.split("\t")[1]
|
run("screen -S %s -X stuff \"^C\"" % screen_name)
|
run("screen -S %s -X stuff \"\033[A\"" % screen_name)
|
run("screen -S %s -X stuff \"^M\"" % screen_name)
|