1#!/usr/bin/env python 2# 3# Copyright 2018 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16"""Action to create goldfish device instances. 17 18A Goldfish device is an emulated android device based on the android 19emulator. 20""" 21import logging 22import os 23import re 24 25from acloud import errors 26from acloud.public.actions import base_device_factory 27from acloud.public.actions import common_operations 28from acloud.internal import constants 29from acloud.internal.lib import android_build_client 30from acloud.internal.lib import auth 31from acloud.internal.lib import goldfish_compute_client 32from acloud.internal.lib import utils 33 34 35logger = logging.getLogger(__name__) 36 37_EMULATOR_INFO_FILENAME = "emulator-info.txt" 38_SYSIMAGE_INFO_FILENAME = "android-info.txt" 39_VERSION_PATTERN = r"version-.*=(\d+)" 40 41 42class GoldfishDeviceFactory(base_device_factory.BaseDeviceFactory): 43 """A class that can produce a goldfish device. 44 45 Attributes: 46 _cfg: An AcloudConfig instance. 47 _build_target: String, the build target, e.g. aosp_x86-eng. 48 _build_id: String, Build id, e.g. "2263051", "P2804227" 49 _emulator_build_target: String, the emulator build target, e.g. aosp_x86-eng. 50 _emulator_build_id: String, emulator build id. 51 _gpu: String, GPU to attach to the device or None. e.g. "nvidia-tesla-k80" 52 _blank_data_disk_size_gb: Integer, extra disk size 53 _build_client: An AndroidBuildClient instance 54 _branch: String, android branch name, e.g. git_master 55 _emulator_branch: String, emulator branch name, e.g. "aosp-emu-master-dev" 56 """ 57 LOG_FILES = ["/home/vsoc-01/emulator.log", 58 "/home/vsoc-01/log/logcat.log", 59 "/home/vsoc-01/log/adb.log", 60 "/var/log/daemon.log"] 61 62 def __init__(self, 63 cfg, 64 build_target, 65 build_id, 66 emulator_build_target, 67 emulator_build_id, 68 kernel_build_id=None, 69 kernel_branch=None, 70 kernel_build_target=None, 71 gpu=None, 72 avd_spec=None, 73 tags=None, 74 branch=None, 75 emulator_branch=None): 76 77 """Initialize. 78 79 Args: 80 cfg: An AcloudConfig instance. 81 build_target: String, the build target, e.g. aosp_x86-eng. 82 build_id: String, Build id, e.g. "2263051", "P2804227" 83 emulator_build_target: String, the emulator build target, e.g. aosp_x86-eng. 84 emulator_build_id: String, emulator build id. 85 gpu: String, GPU to attach to the device or None. e.g. "nvidia-tesla-k80" 86 avd_spec: An AVDSpec instance. 87 tags: A list of tags to associate with the instance. e.g. 88 ["http-server", "https-server"] 89 branch: String, branch of the emulator build target. 90 emulator_branch: String, branch of the emulator. 91 """ 92 93 self.credentials = auth.CreateCredentials(cfg) 94 95 compute_client = goldfish_compute_client.GoldfishComputeClient( 96 cfg, self.credentials) 97 super().__init__(compute_client) 98 99 # Private creation parameters 100 self._cfg = cfg 101 self._gpu = gpu 102 self._avd_spec = avd_spec 103 self._blank_data_disk_size_gb = cfg.extra_data_disk_size_gb 104 self._extra_scopes = cfg.extra_scopes 105 self._tags = tags 106 107 # Configure clients 108 self._build_client = android_build_client.AndroidBuildClient( 109 self.credentials) 110 111 # Get build info 112 self.build_info = self._build_client.GetBuildInfo( 113 build_target, build_id, branch) 114 self.emulator_build_info = self._build_client.GetBuildInfo( 115 emulator_build_target, emulator_build_id, emulator_branch) 116 self.kernel_build_info = self._build_client.GetBuildInfo( 117 kernel_build_target or cfg.kernel_build_target, kernel_build_id, 118 kernel_branch) 119 120 def GetBuildInfoDict(self): 121 """Get build info dictionary. 122 123 Returns: 124 A build info dictionary 125 """ 126 build_info_dict = { 127 key: val for key, val in utils.GetDictItems(self.build_info) if val} 128 129 build_info_dict.update( 130 {"emulator_%s" % key: val 131 for key, val in utils.GetDictItems(self.emulator_build_info) if val} 132 ) 133 134 build_info_dict.update( 135 {"kernel_%s" % key: val 136 for key, val in utils.GetDictItems(self.kernel_build_info) if val} 137 ) 138 139 return build_info_dict 140 141 def CreateInstance(self): 142 """Creates single configured goldfish device. 143 144 Override method from parent class. 145 146 Returns: 147 String, the name of the created instance. 148 """ 149 instance = self._compute_client.GenerateInstanceName( 150 build_id=self.build_info.build_id, 151 build_target=self.build_info.build_target) 152 153 self._compute_client.CreateInstance( 154 instance=instance, 155 image_name=self._cfg.stable_goldfish_host_image_name, 156 image_project=self._cfg.stable_goldfish_host_image_project, 157 build_target=self.build_info.build_target, 158 branch=self.build_info.branch, 159 build_id=self.build_info.build_id, 160 emulator_branch=self.emulator_build_info.branch, 161 emulator_build_id=self.emulator_build_info.build_id, 162 emulator_build_target=self.emulator_build_info.build_target, 163 kernel_branch=self.kernel_build_info.branch, 164 kernel_build_id=self.kernel_build_info.build_id, 165 kernel_build_target=self.kernel_build_info.build_target, 166 gpu=self._gpu, 167 blank_data_disk_size_gb=self._blank_data_disk_size_gb, 168 avd_spec=self._avd_spec, 169 tags=self._tags, 170 extra_scopes=self._extra_scopes, 171 launch_args=self._cfg.launch_args) 172 173 return instance 174 175 176def ParseBuildInfo(filename): 177 """Parse build id based on a substring. 178 179 This will parse a file which contains build information to be used. For an 180 emulator build, the file will contain the information about the 181 corresponding stable system image build id. In emulator-info.txt, the file 182 will contains the information about the corresponding stable emulator 183 build id, for example "require version-emulator=5292001". In 184 android-info.txt, the file will contains the information about a stable 185 system image build id, for example 186 "version-sysimage-git_pi-dev-sdk_gphone_x86_64-userdebug=4833817" 187 188 Args: 189 filename: Name of file to parse. 190 191 Returns: 192 Build id parsed from the file based on pattern 193 Returns None if pattern not found in file 194 """ 195 with open(filename) as build_info_file: 196 for line in build_info_file: 197 match = re.search(_VERSION_PATTERN, line) 198 if match: 199 return match.group(1) 200 return None 201 202 203def _FetchBuildIdFromFile(cfg, build_target, build_id, filename): 204 """Parse and fetch build id from a file based on a pattern. 205 206 Verify if one of the system image or emulator binary build id is missing. 207 If found missing, then update according to the resource file. 208 209 Args: 210 cfg: An AcloudConfig instance. 211 build_target: Target name. 212 build_id: Build id, a string, e.g. "2263051", "P2804227" 213 filename: Name of file containing the build info. 214 215 Returns: 216 A build id or None 217 """ 218 build_client = android_build_client.AndroidBuildClient( 219 auth.CreateCredentials(cfg)) 220 221 with utils.TempDir() as tempdir: 222 temp_filename = os.path.join(tempdir, filename) 223 build_client.DownloadArtifact(build_target, 224 build_id, 225 filename, 226 temp_filename) 227 228 return ParseBuildInfo(temp_filename) 229 230 231#pylint: disable=too-many-locals 232def CreateDevices(avd_spec=None, 233 cfg=None, 234 build_target=None, 235 build_id=None, 236 emulator_build_id=None, 237 emulator_branch=None, 238 emulator_build_target=None, 239 kernel_build_id=None, 240 kernel_branch=None, 241 kernel_build_target=None, 242 gpu=None, 243 num=1, 244 serial_log_file=None, 245 autoconnect=False, 246 branch=None, 247 tags=None, 248 report_internal_ip=False, 249 boot_timeout_secs=None): 250 """Create one or multiple Goldfish devices. 251 252 Args: 253 avd_spec: An AVDSpec instance. 254 cfg: An AcloudConfig instance. 255 build_target: String, the build target, e.g. aosp_x86-eng. 256 build_id: String, Build id, e.g. "2263051", "P2804227" 257 branch: String, Branch name for system image. 258 emulator_build_id: String, emulator build id. 259 emulator_branch: String, emulator branch name. 260 emulator_build_target: String, emulator build target. 261 gpu: String, GPU to attach to the device or None. e.g. "nvidia-k80" 262 kernel_build_id: Kernel build id, a string. 263 kernel_branch: Kernel branch name, a string. 264 kernel_build_target: Kernel build artifact, a string. 265 num: Integer, Number of devices to create. 266 serial_log_file: String, A path to a file where serial output should 267 be saved to. 268 autoconnect: Boolean, Create ssh tunnel(s) and adb connect after device 269 creation. 270 branch: String, Branch name for system image. 271 tags: A list of tags to associate with the instance. e.g. 272 ["http-server", "https-server"] 273 report_internal_ip: Boolean to report the internal ip instead of 274 external ip. 275 boot_timeout_secs: Integer, the maximum time in seconds used to 276 wait for the AVD to boot. 277 278 Returns: 279 A Report instance. 280 """ 281 client_adb_port = None 282 if avd_spec: 283 cfg = avd_spec.cfg 284 build_target = avd_spec.remote_image[constants.BUILD_TARGET] 285 build_id = avd_spec.remote_image[constants.BUILD_ID] 286 branch = avd_spec.remote_image[constants.BUILD_BRANCH] 287 num = avd_spec.num 288 emulator_build_id = avd_spec.emulator_build_id 289 emulator_build_target = avd_spec.emulator_build_target 290 gpu = avd_spec.gpu 291 serial_log_file = avd_spec.serial_log_file 292 autoconnect = avd_spec.autoconnect 293 report_internal_ip = avd_spec.report_internal_ip 294 client_adb_port = avd_spec.client_adb_port 295 boot_timeout_secs = avd_spec.boot_timeout_secs 296 297 if not emulator_build_target: 298 emulator_build_target = cfg.emulator_build_target 299 300 # If emulator_build_id and emulator_branch is None, retrieve emulator 301 # build id from platform build emulator-info.txt artifact 302 # Example: require version-emulator=5292001 303 if not emulator_build_id and not emulator_branch: 304 logger.info("emulator_build_id not provided. " 305 "Attempting to get %s from build %s/%s.", _EMULATOR_INFO_FILENAME, 306 build_id, build_target) 307 emulator_build_id = _FetchBuildIdFromFile(cfg, 308 build_target, 309 build_id, 310 _EMULATOR_INFO_FILENAME) 311 312 if not emulator_build_id: 313 raise errors.CommandArgError("Emulator build id not found " 314 "in %s" % _EMULATOR_INFO_FILENAME) 315 316 # If build_id and branch is None, retrieve build_id from 317 # emulator build android-info.txt artifact 318 # Example: version-sysimage-git_pi-dev-sdk_gphone_x86_64-userdebug=4833817 319 if not build_id and not branch: 320 build_id = _FetchBuildIdFromFile(cfg, 321 emulator_build_target, 322 emulator_build_id, 323 _SYSIMAGE_INFO_FILENAME) 324 325 if not build_id: 326 raise errors.CommandArgError("Emulator system image build id not found " 327 "in %s" % _SYSIMAGE_INFO_FILENAME) 328 logger.info( 329 "Creating a goldfish device in project %s, build_target: %s, " 330 "build_id: %s, emulator_bid: %s, emulator_branch: %s, kernel_build_id: %s, " 331 "kernel_branch: %s, kernel_build_target: %s, GPU: %s, num: %s, " 332 "serial_log_file: %s, " 333 "autoconnect: %s", cfg.project, build_target, build_id, 334 emulator_build_id, emulator_branch, kernel_build_id, kernel_branch, 335 kernel_build_target, gpu, num, serial_log_file, autoconnect) 336 337 device_factory = GoldfishDeviceFactory( 338 cfg, build_target, build_id, 339 emulator_build_target, 340 emulator_build_id, gpu=gpu, 341 avd_spec=avd_spec, tags=tags, 342 branch=branch, 343 emulator_branch=emulator_branch, 344 kernel_build_id=kernel_build_id, 345 kernel_branch=kernel_branch, 346 kernel_build_target=kernel_build_target) 347 348 return common_operations.CreateDevices("create_gf", cfg, device_factory, 349 num, constants.TYPE_GF, 350 report_internal_ip, autoconnect, 351 serial_log_file, client_adb_port, 352 boot_timeout_secs) 353