#!/usr/bin/env python # # Copyright 2018 - The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """GCE device factory. GCEDeviceFactory provides a base class for AVDs that run on GCE. """ import os from acloud.internal import constants from acloud.internal.lib import auth from acloud.internal.lib import cvd_compute_client_multi_stage from acloud.internal.lib import ssh from acloud.public.actions import base_device_factory class GCEDeviceFactory(base_device_factory.BaseDeviceFactory): """A base class for AVDs that run on GCE.""" _USER_BUILD = "userbuild" def __init__(self, avd_spec, local_image_artifact=None): """Constructs a new remote instance device factory.""" self._avd_spec = avd_spec self._cfg = avd_spec.cfg self._local_image_artifact = local_image_artifact self._report_internal_ip = avd_spec.report_internal_ip self.credentials = auth.CreateCredentials(avd_spec.cfg) # Control compute_client with enable_multi_stage compute_client = cvd_compute_client_multi_stage.CvdComputeClient( acloud_config=avd_spec.cfg, oauth2_credentials=self.credentials, ins_timeout_secs=avd_spec.ins_timeout_secs, report_internal_ip=avd_spec.report_internal_ip, gpu=avd_spec.gpu) super(GCEDeviceFactory, self).__init__(compute_client) self._ssh = None def _CreateGceInstance(self): """Create a single configured GCE instance. build_target: The format is like "aosp_cf_x86_phone". We only get info from the user build image file name. If the file name is not custom format (no "-"), we will use $TARGET_PRODUCT from environment variable as build_target. Returns: A string, representing instance name. """ image_name = os.path.basename( self._local_image_artifact) if self._local_image_artifact else "" build_target = (os.environ.get(constants.ENV_BUILD_TARGET) if "-" not in image_name else image_name.split("-")[0]) build_id = self._USER_BUILD if self._avd_spec.image_source == constants.IMAGE_SRC_REMOTE: build_id = self._avd_spec.remote_image[constants.BUILD_ID] build_target = self._avd_spec.remote_image[constants.BUILD_TARGET] if self._avd_spec.instance_name_to_reuse: instance = self._avd_spec.instance_name_to_reuse else: instance = self._compute_client.GenerateInstanceName( build_target=build_target, build_id=build_id) host_image_name = self._compute_client.GetHostImageName( self._cfg.stable_host_image_name, self._cfg.stable_host_image_family, self._cfg.stable_host_image_project) # Create an instance from Stable Host Image self._compute_client.CreateInstance( instance=instance, image_name=host_image_name, image_project=self._cfg.stable_host_image_project, blank_data_disk_size_gb=self._cfg.extra_data_disk_size_gb, avd_spec=self._avd_spec) ip = self._compute_client.GetInstanceIP(instance) self._ssh = ssh.Ssh(ip=ip, user=constants.GCE_USER, ssh_private_key_path=self._cfg.ssh_private_key_path, extra_args_ssh_tunnel=self._cfg.extra_args_ssh_tunnel, report_internal_ip=self._report_internal_ip) return instance def GetFailures(self): """Get failures from all devices. Returns: A dictionary that contains all the failures. The key is the name of the instance that fails to boot, and the value is an errors.DeviceBootError object. """ return self._compute_client.all_failures def _SetFailures(self, instance, error_msg): """Set failures from this device. Record the failures for any steps in AVD creation. Args: instance: String of instance name. error_msg: String of error message. """ self._compute_client.all_failures[instance] = error_msg