1# 2# Copyright 2018 - The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16 17import imp 18import os 19import sys 20import time 21 22from fabric.api import env 23from fabric.api import local 24from fabric.api import run 25from fabric.api import settings 26from fabric.api import sudo 27from fabric.contrib.files import contains 28from fabric.contrib.files import exists 29from fabric.context_managers import cd 30 31_PIP_REQUIREMENTS_PATHS = [ 32 "test/vts/script/pip_requirements.txt", 33 "test/framework/harnesses/host_controller/script/pip_requirements.txt" 34] 35 36# Path to the file that contains the abs path to the deployed vtslab pakcage. 37_VTSLAB_PACKAGE_PATH_FILENAME = ".vtslab_package_path" 38 39# Zone filter list for GCE instances. 40_DEFAULT_GCE_ZONE_LIST = [ 41 "us-east1-b", 42 "asia-northeast1-a", 43] 44 45 46def SetPassword(password): 47 """Sets password for hosts to access through ssh and to run sudo commands 48 49 usage: $ fab SetPassword:<password for hosts> 50 51 Args: 52 password: string, password for hosts. 53 """ 54 env.password = password 55 56 57def GetHosts(hosts_file_path, gce_instance_name=None, account=None): 58 """Configures env.hosts to a given list of hosts. 59 60 usage: $ fab GetHosts:<path to a source file contains hosts info> 61 62 Args: 63 hosts_file_path: string, path to a python file passed from command file 64 input. 65 gce_instance_name: string, GCE instance name. 66 account: string, account name used for the ssh connection. 67 """ 68 if hosts_file_path.endswith(".py"): 69 hosts_module = imp.load_source('hosts_module', hosts_file_path) 70 env.hosts = hosts_module.EmitHostList() 71 else: 72 if not gce_instance_name or not account: 73 print( 74 "Please specify gce_instance_name and account using -H option. " 75 "Example: -H <Google_Cloud_project>,<GCE_instance>,<account>") 76 sys.exit(0) 77 env.key_filename = "~/.ssh/google_compute_engine" 78 gce_list_out = local( 79 "gcloud compute instances list --project=%s --filter=\"zone:(%s)\"" 80 % (hosts_file_path, " ".join(_DEFAULT_GCE_ZONE_LIST)), 81 capture=True) 82 for line in gce_list_out.split("\n")[1:]: 83 if line.startswith(gce_instance_name): 84 env.hosts.append("%s@%s" % (account, line.strip().split()[-2])) 85 86 87def SetupIptables(ip_address_file_path): 88 """Configures iptables setting for all hosts listed. 89 90 usage: $ fab SetupIptables:<path to a source file contains ip addresses of 91 certified machines> 92 93 Args: 94 ip_address_file_path: string, path to a python file passed from command 95 file input. 96 """ 97 ip_addresses_module = imp.load_source('ip_addresses_module', 98 ip_address_file_path) 99 ip_address_list = ip_addresses_module.EmitIPAddressList() 100 101 sudo("apt-get install -y iptables-persistent") 102 sudo("iptables -P INPUT ACCEPT") 103 sudo("iptables -P FORWARD ACCEPT") 104 sudo("iptables -F") 105 106 for ip_address in ip_address_list: 107 sudo( 108 "iptables -A INPUT -p tcp -s %s --dport 22 -j ACCEPT" % ip_address) 109 110 sudo("iptables -P INPUT DROP") 111 sudo("iptables -P FORWARD DROP") 112 sudo("iptables -A INPUT -p icmp -j ACCEPT") 113 sudo("netfilter-persistent save") 114 sudo("netfilter-persistent reload") 115 116 117def SetupSudoers(): 118 """Append sudo rules for vtslab user. 119 120 usage: $ fab SetupSudoers 121 """ 122 if not contains("/etc/sudoers", "vtslab", use_sudo=True): 123 sudo("echo '' | sudo tee -a /etc/sudoers") 124 sudo("echo '# Let vtslab account have all authorization' | " 125 "sudo tee -a /etc/sudoers") 126 sudo("echo 'vtslab ALL=(ALL:ALL) ALL' | sudo tee -a /etc/sudoers") 127 128 129def SetupUSBPermission(): 130 """Sets up the USB permission for adb and fastboot. 131 132 usage: $ fab SetupUSBPermission 133 """ 134 sudo("curl --create-dirs -L -o /etc/udev/rules.d/51-android.rules -O -L " 135 "https://raw.githubusercontent.com/snowdream/51-android/master/" 136 "51-android.rules") 137 sudo("chmod a+r /etc/udev/rules.d/51-android.rules") 138 sudo("service udev restart") 139 140 141def SetupADBVendorKeysEnvVar(): 142 """Appends scripts for ADB_VENDOR_KEYS path setup. 143 144 In setup step, this function looks into .bashrc file for this script, and 145 if there is not then appends the below scripts to .bashrc. 146 Later when shell env created (through ssh or screen instance creation time), 147 .bashrc file will look for _VTSLAB_PACKAGE_PATH_FILENAME and use the 148 contents of the file to set ADB_VENDOR_KEYS. 149 150 usage: $ fab SetupADBVendorKeysEnvVar 151 """ 152 if not contains("~/.bashrc", _VTSLAB_PACKAGE_PATH_FILENAME): 153 run("echo '' >> ~/.bashrc", ) 154 run("echo '# Set $ADB_VENDOR_KEYS as paths to adb private key files " 155 "within the vtslab-package' >> ~/.bashrc") 156 run("echo 'if [ -f ~/%s ]; then' >> ~/.bashrc" % 157 _VTSLAB_PACKAGE_PATH_FILENAME) 158 run("echo ' export ADB_VENDOR_KEYS=$(find $(cat ~/%s)/android-vtslab/" 159 "testcases/DATA/ak -name \".*.ak\" | tr \"\\n\" \":\")' " 160 ">> ~/.bashrc" % _VTSLAB_PACKAGE_PATH_FILENAME) 161 run("echo 'fi' >> ~/.bashrc") 162 163 164def _CheckADBVendorKeysEnvVar(vtslab_package_file_name=""): 165 """Checks if there is a change in ADB_VENDOR_KEYS env variable. 166 167 if there is, then the adbd needs to be restarted in the screen context 168 before running the HC. 169 170 Args: 171 vtslab_package_file_name: string, the HC package file name that is about 172 to be deployed. 173 174 Returns: 175 True if the list of the adb vendor key files have changed, 176 False otherwise. 177 """ 178 former_key_set = set() 179 current_key_set = set() 180 set_keyfile_set = lambda set, path_list: map(set.add, map(os.path.basename, 181 path_list)) 182 vtslab_package_path_filepath = "~/%s" % _VTSLAB_PACKAGE_PATH_FILENAME 183 184 if exists(vtslab_package_path_filepath): 185 former_HC_package_path = run("cat %s" % vtslab_package_path_filepath) 186 former_HC_package_adbkey_path = os.path.join( 187 former_HC_package_path, "android-vtslab/testcases/DATA/ak") 188 if exists(former_HC_package_adbkey_path): 189 adb_vendor_keys_list = run("find %s -name \".*.ak\"" % 190 former_HC_package_adbkey_path).split() 191 set_keyfile_set(former_key_set, adb_vendor_keys_list) 192 193 if exists("~/run/%s.dir/android-vtslab/testcases/DATA/ak" % 194 vtslab_package_file_name): 195 adb_vendor_keys_list = run( 196 "find ~/run/%s.dir/android-vtslab/testcases/DATA/ak -name \".*.ak\"" 197 % vtslab_package_file_name).split() 198 set_keyfile_set(current_key_set, adb_vendor_keys_list) 199 200 return former_key_set != current_key_set 201 202 203def SetupPackages(ip_address_file_path=None): 204 """Sets up the execution environment for vts `run` command. 205 206 Need to temporarily open the ports for apt-get and pip commands. 207 208 usage: $ fab SetupPackages 209 210 Args: 211 ip_address_file_path: string, path to a python file passed from command 212 file input. Will be passed to SetupIptables(). 213 """ 214 sudo("iptables -P INPUT ACCEPT") 215 216 # todo : replace "kr.ubuntu." to "ubuntu" in /etc/apt/sources.list 217 sudo("apt-get upgrade -y") 218 sudo("apt-get update -y") 219 sudo("apt-get install -y git-core gnupg flex bison gperf build-essential " 220 "zip curl zlib1g-dev gcc-multilib g++-multilib x11proto-core-dev " 221 "libx11-dev lib32z-dev ccache libgl1-mesa-dev libxml2-utils xsltproc " 222 "unzip liblz4-tool udev screen") 223 224 sudo("apt-get install -y android-tools-adb") 225 sudo("usermod -aG plugdev $LOGNAME") 226 227 SetupUSBPermission() 228 229 sudo("apt-get update") 230 sudo("apt-get install -y python2.7") 231 sudo("apt-get install -y python-pip") 232 run("pip install --upgrade pip") 233 sudo("apt-get install -y python-virtualenv") 234 235 sudo("apt-get install -y python-dev python-protobuf protobuf-compiler " 236 "python-setuptools") 237 238 for req_path in _PIP_REQUIREMENTS_PATHS: 239 full_path = os.path.join(os.environ["ANDROID_BUILD_TOP"], req_path) 240 pip_requirement_list = [] 241 try: 242 requirements_fd = open(full_path, "r") 243 lines = requirements_fd.readlines() 244 for line in lines: 245 req = line.rstrip() 246 if req != "" and not req.startswith("#"): 247 pip_requirement_list.append(req) 248 except IOError as e: 249 print("%s: %s" % (e.strerror, full_path)) 250 return 251 sudo("pip install %s" % " ".join(pip_requirement_list)) 252 253 sudo("pip install --upgrade protobuf") 254 255 lsb_result = run("lsb_release -c -s") 256 sudo("echo \"deb http://packages.cloud.google.com/apt cloud-sdk-%s " 257 "main\" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list" % 258 lsb_result) 259 sudo("curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | " 260 "sudo apt-key add -") 261 sudo("apt-get update && sudo apt-get install -y google-cloud-sdk") 262 sudo("apt-get install -y google-cloud-sdk-app-engine-java " 263 "google-cloud-sdk-app-engine-python kubectl") 264 265 sudo("apt-get install -y m4 bison") 266 267 if ip_address_file_path is not None: 268 SetupIptables(ip_address_file_path) 269 270 SetupADBVendorKeysEnvVar() 271 272 273def DeployVtslab(vtslab_package_gcs_url=None): 274 """Deploys vtslab package. 275 276 Fetches and deploy vtslab by going through the processes described below 277 1. Send the "exit --wait_for_jobs=True" command to all detached screen. 278 And let the screen to terminate itself. 279 2. Create a new screen instance that downloads and runs the new HC, 280 give password and device command to the HC without actually attaching it 281 282 usage: $ fab DeployVtslab -p <password> -H hosts.py -f <gs://vtslab-release/...> 283 284 Args: 285 vtslab_package_gcs_url: string, URL to a certain vtslab package file. 286 """ 287 if not vtslab_package_gcs_url: 288 print("Please specify vtslab package file URL using -f option.") 289 return 290 elif not vtslab_package_gcs_url.startswith("gs://vtslab-release/"): 291 print("Please spcify a valid URL for the vtslab package.") 292 return 293 else: 294 vti = "vtslab-schedule-" + vtslab_package_gcs_url[len( 295 "gs://vtslab-release/"):].split("/")[0] + ".appspot.com" 296 with settings(warn_only=True): 297 screen_list_result = run("screen -list") 298 lines = screen_list_result.split("\n") 299 for line in lines: 300 if "(Detached)" in line: 301 screen_name = line.split("\t")[1] 302 print(screen_name) 303 with settings(warn_only=True): 304 run("screen -S %s -X stuff \"exit --wait_for_jobs=True\"" % 305 screen_name) 306 run("screen -S %s -X stuff \"^M\"" % screen_name) 307 run("screen -S %s -X stuff \"exit\"" % screen_name) 308 run("screen -S %s -X stuff \"^M\"" % screen_name) 309 310 vtslab_package_file_name = os.path.basename(vtslab_package_gcs_url) 311 run("mkdir -p ~/run/%s.dir/" % vtslab_package_file_name) 312 with cd("~/run/%s.dir" % vtslab_package_file_name): 313 run("gsutil cp %s ./" % vtslab_package_gcs_url) 314 run("unzip -o %s" % vtslab_package_file_name) 315 adb_vendor_keys_changed = _CheckADBVendorKeysEnvVar( 316 vtslab_package_file_name) 317 run("pwd > ~/%s" % _VTSLAB_PACKAGE_PATH_FILENAME) 318 319 with cd("~/run/%s.dir/android-vtslab/tools" % vtslab_package_file_name): 320 new_screen_name = run("cat ../testcases/version.txt") 321 322 with cd("~/run/%s.dir/android-vtslab/tools" % vtslab_package_file_name): 323 run("./make_screen %s ; sleep 1" % new_screen_name) 324 325 if adb_vendor_keys_changed: 326 reset_adbd = "" 327 while reset_adbd.lower() not in ["y", "n"]: 328 if reset_adbd: 329 print("Please type 'y' or 'n'") 330 reset_adbd = raw_input( 331 "Reset adb server daemon on host %s (y/n)? " % env.host) 332 if reset_adbd.lower() == "y": 333 run("screen -S %s -X stuff \"adb kill-server^M\"" % 334 new_screen_name) 335 run("screen -S %s -X stuff \"adb start-server^M\"" % 336 new_screen_name) 337 run("screen -S %s -X stuff \"./run --vti=%s\"" % (new_screen_name, vti)) 338 run("screen -S %s -X stuff \"^M\"" % new_screen_name) 339 time.sleep(5) 340 run("screen -S %s -X stuff \"password\"" % new_screen_name) 341 run("screen -S %s -X stuff \"^M\"" % new_screen_name) 342 run("screen -S %s -X stuff \"%s\"" % (new_screen_name, env.password)) 343 run("screen -S %s -X stuff \"^M\"" % new_screen_name) 344 run("screen -S %s -X stuff \"device --lease=True\"" % new_screen_name) 345 run("screen -S %s -X stuff \"^M\"" % new_screen_name) 346 347 with cd("~/run/%s.dir" % vtslab_package_file_name): 348 run("rm %s" % vtslab_package_file_name) 349 350 351def DeployGCE(vtslab_package_gcs_url=None): 352 """Deploys a vtslab package to GCE nodes. 353 354 Fetches and deploy vtslab on monitor-hc by doing; 355 1. Download android-vtslab-<>.zip from GCS using the given URL and upzip it. 356 2. Send the Ctrl-c key input to all detached screen, then cursor-up 357 key input and enter key input, making the screen to execute 358 the last run command. 359 360 usage: $ fab DeployVtslab -p <password> -H <Google Cloud Platform project name> -f <gs://vtslab-release/...> 361 362 Args: 363 vtslab_package_gcs_url: string, URL to a certain vtslab package file. 364 """ 365 if not vtslab_package_gcs_url: 366 print("Please specify vtslab package file URL using -f option.") 367 return 368 elif not vtslab_package_gcs_url.startswith("gs://"): 369 print("Please spcify a valid URL for the vtslab package.") 370 return 371 372 vtslab_package_file_name = os.path.basename(vtslab_package_gcs_url) 373 with cd("~/run"): 374 run("gsutil cp %s ./" % vtslab_package_gcs_url) 375 run("unzip -o %s" % vtslab_package_file_name) 376 run("rm %s" % vtslab_package_file_name) 377 378 with settings(warn_only=True): 379 screen_list_result = run("screen -list") 380 lines = screen_list_result.split("\n") 381 for line in lines: 382 if "(Detached)" in line: 383 screen_name = line.split("\t")[1] 384 run("screen -S %s -X stuff \"^C\"" % screen_name) 385 run("screen -S %s -X stuff \"\033[A\"" % screen_name) 386 run("screen -S %s -X stuff \"^M\"" % screen_name) 387