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"""GCE device factory. 18 19GCEDeviceFactory provides a base class for AVDs that run on GCE. 20""" 21 22import os 23 24from acloud.internal import constants 25from acloud.internal.lib import auth 26from acloud.internal.lib import cvd_compute_client_multi_stage 27from acloud.internal.lib import ssh 28from acloud.public.actions import base_device_factory 29 30 31class GCEDeviceFactory(base_device_factory.BaseDeviceFactory): 32 """A base class for AVDs that run on GCE.""" 33 34 _USER_BUILD = "userbuild" 35 36 def __init__(self, avd_spec, local_image_artifact=None): 37 """Constructs a new remote instance device factory.""" 38 self._avd_spec = avd_spec 39 self._cfg = avd_spec.cfg 40 self._local_image_artifact = local_image_artifact 41 self._report_internal_ip = avd_spec.report_internal_ip 42 self._all_failures = {} 43 self.credentials = auth.CreateCredentials(avd_spec.cfg) 44 # Control compute_client with enable_multi_stage 45 compute_client = cvd_compute_client_multi_stage.CvdComputeClient( 46 acloud_config=avd_spec.cfg, 47 oauth2_credentials=self.credentials, 48 ins_timeout_secs=avd_spec.ins_timeout_secs, 49 report_internal_ip=avd_spec.report_internal_ip, 50 gpu=avd_spec.gpu) 51 super().__init__(compute_client) 52 self._ssh = None 53 54 def CreateGceInstance(self): 55 """Create a single configured GCE instance. 56 57 build_target: The format is like "aosp_cf_x86_phone". We only get info 58 from the user build image file name. If the file name is 59 not custom format (no "-"), we will use $TARGET_PRODUCT 60 from environment variable as build_target. 61 62 Returns: 63 A string, representing instance name. 64 """ 65 image_name = os.path.basename( 66 self._local_image_artifact) if self._local_image_artifact else "" 67 build_target = (os.environ.get(constants.ENV_BUILD_TARGET) if "-" not 68 in image_name else image_name.split("-")[0]) 69 build_id = self._USER_BUILD 70 if self._avd_spec.image_source == constants.IMAGE_SRC_REMOTE: 71 build_id = self._avd_spec.remote_image[constants.BUILD_ID] 72 build_target = self._avd_spec.remote_image[constants.BUILD_TARGET] 73 74 if self._avd_spec.instance_name_to_reuse: 75 instance = self._avd_spec.instance_name_to_reuse 76 else: 77 instance = self._compute_client.GenerateInstanceName( 78 build_target=build_target, build_id=build_id) 79 80 host_image_name = self._compute_client.GetHostImageName( 81 self._avd_spec.stable_host_image_name, 82 self._cfg.stable_host_image_family, 83 self._cfg.stable_host_image_project) 84 85 # Create an instance from Stable Host Image 86 self._compute_client.CreateInstance( 87 instance=instance, 88 image_name=host_image_name, 89 image_project=self._cfg.stable_host_image_project, 90 avd_spec=self._avd_spec) 91 ip = self._compute_client.GetInstanceIP(instance) 92 self._all_failures = self._compute_client.all_failures 93 self._ssh = ssh.Ssh(ip=ip, 94 user=constants.GCE_USER, 95 ssh_private_key_path=self._cfg.ssh_private_key_path, 96 extra_args_ssh_tunnel=self._cfg.extra_args_ssh_tunnel, 97 report_internal_ip=self._report_internal_ip, 98 gce_hostname=self._compute_client.gce_hostname) 99 return instance 100 101 def GetFailures(self): 102 """Get failures from all devices. 103 104 Returns: 105 A dictionary that contains all the failures. 106 The key is the name of the instance that fails to boot, 107 and the value is a string or an errors.DeviceBootError object. 108 """ 109 return self._all_failures 110 111 def _SetFailures(self, instance, error_msg): 112 """Set failures from this device. 113 114 Record the failures for any steps in AVD creation. 115 116 Args: 117 instance: String of instance name. 118 error_msg: String of error message. 119 """ 120 self._all_failures[instance] = error_msg 121