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 17"""Create cuttlefish instances. 18 19TODO: This module now just contains the skeleton but not the actual logic. 20 Need to fill in the actuall logic. 21""" 22 23import logging 24 25from acloud.public.actions import common_operations 26from acloud.public.actions import base_device_factory 27from acloud.internal import constants 28from acloud.internal.lib import android_build_client 29from acloud.internal.lib import auth 30from acloud.internal.lib import cvd_compute_client 31from acloud.internal.lib import cvd_compute_client_multi_stage 32from acloud.internal.lib import utils 33 34 35logger = logging.getLogger(__name__) 36 37 38class CuttlefishDeviceFactory(base_device_factory.BaseDeviceFactory): 39 """A class that can produce a cuttlefish device. 40 41 Attributes: 42 cfg: An AcloudConfig instance. 43 build_target: String,Target name. 44 build_id: String, Build id, e.g. "2263051", "P2804227" 45 kernel_build_id: String, Kernel build id. 46 gpu: String, GPU to attach to the device or None. e.g. "nvidia-tesla-k80" 47 """ 48 49 LOG_FILES = ["/home/vsoc-01/cuttlefish_runtime/kernel.log", 50 "/home/vsoc-01/cuttlefish_runtime/logcat", 51 "/home/vsoc-01/cuttlefish_runtime/cuttlefish_config.json"] 52 53 #pylint: disable=too-many-locals 54 def __init__(self, cfg, build_target, build_id, branch=None, 55 kernel_build_id=None, kernel_branch=None, 56 kernel_build_target=None, system_branch=None, 57 system_build_id=None, system_build_target=None, 58 bootloader_branch=None, bootloader_build_id=None, 59 bootloader_build_target=None, boot_timeout_secs=None, 60 ins_timeout_secs=None, report_internal_ip=None, gpu=None): 61 62 self.credentials = auth.CreateCredentials(cfg) 63 64 if cfg.enable_multi_stage: 65 compute_client = cvd_compute_client_multi_stage.CvdComputeClient( 66 cfg, self.credentials, boot_timeout_secs, ins_timeout_secs, 67 report_internal_ip, gpu) 68 else: 69 compute_client = cvd_compute_client.CvdComputeClient( 70 cfg, self.credentials) 71 super(CuttlefishDeviceFactory, self).__init__(compute_client) 72 73 # Private creation parameters 74 self._cfg = cfg 75 self._build_target = build_target 76 self._build_id = build_id 77 self._branch = branch 78 self._kernel_build_id = kernel_build_id 79 self._blank_data_disk_size_gb = cfg.extra_data_disk_size_gb 80 self._extra_scopes = cfg.extra_scopes 81 82 # Configure clients for interaction with GCE/Build servers 83 self._build_client = android_build_client.AndroidBuildClient( 84 self.credentials) 85 86 # Get build_info namedtuple for platform, kernel, system build 87 self.build_info = self._build_client.GetBuildInfo( 88 build_target, build_id, branch) 89 self.kernel_build_info = self._build_client.GetBuildInfo( 90 kernel_build_target or cfg.kernel_build_target, kernel_build_id, 91 kernel_branch) 92 self.system_build_info = self._build_client.GetBuildInfo( 93 system_build_target or build_target, system_build_id, system_branch) 94 self.bootloader_build_info = self._build_client.GetBuildInfo( 95 bootloader_build_target, bootloader_build_id, bootloader_branch) 96 97 def GetBuildInfoDict(self): 98 """Get build info dictionary. 99 100 Returns: 101 A build info dictionary. 102 """ 103 build_info_dict = { 104 key: val for key, val in utils.GetDictItems(self.build_info) if val} 105 106 build_info_dict.update( 107 {"kernel_%s" % key: val 108 for key, val in utils.GetDictItems(self.kernel_build_info) if val} 109 ) 110 build_info_dict.update( 111 {"system_%s" % key: val 112 for key, val in utils.GetDictItems(self.system_build_info) if val} 113 ) 114 build_info_dict.update( 115 {"bootloader_%s" % key: val 116 for key, val in utils.GetDictItems(self.bootloader_build_info) if val} 117 ) 118 return build_info_dict 119 120 def GetFailures(self): 121 """Get failures from all devices. 122 123 Returns: 124 A dictionary that contains all the failures. 125 The key is the name of the instance that fails to boot, 126 and the value is an errors.DeviceBootError object. 127 """ 128 return self._compute_client.all_failures 129 130 @staticmethod 131 def _GetGcsBucketBuildId(build_id, release_id): 132 """Get GCS Bucket Build Id. 133 134 Args: 135 build_id: The incremental build id. For example 5325535. 136 release_id: The release build id, None if not a release build. 137 For example AAAA.190220.001. 138 139 Returns: 140 GCS bucket build id. For example: AAAA.190220.001-5325535 141 """ 142 return "-".join([release_id, build_id]) if release_id else build_id 143 144 def CreateInstance(self): 145 """Creates singe configured cuttlefish device. 146 147 Override method from parent class. 148 149 Returns: 150 A string, representing instance name. 151 """ 152 153 # Create host instances for cuttlefish device. Currently one host instance 154 # has one cuttlefish device. In the future, these logics should be modified 155 # to support multiple cuttlefish devices per host instance. 156 instance = self._compute_client.GenerateInstanceName( 157 build_id=self.build_info.build_id, build_target=self._build_target) 158 159 if self._cfg.enable_multi_stage: 160 remote_build_id = self.build_info.build_id 161 else: 162 remote_build_id = self._GetGcsBucketBuildId( 163 self.build_info.build_id, self.build_info.release_build_id) 164 165 if self._cfg.enable_multi_stage: 166 remote_system_build_id = self.system_build_info.build_id 167 else: 168 remote_system_build_id = self._GetGcsBucketBuildId( 169 self.system_build_info.build_id, self.system_build_info.release_build_id) 170 171 host_image_name = self._compute_client.GetHostImageName( 172 self._cfg.stable_host_image_name, 173 self._cfg.stable_host_image_family, 174 self._cfg.stable_host_image_project) 175 # Create an instance from Stable Host Image 176 self._compute_client.CreateInstance( 177 instance=instance, 178 image_name=host_image_name, 179 image_project=self._cfg.stable_host_image_project, 180 build_target=self.build_info.build_target, 181 branch=self.build_info.branch, 182 build_id=remote_build_id, 183 kernel_branch=self.kernel_build_info.branch, 184 kernel_build_id=self.kernel_build_info.build_id, 185 kernel_build_target=self.kernel_build_info.build_target, 186 blank_data_disk_size_gb=self._blank_data_disk_size_gb, 187 extra_scopes=self._extra_scopes, 188 system_build_target=self.system_build_info.build_target, 189 system_branch=self.system_build_info.branch, 190 system_build_id=remote_system_build_id, 191 bootloader_build_target=self.bootloader_build_info.build_target, 192 bootloader_branch=self.bootloader_build_info.branch, 193 bootloader_build_id=self.bootloader_build_info.build_id) 194 195 return instance 196 197 198#pylint: disable=too-many-locals 199def CreateDevices(cfg, 200 build_target=None, 201 build_id=None, 202 branch=None, 203 kernel_build_id=None, 204 kernel_branch=None, 205 kernel_build_target=None, 206 system_branch=None, 207 system_build_id=None, 208 system_build_target=None, 209 bootloader_branch=None, 210 bootloader_build_id=None, 211 bootloader_build_target=None, 212 gpu=None, 213 num=1, 214 serial_log_file=None, 215 autoconnect=False, 216 report_internal_ip=False, 217 boot_timeout_secs=None, 218 ins_timeout_secs=None): 219 """Create one or multiple Cuttlefish devices. 220 221 Args: 222 cfg: An AcloudConfig instance. 223 build_target: String, Target name. 224 build_id: String, Build id, e.g. "2263051", "P2804227" 225 branch: Branch name, a string, e.g. aosp_master 226 kernel_build_id: String, Kernel build id. 227 kernel_branch: String, Kernel branch name. 228 kernel_build_target: String, Kernel build target name. 229 system_branch: Branch name to consume the system.img from, a string. 230 system_build_id: System branch build id, a string. 231 system_build_target: System image build target, a string. 232 bootloader_branch: String of the bootloader branch name. 233 bootloader_build_id: String of the bootloader build id. 234 bootloader_build_target: String of the bootloader target name. 235 gpu: String, GPU to attach to the device or None. e.g. "nvidia-tesla-k80" 236 num: Integer, Number of devices to create. 237 serial_log_file: String, A path to a tar file where serial output should 238 be saved to. 239 autoconnect: Boolean, Create ssh tunnel(s) and adb connect after device 240 creation. 241 report_internal_ip: Boolean to report the internal ip instead of 242 external ip. 243 boot_timeout_secs: Integer, the maximum time in seconds used to wait 244 for the AVD to boot. 245 ins_timeout_secs: Integer, the maximum time in seconds used to wait for 246 the instance ready. 247 248 Returns: 249 A Report instance. 250 """ 251 client_adb_port = None 252 unlock_screen = False 253 wait_for_boot = True 254 logger.info( 255 "Creating a cuttlefish device in project %s, " 256 "build_target: %s, " 257 "build_id: %s, " 258 "branch: %s, " 259 "kernel_build_id: %s, " 260 "kernel_branch: %s, " 261 "kernel_build_target: %s, " 262 "system_branch: %s, " 263 "system_build_id: %s, " 264 "system_build_target: %s, " 265 "bootloader_branch: %s, " 266 "bootloader_build_id: %s, " 267 "bootloader_build_target: %s, " 268 "gpu: %s" 269 "num: %s, " 270 "serial_log_file: %s, " 271 "autoconnect: %s, " 272 "report_internal_ip: %s", cfg.project, build_target, 273 build_id, branch, kernel_build_id, kernel_branch, kernel_build_target, 274 system_branch, system_build_id, system_build_target, bootloader_branch, 275 bootloader_build_id, bootloader_build_target, gpu, num, serial_log_file, 276 autoconnect, report_internal_ip) 277 # If multi_stage enable, launch_cvd don't write serial log to instance. So 278 # it doesn't go WaitForBoot function. 279 if cfg.enable_multi_stage: 280 wait_for_boot = False 281 device_factory = CuttlefishDeviceFactory( 282 cfg, build_target, build_id, branch=branch, 283 kernel_build_id=kernel_build_id, kernel_branch=kernel_branch, 284 kernel_build_target=kernel_build_target, system_branch=system_branch, 285 system_build_id=system_build_id, 286 system_build_target=system_build_target, 287 bootloader_branch=bootloader_branch, 288 bootloader_build_id=bootloader_build_id, 289 bootloader_build_target=bootloader_build_target, 290 boot_timeout_secs=boot_timeout_secs, 291 ins_timeout_secs=ins_timeout_secs, 292 report_internal_ip=report_internal_ip, 293 gpu=gpu) 294 return common_operations.CreateDevices("create_cf", cfg, device_factory, 295 num, constants.TYPE_CF, 296 report_internal_ip, autoconnect, 297 serial_log_file, client_adb_port, 298 boot_timeout_secs, unlock_screen, 299 wait_for_boot) 300