• 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"""Action to create goldfish device instances.
17
18A Goldfish device is an emulated android device based on the android
19emulator.
20"""
21import logging
22import os
23import re
24
25from acloud import errors
26from acloud.public.actions import base_device_factory
27from acloud.public.actions import common_operations
28from acloud.internal import constants
29from acloud.internal.lib import android_build_client
30from acloud.internal.lib import auth
31from acloud.internal.lib import goldfish_compute_client
32from acloud.internal.lib import utils
33
34
35logger = logging.getLogger(__name__)
36
37_EMULATOR_INFO_FILENAME = "emulator-info.txt"
38_SYSIMAGE_INFO_FILENAME = "android-info.txt"
39_VERSION_PATTERN = r"version-.*=(\d+)"
40
41
42class GoldfishDeviceFactory(base_device_factory.BaseDeviceFactory):
43    """A class that can produce a goldfish device.
44
45    Attributes:
46        _cfg: An AcloudConfig instance.
47        _build_target: String, the build target, e.g. aosp_x86-eng.
48        _build_id: String, Build id, e.g. "2263051", "P2804227"
49        _emulator_build_target: String, the emulator build target, e.g. aosp_x86-eng.
50        _emulator_build_id: String, emulator build id.
51        _gpu: String, GPU to attach to the device or None. e.g. "nvidia-tesla-k80"
52        _blank_data_disk_size_gb: Integer, extra disk size
53        _build_client: An AndroidBuildClient instance
54        _branch: String, android branch name, e.g. git_master
55        _emulator_branch: String, emulator branch name, e.g. "aosp-emu-master-dev"
56    """
57    LOG_FILES = ["/home/vsoc-01/emulator.log",
58                 "/home/vsoc-01/log/logcat.log",
59                 "/home/vsoc-01/log/adb.log",
60                 "/var/log/daemon.log"]
61
62    def __init__(self,
63                 cfg,
64                 build_target,
65                 build_id,
66                 emulator_build_target,
67                 emulator_build_id,
68                 kernel_build_id=None,
69                 kernel_branch=None,
70                 kernel_build_target=None,
71                 gpu=None,
72                 avd_spec=None,
73                 tags=None,
74                 branch=None,
75                 emulator_branch=None):
76
77        """Initialize.
78
79        Args:
80            cfg: An AcloudConfig instance.
81            build_target: String, the build target, e.g. aosp_x86-eng.
82            build_id: String, Build id, e.g. "2263051", "P2804227"
83            emulator_build_target: String, the emulator build target, e.g. aosp_x86-eng.
84            emulator_build_id: String, emulator build id.
85            gpu: String, GPU to attach to the device or None. e.g. "nvidia-tesla-k80"
86            avd_spec: An AVDSpec instance.
87            tags: A list of tags to associate with the instance. e.g.
88                  ["http-server", "https-server"]
89            branch: String, branch of the emulator build target.
90            emulator_branch: String, branch of the emulator.
91        """
92
93        self.credentials = auth.CreateCredentials(cfg)
94
95        compute_client = goldfish_compute_client.GoldfishComputeClient(
96            cfg, self.credentials)
97        super(GoldfishDeviceFactory, self).__init__(compute_client)
98
99        # Private creation parameters
100        self._cfg = cfg
101        self._gpu = gpu
102        self._avd_spec = avd_spec
103        self._blank_data_disk_size_gb = cfg.extra_data_disk_size_gb
104        self._extra_scopes = cfg.extra_scopes
105        self._tags = tags
106
107        # Configure clients
108        self._build_client = android_build_client.AndroidBuildClient(
109            self.credentials)
110
111        # Get build info
112        self.build_info = self._build_client.GetBuildInfo(
113            build_target, build_id, branch)
114        self.emulator_build_info = self._build_client.GetBuildInfo(
115            emulator_build_target, emulator_build_id, emulator_branch)
116        self.kernel_build_info = self._build_client.GetBuildInfo(
117            kernel_build_target or cfg.kernel_build_target, kernel_build_id,
118            kernel_branch)
119
120    def GetBuildInfoDict(self):
121        """Get build info dictionary.
122
123        Returns:
124          A build info dictionary
125        """
126        build_info_dict = {
127            key: val for key, val in utils.GetDictItems(self.build_info) if val}
128
129        build_info_dict.update(
130            {"emulator_%s" % key: val
131             for key, val in utils.GetDictItems(self.emulator_build_info) if val}
132            )
133
134        build_info_dict.update(
135            {"kernel_%s" % key: val
136             for key, val in utils.GetDictItems(self.kernel_build_info) if val}
137            )
138
139        return build_info_dict
140
141    def CreateInstance(self):
142        """Creates single configured goldfish device.
143
144        Override method from parent class.
145
146        Returns:
147            String, the name of the created instance.
148        """
149        instance = self._compute_client.GenerateInstanceName(
150            build_id=self.build_info.build_id,
151            build_target=self.build_info.build_target)
152
153        self._compute_client.CreateInstance(
154            instance=instance,
155            image_name=self._cfg.stable_goldfish_host_image_name,
156            image_project=self._cfg.stable_goldfish_host_image_project,
157            build_target=self.build_info.build_target,
158            branch=self.build_info.branch,
159            build_id=self.build_info.build_id,
160            emulator_branch=self.emulator_build_info.branch,
161            emulator_build_id=self.emulator_build_info.build_id,
162            kernel_branch=self.kernel_build_info.branch,
163            kernel_build_id=self.kernel_build_info.build_id,
164            kernel_build_target=self.kernel_build_info.build_target,
165            gpu=self._gpu,
166            blank_data_disk_size_gb=self._blank_data_disk_size_gb,
167            avd_spec=self._avd_spec,
168            tags=self._tags,
169            extra_scopes=self._extra_scopes)
170
171        return instance
172
173
174def ParseBuildInfo(filename):
175    """Parse build id based on a substring.
176
177    This will parse a file which contains build information to be used. For an
178    emulator build, the file will contain the information about the
179    corresponding stable system image build id. In emulator-info.txt, the file
180    will contains the information about the corresponding stable emulator
181    build id, for example "require version-emulator=5292001". In
182    android-info.txt, the file will contains the information about a stable
183    system image build id, for example
184    "version-sysimage-git_pi-dev-sdk_gphone_x86_64-userdebug=4833817"
185
186    Args:
187        filename: Name of file to parse.
188
189    Returns:
190        Build id parsed from the file based on pattern
191        Returns None if pattern not found in file
192    """
193    with open(filename) as build_info_file:
194        for line in build_info_file:
195            match = re.search(_VERSION_PATTERN, line)
196            if match:
197                return match.group(1)
198    return None
199
200
201def _FetchBuildIdFromFile(cfg, build_target, build_id, filename):
202    """Parse and fetch build id from a file based on a pattern.
203
204    Verify if one of the system image or emulator binary build id is missing.
205    If found missing, then update according to the resource file.
206
207    Args:
208        cfg: An AcloudConfig instance.
209        build_target: Target name.
210        build_id: Build id, a string, e.g. "2263051", "P2804227"
211        filename: Name of file containing the build info.
212
213    Returns:
214        A build id or None
215    """
216    build_client = android_build_client.AndroidBuildClient(
217        auth.CreateCredentials(cfg))
218
219    with utils.TempDir() as tempdir:
220        temp_filename = os.path.join(tempdir, filename)
221        build_client.DownloadArtifact(build_target,
222                                      build_id,
223                                      filename,
224                                      temp_filename)
225
226        return ParseBuildInfo(temp_filename)
227
228
229#pylint: disable=too-many-locals
230def CreateDevices(avd_spec=None,
231                  cfg=None,
232                  build_target=None,
233                  build_id=None,
234                  emulator_build_id=None,
235                  emulator_branch=None,
236                  kernel_build_id=None,
237                  kernel_branch=None,
238                  kernel_build_target=None,
239                  gpu=None,
240                  num=1,
241                  serial_log_file=None,
242                  autoconnect=False,
243                  branch=None,
244                  tags=None,
245                  report_internal_ip=False):
246    """Create one or multiple Goldfish devices.
247
248    Args:
249        avd_spec: An AVDSpec instance.
250        cfg: An AcloudConfig instance.
251        build_target: String, the build target, e.g. aosp_x86-eng.
252        build_id: String, Build id, e.g. "2263051", "P2804227"
253        branch: String, Branch name for system image.
254        emulator_build_id: String, emulator build id.
255        emulator_branch: String, Emulator branch name.
256        gpu: String, GPU to attach to the device or None. e.g. "nvidia-k80"
257        kernel_build_id: Kernel build id, a string.
258        kernel_branch: Kernel branch name, a string.
259        kernel_build_target: Kernel build artifact, a string.
260        num: Integer, Number of devices to create.
261        serial_log_file: String, A path to a file where serial output should
262                        be saved to.
263        autoconnect: Boolean, Create ssh tunnel(s) and adb connect after device
264                     creation.
265        branch: String, Branch name for system image.
266        tags: A list of tags to associate with the instance. e.g.
267              ["http-server", "https-server"]
268        report_internal_ip: Boolean to report the internal ip instead of
269                            external ip.
270
271    Returns:
272        A Report instance.
273    """
274    client_adb_port = None
275    boot_timeout_secs = None
276    if avd_spec:
277        cfg = avd_spec.cfg
278        build_target = avd_spec.remote_image[constants.BUILD_TARGET]
279        build_id = avd_spec.remote_image[constants.BUILD_ID]
280        branch = avd_spec.remote_image[constants.BUILD_BRANCH]
281        num = avd_spec.num
282        emulator_build_id = avd_spec.emulator_build_id
283        gpu = avd_spec.gpu
284        serial_log_file = avd_spec.serial_log_file
285        autoconnect = avd_spec.autoconnect
286        report_internal_ip = avd_spec.report_internal_ip
287        client_adb_port = avd_spec.client_adb_port
288        boot_timeout_secs = avd_spec.boot_timeout_secs
289
290    # If emulator_build_id and emulator_branch is None, retrieve emulator
291    # build id from platform build emulator-info.txt artifact
292    # Example: require version-emulator=5292001
293    if not emulator_build_id and not emulator_branch:
294        logger.info("emulator_build_id not provided. "
295                    "Try to get %s from build %s/%s.", _EMULATOR_INFO_FILENAME,
296                    build_id, build_target)
297        emulator_build_id = _FetchBuildIdFromFile(cfg,
298                                                  build_target,
299                                                  build_id,
300                                                  _EMULATOR_INFO_FILENAME)
301
302    if not emulator_build_id:
303        raise errors.CommandArgError("Emulator build id not found "
304                                     "in %s" % _EMULATOR_INFO_FILENAME)
305
306    # If build_id and branch is None, retrieve build_id from
307    # emulator build android-info.txt artifact
308    # Example: version-sysimage-git_pi-dev-sdk_gphone_x86_64-userdebug=4833817
309    if not build_id and not branch:
310        build_id = _FetchBuildIdFromFile(cfg,
311                                         cfg.emulator_build_target,
312                                         emulator_build_id,
313                                         _SYSIMAGE_INFO_FILENAME)
314
315    if not build_id:
316        raise errors.CommandArgError("Emulator system image build id not found "
317                                     "in %s" % _SYSIMAGE_INFO_FILENAME)
318    logger.info(
319        "Creating a goldfish device in project %s, build_target: %s, "
320        "build_id: %s, emulator_bid: %s, kernel_build_id: %s, "
321        "kernel_branch: %s, kernel_build_target: %s, GPU: %s, num: %s, "
322        "serial_log_file: %s, "
323        "autoconnect: %s", cfg.project, build_target, build_id,
324        emulator_build_id, kernel_build_id, kernel_branch, kernel_build_target,
325        gpu, num, serial_log_file, autoconnect)
326
327    device_factory = GoldfishDeviceFactory(
328        cfg, build_target, build_id,
329        cfg.emulator_build_target,
330        emulator_build_id, gpu=gpu,
331        avd_spec=avd_spec, tags=tags,
332        branch=branch,
333        emulator_branch=emulator_branch,
334        kernel_build_id=kernel_build_id,
335        kernel_branch=kernel_branch,
336        kernel_build_target=kernel_build_target)
337
338    return common_operations.CreateDevices("create_gf", cfg, device_factory,
339                                           num, constants.TYPE_GF,
340                                           report_internal_ip, autoconnect,
341                                           serial_log_file, client_adb_port,
342                                           boot_timeout_secs)
343