1*800a58d9SAndroid Build Coastguard Worker#!/usr/bin/env python 2*800a58d9SAndroid Build Coastguard Worker# 3*800a58d9SAndroid Build Coastguard Worker# Copyright 2016 - The Android Open Source Project 4*800a58d9SAndroid Build Coastguard Worker# 5*800a58d9SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*800a58d9SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*800a58d9SAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*800a58d9SAndroid Build Coastguard Worker# 9*800a58d9SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*800a58d9SAndroid Build Coastguard Worker# 11*800a58d9SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*800a58d9SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*800a58d9SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*800a58d9SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*800a58d9SAndroid Build Coastguard Worker# limitations under the License. 16*800a58d9SAndroid Build Coastguard Worker 17*800a58d9SAndroid Build Coastguard Worker"""Public Device Driver APIs. 18*800a58d9SAndroid Build Coastguard Worker 19*800a58d9SAndroid Build Coastguard WorkerThis module provides public device driver APIs that can be called 20*800a58d9SAndroid Build Coastguard Workeras a Python library. 21*800a58d9SAndroid Build Coastguard Worker 22*800a58d9SAndroid Build Coastguard WorkerTODO: The following APIs have not been implemented 23*800a58d9SAndroid Build Coastguard Worker - RebootAVD(ip): 24*800a58d9SAndroid Build Coastguard Worker - RegisterSshPubKey(username, key): 25*800a58d9SAndroid Build Coastguard Worker - UnregisterSshPubKey(username, key): 26*800a58d9SAndroid Build Coastguard Worker - CleanupStaleImages(): 27*800a58d9SAndroid Build Coastguard Worker - CleanupStaleDevices(): 28*800a58d9SAndroid Build Coastguard Worker""" 29*800a58d9SAndroid Build Coastguard Worker 30*800a58d9SAndroid Build Coastguard Workerfrom __future__ import print_function 31*800a58d9SAndroid Build Coastguard Workerimport logging 32*800a58d9SAndroid Build Coastguard Workerimport os 33*800a58d9SAndroid Build Coastguard Worker 34*800a58d9SAndroid Build Coastguard Workerfrom acloud import errors 35*800a58d9SAndroid Build Coastguard Workerfrom acloud.public import avd 36*800a58d9SAndroid Build Coastguard Workerfrom acloud.public import report 37*800a58d9SAndroid Build Coastguard Workerfrom acloud.public.actions import common_operations 38*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal import constants 39*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import auth 40*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import android_build_client 41*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import android_compute_client 42*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import gstorage_client 43*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import utils 44*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib.adb_tools import AdbTools 45*800a58d9SAndroid Build Coastguard Worker 46*800a58d9SAndroid Build Coastguard Worker 47*800a58d9SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__) 48*800a58d9SAndroid Build Coastguard Worker 49*800a58d9SAndroid Build Coastguard WorkerMAX_BATCH_CLEANUP_COUNT = 100 50*800a58d9SAndroid Build Coastguard Worker 51*800a58d9SAndroid Build Coastguard Worker_SSH_USER = "root" 52*800a58d9SAndroid Build Coastguard Worker 53*800a58d9SAndroid Build Coastguard Worker 54*800a58d9SAndroid Build Coastguard Worker# pylint: disable=invalid-name 55*800a58d9SAndroid Build Coastguard Workerclass AndroidVirtualDevicePool(): 56*800a58d9SAndroid Build Coastguard Worker """A class that manages a pool of devices.""" 57*800a58d9SAndroid Build Coastguard Worker 58*800a58d9SAndroid Build Coastguard Worker def __init__(self, cfg, devices=None): 59*800a58d9SAndroid Build Coastguard Worker self._devices = devices or [] 60*800a58d9SAndroid Build Coastguard Worker self._cfg = cfg 61*800a58d9SAndroid Build Coastguard Worker credentials = auth.CreateCredentials(cfg) 62*800a58d9SAndroid Build Coastguard Worker self._build_client = android_build_client.AndroidBuildClient( 63*800a58d9SAndroid Build Coastguard Worker credentials) 64*800a58d9SAndroid Build Coastguard Worker self._storage_client = gstorage_client.StorageClient(credentials) 65*800a58d9SAndroid Build Coastguard Worker self._compute_client = android_compute_client.AndroidComputeClient( 66*800a58d9SAndroid Build Coastguard Worker cfg, credentials) 67*800a58d9SAndroid Build Coastguard Worker 68*800a58d9SAndroid Build Coastguard Worker @utils.TimeExecute("Creating GCE image") 69*800a58d9SAndroid Build Coastguard Worker def _CreateGceImageWithBuildInfo(self, build_target, build_id): 70*800a58d9SAndroid Build Coastguard Worker """Creates a Gce image using build from Launch Control. 71*800a58d9SAndroid Build Coastguard Worker 72*800a58d9SAndroid Build Coastguard Worker Clone avd-system.tar.gz of a build to a cache storage bucket 73*800a58d9SAndroid Build Coastguard Worker using launch control api. And then create a Gce image. 74*800a58d9SAndroid Build Coastguard Worker 75*800a58d9SAndroid Build Coastguard Worker Args: 76*800a58d9SAndroid Build Coastguard Worker build_target: Target name, e.g. "aosp_cf_x86_64_phone-userdebug" 77*800a58d9SAndroid Build Coastguard Worker build_id: Build id, a string, e.g. "2263051", "P2804227" 78*800a58d9SAndroid Build Coastguard Worker 79*800a58d9SAndroid Build Coastguard Worker Returns: 80*800a58d9SAndroid Build Coastguard Worker String, name of the Gce image that has been created. 81*800a58d9SAndroid Build Coastguard Worker """ 82*800a58d9SAndroid Build Coastguard Worker logger.info("Creating a new gce image using build: build_id %s, " 83*800a58d9SAndroid Build Coastguard Worker "build_target %s", build_id, build_target) 84*800a58d9SAndroid Build Coastguard Worker disk_image_id = utils.GenerateUniqueName( 85*800a58d9SAndroid Build Coastguard Worker suffix=self._cfg.disk_image_name) 86*800a58d9SAndroid Build Coastguard Worker self._build_client.CopyTo( 87*800a58d9SAndroid Build Coastguard Worker build_target, 88*800a58d9SAndroid Build Coastguard Worker build_id, 89*800a58d9SAndroid Build Coastguard Worker artifact_name=self._cfg.disk_image_name, 90*800a58d9SAndroid Build Coastguard Worker destination_bucket=self._cfg.storage_bucket_name, 91*800a58d9SAndroid Build Coastguard Worker destination_path=disk_image_id) 92*800a58d9SAndroid Build Coastguard Worker disk_image_url = self._storage_client.GetUrl( 93*800a58d9SAndroid Build Coastguard Worker self._cfg.storage_bucket_name, disk_image_id) 94*800a58d9SAndroid Build Coastguard Worker try: 95*800a58d9SAndroid Build Coastguard Worker image_name = self._compute_client.GenerateImageName(build_target, 96*800a58d9SAndroid Build Coastguard Worker build_id) 97*800a58d9SAndroid Build Coastguard Worker self._compute_client.CreateImage(image_name=image_name, 98*800a58d9SAndroid Build Coastguard Worker source_uri=disk_image_url) 99*800a58d9SAndroid Build Coastguard Worker finally: 100*800a58d9SAndroid Build Coastguard Worker self._storage_client.Delete(self._cfg.storage_bucket_name, 101*800a58d9SAndroid Build Coastguard Worker disk_image_id) 102*800a58d9SAndroid Build Coastguard Worker return image_name 103*800a58d9SAndroid Build Coastguard Worker 104*800a58d9SAndroid Build Coastguard Worker @utils.TimeExecute("Creating GCE image") 105*800a58d9SAndroid Build Coastguard Worker def _CreateGceImageWithLocalFile(self, local_disk_image): 106*800a58d9SAndroid Build Coastguard Worker """Create a Gce image with a local image file. 107*800a58d9SAndroid Build Coastguard Worker 108*800a58d9SAndroid Build Coastguard Worker The local disk image can be either a tar.gz file or a 109*800a58d9SAndroid Build Coastguard Worker raw vmlinux image. 110*800a58d9SAndroid Build Coastguard Worker e.g. /tmp/avd-system.tar.gz or /tmp/android_system_disk_syslinux.img 111*800a58d9SAndroid Build Coastguard Worker If a raw vmlinux image is provided, it will be archived into a tar.gz file. 112*800a58d9SAndroid Build Coastguard Worker 113*800a58d9SAndroid Build Coastguard Worker The final tar.gz file will be uploaded to a cache bucket in storage. 114*800a58d9SAndroid Build Coastguard Worker 115*800a58d9SAndroid Build Coastguard Worker Args: 116*800a58d9SAndroid Build Coastguard Worker local_disk_image: string, path to a local disk image, 117*800a58d9SAndroid Build Coastguard Worker 118*800a58d9SAndroid Build Coastguard Worker Returns: 119*800a58d9SAndroid Build Coastguard Worker String, name of the Gce image that has been created. 120*800a58d9SAndroid Build Coastguard Worker 121*800a58d9SAndroid Build Coastguard Worker Raises: 122*800a58d9SAndroid Build Coastguard Worker DriverError: if a file with an unexpected extension is given. 123*800a58d9SAndroid Build Coastguard Worker """ 124*800a58d9SAndroid Build Coastguard Worker logger.info("Creating a new gce image from a local file %s", 125*800a58d9SAndroid Build Coastguard Worker local_disk_image) 126*800a58d9SAndroid Build Coastguard Worker with utils.TempDir() as tempdir: 127*800a58d9SAndroid Build Coastguard Worker if local_disk_image.endswith(self._cfg.disk_raw_image_extension): 128*800a58d9SAndroid Build Coastguard Worker dest_tar_file = os.path.join(tempdir, 129*800a58d9SAndroid Build Coastguard Worker self._cfg.disk_image_name) 130*800a58d9SAndroid Build Coastguard Worker utils.MakeTarFile( 131*800a58d9SAndroid Build Coastguard Worker src_dict={local_disk_image: self._cfg.disk_raw_image_name}, 132*800a58d9SAndroid Build Coastguard Worker dest=dest_tar_file) 133*800a58d9SAndroid Build Coastguard Worker local_disk_image = dest_tar_file 134*800a58d9SAndroid Build Coastguard Worker elif not local_disk_image.endswith(self._cfg.disk_image_extension): 135*800a58d9SAndroid Build Coastguard Worker raise errors.DriverError( 136*800a58d9SAndroid Build Coastguard Worker "Wrong local_disk_image type, must be a *%s file or *%s file" 137*800a58d9SAndroid Build Coastguard Worker % (self._cfg.disk_raw_image_extension, 138*800a58d9SAndroid Build Coastguard Worker self._cfg.disk_image_extension)) 139*800a58d9SAndroid Build Coastguard Worker 140*800a58d9SAndroid Build Coastguard Worker disk_image_id = utils.GenerateUniqueName( 141*800a58d9SAndroid Build Coastguard Worker suffix=self._cfg.disk_image_name) 142*800a58d9SAndroid Build Coastguard Worker self._storage_client.Upload( 143*800a58d9SAndroid Build Coastguard Worker local_src=local_disk_image, 144*800a58d9SAndroid Build Coastguard Worker bucket_name=self._cfg.storage_bucket_name, 145*800a58d9SAndroid Build Coastguard Worker object_name=disk_image_id, 146*800a58d9SAndroid Build Coastguard Worker mime_type=self._cfg.disk_image_mime_type) 147*800a58d9SAndroid Build Coastguard Worker disk_image_url = self._storage_client.GetUrl( 148*800a58d9SAndroid Build Coastguard Worker self._cfg.storage_bucket_name, disk_image_id) 149*800a58d9SAndroid Build Coastguard Worker try: 150*800a58d9SAndroid Build Coastguard Worker image_name = self._compute_client.GenerateImageName() 151*800a58d9SAndroid Build Coastguard Worker self._compute_client.CreateImage(image_name=image_name, 152*800a58d9SAndroid Build Coastguard Worker source_uri=disk_image_url) 153*800a58d9SAndroid Build Coastguard Worker finally: 154*800a58d9SAndroid Build Coastguard Worker self._storage_client.Delete(self._cfg.storage_bucket_name, 155*800a58d9SAndroid Build Coastguard Worker disk_image_id) 156*800a58d9SAndroid Build Coastguard Worker return image_name 157*800a58d9SAndroid Build Coastguard Worker 158*800a58d9SAndroid Build Coastguard Worker # pylint: disable=too-many-locals 159*800a58d9SAndroid Build Coastguard Worker def CreateDevices(self, 160*800a58d9SAndroid Build Coastguard Worker num, 161*800a58d9SAndroid Build Coastguard Worker build_target=None, 162*800a58d9SAndroid Build Coastguard Worker build_id=None, 163*800a58d9SAndroid Build Coastguard Worker gce_image=None, 164*800a58d9SAndroid Build Coastguard Worker local_disk_image=None, 165*800a58d9SAndroid Build Coastguard Worker cleanup=True, 166*800a58d9SAndroid Build Coastguard Worker extra_data_disk_size_gb=None, 167*800a58d9SAndroid Build Coastguard Worker precreated_data_image=None, 168*800a58d9SAndroid Build Coastguard Worker avd_spec=None, 169*800a58d9SAndroid Build Coastguard Worker extra_scopes=None): 170*800a58d9SAndroid Build Coastguard Worker """Creates |num| devices for given build_target and build_id. 171*800a58d9SAndroid Build Coastguard Worker 172*800a58d9SAndroid Build Coastguard Worker - If gce_image is provided, will use it to create an instance. 173*800a58d9SAndroid Build Coastguard Worker - If local_disk_image is provided, will upload it to a temporary 174*800a58d9SAndroid Build Coastguard Worker caching storage bucket which is defined by user as |storage_bucket_name| 175*800a58d9SAndroid Build Coastguard Worker And then create an gce image with it; and then create an instance. 176*800a58d9SAndroid Build Coastguard Worker - If build_target and build_id are provided, will clone the disk image 177*800a58d9SAndroid Build Coastguard Worker via launch control to the temporary caching storage bucket. 178*800a58d9SAndroid Build Coastguard Worker And then create an gce image with it; and then create an instance. 179*800a58d9SAndroid Build Coastguard Worker 180*800a58d9SAndroid Build Coastguard Worker Args: 181*800a58d9SAndroid Build Coastguard Worker num: Number of devices to create. 182*800a58d9SAndroid Build Coastguard Worker build_target: Target name, e.g. "aosp_cf_x86_64_phone-userdebug" 183*800a58d9SAndroid Build Coastguard Worker build_id: Build id, a string, e.g. "2263051", "P2804227" 184*800a58d9SAndroid Build Coastguard Worker gce_image: string, if given, will use this image 185*800a58d9SAndroid Build Coastguard Worker instead of creating a new one. 186*800a58d9SAndroid Build Coastguard Worker implies cleanup=False. 187*800a58d9SAndroid Build Coastguard Worker local_disk_image: string, path to a local disk image, e.g. 188*800a58d9SAndroid Build Coastguard Worker /tmp/avd-system.tar.gz 189*800a58d9SAndroid Build Coastguard Worker cleanup: boolean, if True clean up compute engine image after creating 190*800a58d9SAndroid Build Coastguard Worker the instance. 191*800a58d9SAndroid Build Coastguard Worker extra_data_disk_size_gb: Integer, size of extra disk, or None. 192*800a58d9SAndroid Build Coastguard Worker precreated_data_image: A string, the image to use for the extra disk. 193*800a58d9SAndroid Build Coastguard Worker avd_spec: AVDSpec object for pass hw_property. 194*800a58d9SAndroid Build Coastguard Worker extra_scopes: A list of extra scopes given to the new instance. 195*800a58d9SAndroid Build Coastguard Worker 196*800a58d9SAndroid Build Coastguard Worker Raises: 197*800a58d9SAndroid Build Coastguard Worker errors.DriverError: If no source is specified for image creation. 198*800a58d9SAndroid Build Coastguard Worker """ 199*800a58d9SAndroid Build Coastguard Worker if gce_image: 200*800a58d9SAndroid Build Coastguard Worker # GCE image is provided, we can directly move to instance creation. 201*800a58d9SAndroid Build Coastguard Worker logger.info("Using existing gce image %s", gce_image) 202*800a58d9SAndroid Build Coastguard Worker image_name = gce_image 203*800a58d9SAndroid Build Coastguard Worker cleanup = False 204*800a58d9SAndroid Build Coastguard Worker elif local_disk_image: 205*800a58d9SAndroid Build Coastguard Worker image_name = self._CreateGceImageWithLocalFile(local_disk_image) 206*800a58d9SAndroid Build Coastguard Worker elif build_target and build_id: 207*800a58d9SAndroid Build Coastguard Worker image_name = self._CreateGceImageWithBuildInfo(build_target, 208*800a58d9SAndroid Build Coastguard Worker build_id) 209*800a58d9SAndroid Build Coastguard Worker else: 210*800a58d9SAndroid Build Coastguard Worker raise errors.DriverError( 211*800a58d9SAndroid Build Coastguard Worker "Invalid image source, must specify one of the following: gce_image, " 212*800a58d9SAndroid Build Coastguard Worker "local_disk_image, or build_target and build id.") 213*800a58d9SAndroid Build Coastguard Worker 214*800a58d9SAndroid Build Coastguard Worker # Create GCE instances. 215*800a58d9SAndroid Build Coastguard Worker try: 216*800a58d9SAndroid Build Coastguard Worker for _ in range(num): 217*800a58d9SAndroid Build Coastguard Worker instance = self._compute_client.GenerateInstanceName( 218*800a58d9SAndroid Build Coastguard Worker build_target, build_id) 219*800a58d9SAndroid Build Coastguard Worker extra_disk_name = None 220*800a58d9SAndroid Build Coastguard Worker if extra_data_disk_size_gb > 0: 221*800a58d9SAndroid Build Coastguard Worker extra_disk_name = self._compute_client.GetDataDiskName( 222*800a58d9SAndroid Build Coastguard Worker instance) 223*800a58d9SAndroid Build Coastguard Worker self._compute_client.CreateDisk(extra_disk_name, 224*800a58d9SAndroid Build Coastguard Worker precreated_data_image, 225*800a58d9SAndroid Build Coastguard Worker extra_data_disk_size_gb, 226*800a58d9SAndroid Build Coastguard Worker disk_type=avd_spec.disk_type) 227*800a58d9SAndroid Build Coastguard Worker self._compute_client.CreateInstance( 228*800a58d9SAndroid Build Coastguard Worker instance=instance, 229*800a58d9SAndroid Build Coastguard Worker image_name=image_name, 230*800a58d9SAndroid Build Coastguard Worker extra_disk_name=extra_disk_name, 231*800a58d9SAndroid Build Coastguard Worker avd_spec=avd_spec, 232*800a58d9SAndroid Build Coastguard Worker extra_scopes=extra_scopes) 233*800a58d9SAndroid Build Coastguard Worker ip = self._compute_client.GetInstanceIP(instance) 234*800a58d9SAndroid Build Coastguard Worker self.devices.append(avd.AndroidVirtualDevice( 235*800a58d9SAndroid Build Coastguard Worker ip=ip, instance_name=instance)) 236*800a58d9SAndroid Build Coastguard Worker finally: 237*800a58d9SAndroid Build Coastguard Worker if cleanup: 238*800a58d9SAndroid Build Coastguard Worker self._compute_client.DeleteImage(image_name) 239*800a58d9SAndroid Build Coastguard Worker 240*800a58d9SAndroid Build Coastguard Worker def DeleteDevices(self): 241*800a58d9SAndroid Build Coastguard Worker """Deletes devices. 242*800a58d9SAndroid Build Coastguard Worker 243*800a58d9SAndroid Build Coastguard Worker Returns: 244*800a58d9SAndroid Build Coastguard Worker A tuple, (deleted, failed, error_msgs) 245*800a58d9SAndroid Build Coastguard Worker deleted: A list of names of instances that have been deleted. 246*800a58d9SAndroid Build Coastguard Worker faild: A list of names of instances that we fail to delete. 247*800a58d9SAndroid Build Coastguard Worker error_msgs: A list of failure messages. 248*800a58d9SAndroid Build Coastguard Worker """ 249*800a58d9SAndroid Build Coastguard Worker instance_names = [device.instance_name for device in self._devices] 250*800a58d9SAndroid Build Coastguard Worker return self._compute_client.DeleteInstances(instance_names, 251*800a58d9SAndroid Build Coastguard Worker self._cfg.zone) 252*800a58d9SAndroid Build Coastguard Worker 253*800a58d9SAndroid Build Coastguard Worker @utils.TimeExecute("Waiting for AVD to boot") 254*800a58d9SAndroid Build Coastguard Worker def WaitForBoot(self): 255*800a58d9SAndroid Build Coastguard Worker """Waits for all devices to boot up. 256*800a58d9SAndroid Build Coastguard Worker 257*800a58d9SAndroid Build Coastguard Worker Returns: 258*800a58d9SAndroid Build Coastguard Worker A dictionary that contains all the failures. 259*800a58d9SAndroid Build Coastguard Worker The key is the name of the instance that fails to boot, 260*800a58d9SAndroid Build Coastguard Worker the value is an errors.DeviceBoottError object. 261*800a58d9SAndroid Build Coastguard Worker """ 262*800a58d9SAndroid Build Coastguard Worker failures = {} 263*800a58d9SAndroid Build Coastguard Worker for device in self._devices: 264*800a58d9SAndroid Build Coastguard Worker try: 265*800a58d9SAndroid Build Coastguard Worker self._compute_client.WaitForBoot(device.instance_name) 266*800a58d9SAndroid Build Coastguard Worker except errors.DeviceBootError as e: 267*800a58d9SAndroid Build Coastguard Worker failures[device.instance_name] = e 268*800a58d9SAndroid Build Coastguard Worker return failures 269*800a58d9SAndroid Build Coastguard Worker 270*800a58d9SAndroid Build Coastguard Worker @property 271*800a58d9SAndroid Build Coastguard Worker def devices(self): 272*800a58d9SAndroid Build Coastguard Worker """Returns a list of devices in the pool. 273*800a58d9SAndroid Build Coastguard Worker 274*800a58d9SAndroid Build Coastguard Worker Returns: 275*800a58d9SAndroid Build Coastguard Worker A list of devices in the pool. 276*800a58d9SAndroid Build Coastguard Worker """ 277*800a58d9SAndroid Build Coastguard Worker return self._devices 278*800a58d9SAndroid Build Coastguard Worker 279*800a58d9SAndroid Build Coastguard Worker 280*800a58d9SAndroid Build Coastguard Workerdef AddDeletionResultToReport(report_obj, deleted, failed, error_msgs, 281*800a58d9SAndroid Build Coastguard Worker resource_name): 282*800a58d9SAndroid Build Coastguard Worker """Adds deletion result to a Report object. 283*800a58d9SAndroid Build Coastguard Worker 284*800a58d9SAndroid Build Coastguard Worker This function will add the following to report.data. 285*800a58d9SAndroid Build Coastguard Worker "deleted": [ 286*800a58d9SAndroid Build Coastguard Worker {"name": "resource_name", "type": "resource_name"}, 287*800a58d9SAndroid Build Coastguard Worker ], 288*800a58d9SAndroid Build Coastguard Worker "failed": [ 289*800a58d9SAndroid Build Coastguard Worker {"name": "resource_name", "type": "resource_name"}, 290*800a58d9SAndroid Build Coastguard Worker ], 291*800a58d9SAndroid Build Coastguard Worker This function will append error_msgs to report.errors. 292*800a58d9SAndroid Build Coastguard Worker 293*800a58d9SAndroid Build Coastguard Worker Args: 294*800a58d9SAndroid Build Coastguard Worker report_obj: A Report object. 295*800a58d9SAndroid Build Coastguard Worker deleted: A list of names of the resources that have been deleted. 296*800a58d9SAndroid Build Coastguard Worker failed: A list of names of the resources that we fail to delete. 297*800a58d9SAndroid Build Coastguard Worker error_msgs: A list of error message strings to be added to the report. 298*800a58d9SAndroid Build Coastguard Worker resource_name: A string, representing the name of the resource. 299*800a58d9SAndroid Build Coastguard Worker """ 300*800a58d9SAndroid Build Coastguard Worker for name in deleted: 301*800a58d9SAndroid Build Coastguard Worker report_obj.AddData(key="deleted", 302*800a58d9SAndroid Build Coastguard Worker value={"name": name, 303*800a58d9SAndroid Build Coastguard Worker "type": resource_name}) 304*800a58d9SAndroid Build Coastguard Worker for name in failed: 305*800a58d9SAndroid Build Coastguard Worker report_obj.AddData(key="failed", 306*800a58d9SAndroid Build Coastguard Worker value={"name": name, 307*800a58d9SAndroid Build Coastguard Worker "type": resource_name}) 308*800a58d9SAndroid Build Coastguard Worker report_obj.AddErrors(error_msgs) 309*800a58d9SAndroid Build Coastguard Worker if failed or error_msgs: 310*800a58d9SAndroid Build Coastguard Worker report_obj.SetStatus(report.Status.FAIL) 311*800a58d9SAndroid Build Coastguard Worker 312*800a58d9SAndroid Build Coastguard Worker 313*800a58d9SAndroid Build Coastguard Workerdef _FetchSerialLogsFromDevices(compute_client, instance_names, output_file, 314*800a58d9SAndroid Build Coastguard Worker port): 315*800a58d9SAndroid Build Coastguard Worker """Fetch serial logs from a port for a list of devices to a local file. 316*800a58d9SAndroid Build Coastguard Worker 317*800a58d9SAndroid Build Coastguard Worker Args: 318*800a58d9SAndroid Build Coastguard Worker compute_client: An object of android_compute_client.AndroidComputeClient 319*800a58d9SAndroid Build Coastguard Worker instance_names: A list of instance names. 320*800a58d9SAndroid Build Coastguard Worker output_file: A path to a file ending with "tar.gz" 321*800a58d9SAndroid Build Coastguard Worker port: The number of serial port to read from, 0 for serial output, 1 for 322*800a58d9SAndroid Build Coastguard Worker logcat. 323*800a58d9SAndroid Build Coastguard Worker """ 324*800a58d9SAndroid Build Coastguard Worker with utils.TempDir() as tempdir: 325*800a58d9SAndroid Build Coastguard Worker src_dict = {} 326*800a58d9SAndroid Build Coastguard Worker for instance_name in instance_names: 327*800a58d9SAndroid Build Coastguard Worker serial_log = compute_client.GetSerialPortOutput( 328*800a58d9SAndroid Build Coastguard Worker instance=instance_name, port=port) 329*800a58d9SAndroid Build Coastguard Worker file_name = "%s.log" % instance_name 330*800a58d9SAndroid Build Coastguard Worker file_path = os.path.join(tempdir, file_name) 331*800a58d9SAndroid Build Coastguard Worker src_dict[file_path] = file_name 332*800a58d9SAndroid Build Coastguard Worker with open(file_path, "w") as f: 333*800a58d9SAndroid Build Coastguard Worker f.write(serial_log.encode("utf-8")) 334*800a58d9SAndroid Build Coastguard Worker utils.MakeTarFile(src_dict, output_file) 335*800a58d9SAndroid Build Coastguard Worker 336*800a58d9SAndroid Build Coastguard Worker 337*800a58d9SAndroid Build Coastguard Worker# pylint: disable=too-many-locals 338*800a58d9SAndroid Build Coastguard Workerdef CreateGCETypeAVD(cfg, 339*800a58d9SAndroid Build Coastguard Worker build_target=None, 340*800a58d9SAndroid Build Coastguard Worker build_id=None, 341*800a58d9SAndroid Build Coastguard Worker num=1, 342*800a58d9SAndroid Build Coastguard Worker gce_image=None, 343*800a58d9SAndroid Build Coastguard Worker local_disk_image=None, 344*800a58d9SAndroid Build Coastguard Worker cleanup=True, 345*800a58d9SAndroid Build Coastguard Worker serial_log_file=None, 346*800a58d9SAndroid Build Coastguard Worker autoconnect=False, 347*800a58d9SAndroid Build Coastguard Worker report_internal_ip=False, 348*800a58d9SAndroid Build Coastguard Worker avd_spec=None): 349*800a58d9SAndroid Build Coastguard Worker """Creates one or multiple gce android devices. 350*800a58d9SAndroid Build Coastguard Worker 351*800a58d9SAndroid Build Coastguard Worker Args: 352*800a58d9SAndroid Build Coastguard Worker cfg: An AcloudConfig instance. 353*800a58d9SAndroid Build Coastguard Worker build_target: Target name, e.g. "aosp_cf_x86_64_phone-userdebug" 354*800a58d9SAndroid Build Coastguard Worker build_id: Build id, a string, e.g. "2263051", "P2804227" 355*800a58d9SAndroid Build Coastguard Worker num: Number of devices to create. 356*800a58d9SAndroid Build Coastguard Worker gce_image: string, if given, will use this gce image 357*800a58d9SAndroid Build Coastguard Worker instead of creating a new one. 358*800a58d9SAndroid Build Coastguard Worker implies cleanup=False. 359*800a58d9SAndroid Build Coastguard Worker local_disk_image: string, path to a local disk image, e.g. 360*800a58d9SAndroid Build Coastguard Worker /tmp/avd-system.tar.gz 361*800a58d9SAndroid Build Coastguard Worker cleanup: boolean, if True clean up compute engine image and 362*800a58d9SAndroid Build Coastguard Worker disk image in storage after creating the instance. 363*800a58d9SAndroid Build Coastguard Worker serial_log_file: A path to a file where serial output should 364*800a58d9SAndroid Build Coastguard Worker be saved to. 365*800a58d9SAndroid Build Coastguard Worker autoconnect: Create ssh tunnel(s) and adb connect after device creation. 366*800a58d9SAndroid Build Coastguard Worker report_internal_ip: Boolean to report the internal ip instead of 367*800a58d9SAndroid Build Coastguard Worker external ip. 368*800a58d9SAndroid Build Coastguard Worker avd_spec: AVDSpec object for pass hw_property. 369*800a58d9SAndroid Build Coastguard Worker 370*800a58d9SAndroid Build Coastguard Worker Returns: 371*800a58d9SAndroid Build Coastguard Worker A Report instance. 372*800a58d9SAndroid Build Coastguard Worker """ 373*800a58d9SAndroid Build Coastguard Worker r = report.Report(command="create") 374*800a58d9SAndroid Build Coastguard Worker credentials = auth.CreateCredentials(cfg) 375*800a58d9SAndroid Build Coastguard Worker compute_client = android_compute_client.AndroidComputeClient(cfg, 376*800a58d9SAndroid Build Coastguard Worker credentials) 377*800a58d9SAndroid Build Coastguard Worker try: 378*800a58d9SAndroid Build Coastguard Worker common_operations.CreateSshKeyPairIfNecessary(cfg) 379*800a58d9SAndroid Build Coastguard Worker device_pool = AndroidVirtualDevicePool(cfg) 380*800a58d9SAndroid Build Coastguard Worker device_pool.CreateDevices( 381*800a58d9SAndroid Build Coastguard Worker num, 382*800a58d9SAndroid Build Coastguard Worker build_target, 383*800a58d9SAndroid Build Coastguard Worker build_id, 384*800a58d9SAndroid Build Coastguard Worker gce_image, 385*800a58d9SAndroid Build Coastguard Worker local_disk_image, 386*800a58d9SAndroid Build Coastguard Worker cleanup, 387*800a58d9SAndroid Build Coastguard Worker extra_data_disk_size_gb=cfg.extra_data_disk_size_gb, 388*800a58d9SAndroid Build Coastguard Worker precreated_data_image=cfg.precreated_data_image_map.get( 389*800a58d9SAndroid Build Coastguard Worker cfg.extra_data_disk_size_gb), 390*800a58d9SAndroid Build Coastguard Worker avd_spec=avd_spec, 391*800a58d9SAndroid Build Coastguard Worker extra_scopes=cfg.extra_scopes) 392*800a58d9SAndroid Build Coastguard Worker failures = device_pool.WaitForBoot() 393*800a58d9SAndroid Build Coastguard Worker # Write result to report. 394*800a58d9SAndroid Build Coastguard Worker for device in device_pool.devices: 395*800a58d9SAndroid Build Coastguard Worker ip = (device.ip.internal if report_internal_ip 396*800a58d9SAndroid Build Coastguard Worker else device.ip.external) 397*800a58d9SAndroid Build Coastguard Worker device_dict = { 398*800a58d9SAndroid Build Coastguard Worker "ip": ip, 399*800a58d9SAndroid Build Coastguard Worker "instance_name": device.instance_name 400*800a58d9SAndroid Build Coastguard Worker } 401*800a58d9SAndroid Build Coastguard Worker if autoconnect: 402*800a58d9SAndroid Build Coastguard Worker forwarded_ports = utils.AutoConnect( 403*800a58d9SAndroid Build Coastguard Worker ip_addr=ip, 404*800a58d9SAndroid Build Coastguard Worker rsa_key_file=cfg.ssh_private_key_path, 405*800a58d9SAndroid Build Coastguard Worker target_vnc_port=constants.GCE_VNC_PORT, 406*800a58d9SAndroid Build Coastguard Worker target_adb_port=constants.GCE_ADB_PORT, 407*800a58d9SAndroid Build Coastguard Worker ssh_user=_SSH_USER, 408*800a58d9SAndroid Build Coastguard Worker client_adb_port=avd_spec.client_adb_port, 409*800a58d9SAndroid Build Coastguard Worker extra_args_ssh_tunnel=cfg.extra_args_ssh_tunnel) 410*800a58d9SAndroid Build Coastguard Worker device_dict[constants.VNC_PORT] = forwarded_ports.vnc_port 411*800a58d9SAndroid Build Coastguard Worker device_dict[constants.ADB_PORT] = forwarded_ports.adb_port 412*800a58d9SAndroid Build Coastguard Worker if avd_spec.unlock_screen: 413*800a58d9SAndroid Build Coastguard Worker AdbTools(forwarded_ports.adb_port).AutoUnlockScreen() 414*800a58d9SAndroid Build Coastguard Worker if device.instance_name in failures: 415*800a58d9SAndroid Build Coastguard Worker r.AddData(key="devices_failing_boot", value=device_dict) 416*800a58d9SAndroid Build Coastguard Worker r.AddError(str(failures[device.instance_name])) 417*800a58d9SAndroid Build Coastguard Worker else: 418*800a58d9SAndroid Build Coastguard Worker r.AddData(key="devices", value=device_dict) 419*800a58d9SAndroid Build Coastguard Worker if failures: 420*800a58d9SAndroid Build Coastguard Worker r.SetStatus(report.Status.BOOT_FAIL) 421*800a58d9SAndroid Build Coastguard Worker else: 422*800a58d9SAndroid Build Coastguard Worker r.SetStatus(report.Status.SUCCESS) 423*800a58d9SAndroid Build Coastguard Worker 424*800a58d9SAndroid Build Coastguard Worker except errors.DriverError as e: 425*800a58d9SAndroid Build Coastguard Worker r.AddError(str(e)) 426*800a58d9SAndroid Build Coastguard Worker r.SetStatus(report.Status.FAIL) 427*800a58d9SAndroid Build Coastguard Worker finally: 428*800a58d9SAndroid Build Coastguard Worker # Let's do our best to obtain the serial log, even though this 429*800a58d9SAndroid Build Coastguard Worker # could fail in case of failed boots. 430*800a58d9SAndroid Build Coastguard Worker if serial_log_file: 431*800a58d9SAndroid Build Coastguard Worker instance_names=[d.instance_name for d in device_pool.devices] 432*800a58d9SAndroid Build Coastguard Worker try: 433*800a58d9SAndroid Build Coastguard Worker _FetchSerialLogsFromDevices( 434*800a58d9SAndroid Build Coastguard Worker compute_client, 435*800a58d9SAndroid Build Coastguard Worker instance_names=instance_names, 436*800a58d9SAndroid Build Coastguard Worker port=constants.DEFAULT_SERIAL_PORT, 437*800a58d9SAndroid Build Coastguard Worker output_file=serial_log_file) 438*800a58d9SAndroid Build Coastguard Worker except Exception as log_err: 439*800a58d9SAndroid Build Coastguard Worker logging.warning("Failed to obtain serial logs from %s", ", ".join(instance_names)) 440*800a58d9SAndroid Build Coastguard Worker return r 441*800a58d9SAndroid Build Coastguard Worker 442*800a58d9SAndroid Build Coastguard Worker 443*800a58d9SAndroid Build Coastguard Workerdef DeleteAndroidVirtualDevices(cfg, instance_names, default_report=None): 444*800a58d9SAndroid Build Coastguard Worker """Deletes android devices. 445*800a58d9SAndroid Build Coastguard Worker 446*800a58d9SAndroid Build Coastguard Worker Args: 447*800a58d9SAndroid Build Coastguard Worker cfg: An AcloudConfig instance. 448*800a58d9SAndroid Build Coastguard Worker instance_names: A list of names of the instances to delete. 449*800a58d9SAndroid Build Coastguard Worker default_report: A initialized Report instance. 450*800a58d9SAndroid Build Coastguard Worker 451*800a58d9SAndroid Build Coastguard Worker Returns: 452*800a58d9SAndroid Build Coastguard Worker A Report instance. 453*800a58d9SAndroid Build Coastguard Worker """ 454*800a58d9SAndroid Build Coastguard Worker # delete, failed, error_msgs are used to record result. 455*800a58d9SAndroid Build Coastguard Worker deleted = [] 456*800a58d9SAndroid Build Coastguard Worker failed = [] 457*800a58d9SAndroid Build Coastguard Worker error_msgs = [] 458*800a58d9SAndroid Build Coastguard Worker 459*800a58d9SAndroid Build Coastguard Worker r = default_report if default_report else report.Report(command="delete") 460*800a58d9SAndroid Build Coastguard Worker credentials = auth.CreateCredentials(cfg) 461*800a58d9SAndroid Build Coastguard Worker compute_client = android_compute_client.AndroidComputeClient(cfg, 462*800a58d9SAndroid Build Coastguard Worker credentials) 463*800a58d9SAndroid Build Coastguard Worker zone_instances = compute_client.GetZonesByInstances(instance_names) 464*800a58d9SAndroid Build Coastguard Worker 465*800a58d9SAndroid Build Coastguard Worker try: 466*800a58d9SAndroid Build Coastguard Worker for zone, instances in zone_instances.items(): 467*800a58d9SAndroid Build Coastguard Worker deleted_ins, failed_ins, error_ins = compute_client.DeleteInstances( 468*800a58d9SAndroid Build Coastguard Worker instances, zone) 469*800a58d9SAndroid Build Coastguard Worker deleted.extend(deleted_ins) 470*800a58d9SAndroid Build Coastguard Worker failed.extend(failed_ins) 471*800a58d9SAndroid Build Coastguard Worker error_msgs.extend(error_ins) 472*800a58d9SAndroid Build Coastguard Worker AddDeletionResultToReport( 473*800a58d9SAndroid Build Coastguard Worker r, deleted, 474*800a58d9SAndroid Build Coastguard Worker failed, error_msgs, 475*800a58d9SAndroid Build Coastguard Worker resource_name="instance") 476*800a58d9SAndroid Build Coastguard Worker if r.status == report.Status.UNKNOWN: 477*800a58d9SAndroid Build Coastguard Worker r.SetStatus(report.Status.SUCCESS) 478*800a58d9SAndroid Build Coastguard Worker except errors.DriverError as e: 479*800a58d9SAndroid Build Coastguard Worker r.AddError(str(e)) 480*800a58d9SAndroid Build Coastguard Worker r.SetStatus(report.Status.FAIL) 481*800a58d9SAndroid Build Coastguard Worker return r 482*800a58d9SAndroid Build Coastguard Worker 483*800a58d9SAndroid Build Coastguard Worker 484*800a58d9SAndroid Build Coastguard Workerdef CheckAccess(cfg): 485*800a58d9SAndroid Build Coastguard Worker """Check if user has access. 486*800a58d9SAndroid Build Coastguard Worker 487*800a58d9SAndroid Build Coastguard Worker Args: 488*800a58d9SAndroid Build Coastguard Worker cfg: An AcloudConfig instance. 489*800a58d9SAndroid Build Coastguard Worker """ 490*800a58d9SAndroid Build Coastguard Worker credentials = auth.CreateCredentials(cfg) 491*800a58d9SAndroid Build Coastguard Worker compute_client = android_compute_client.AndroidComputeClient( 492*800a58d9SAndroid Build Coastguard Worker cfg, credentials) 493*800a58d9SAndroid Build Coastguard Worker logger.info("Checking if user has access to project %s", cfg.project) 494*800a58d9SAndroid Build Coastguard Worker if not compute_client.CheckAccess(): 495*800a58d9SAndroid Build Coastguard Worker logger.error("User does not have access to project %s", cfg.project) 496*800a58d9SAndroid Build Coastguard Worker # Print here so that command line user can see it. 497*800a58d9SAndroid Build Coastguard Worker print("Looks like you do not have access to %s. " % cfg.project) 498*800a58d9SAndroid Build Coastguard Worker if cfg.project in cfg.no_project_access_msg_map: 499*800a58d9SAndroid Build Coastguard Worker print(cfg.no_project_access_msg_map[cfg.project]) 500