• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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