• 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"""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