xref: /aosp_15_r20/tools/acloud/internal/lib/android_build_client.py (revision 800a58d989c669b8eb8a71d8df53b1ba3d411444)
1 *800a58d9SAndroid Build Coastguard Worker#!/usr/bin/env python
2 *800a58d9SAndroid Build Coastguard Worker#
3 *800a58d9SAndroid Build Coastguard Worker# Copyright 2016 - The Android Open Source Project
4 *800a58d9SAndroid Build Coastguard Worker#
5 *800a58d9SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6 *800a58d9SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7 *800a58d9SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8 *800a58d9SAndroid Build Coastguard Worker#
9 *800a58d9SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10 *800a58d9SAndroid Build Coastguard Worker#
11 *800a58d9SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12 *800a58d9SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13 *800a58d9SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *800a58d9SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15 *800a58d9SAndroid Build Coastguard Worker# limitations under the License.
16 *800a58d9SAndroid Build Coastguard Worker
17 *800a58d9SAndroid Build Coastguard Worker"""A client that talks to Android Build APIs."""
18 *800a58d9SAndroid Build Coastguard Worker
19 *800a58d9SAndroid Build Coastguard Workerimport collections
20 *800a58d9SAndroid Build Coastguard Workerimport io
21 *800a58d9SAndroid Build Coastguard Workerimport json
22 *800a58d9SAndroid Build Coastguard Workerimport logging
23 *800a58d9SAndroid Build Coastguard Workerimport os
24 *800a58d9SAndroid Build Coastguard Workerimport ssl
25 *800a58d9SAndroid Build Coastguard Workerimport stat
26 *800a58d9SAndroid Build Coastguard Worker
27 *800a58d9SAndroid Build Coastguard Workerimport apiclient
28 *800a58d9SAndroid Build Coastguard Worker
29 *800a58d9SAndroid Build Coastguard Workerfrom acloud import errors
30 *800a58d9SAndroid Build Coastguard Workerfrom acloud.internal import constants
31 *800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import base_cloud_client
32 *800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import utils
33 *800a58d9SAndroid Build Coastguard Worker
34 *800a58d9SAndroid Build Coastguard Worker
35 *800a58d9SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__)
36 *800a58d9SAndroid Build Coastguard Worker
37 *800a58d9SAndroid Build Coastguard Worker# The BuildInfo namedtuple data structure.
38 *800a58d9SAndroid Build Coastguard Worker# It will be the data structure returned by GetBuildInfo method.
39 *800a58d9SAndroid Build Coastguard WorkerBuildInfo = collections.namedtuple("BuildInfo", [
40 *800a58d9SAndroid Build Coastguard Worker    "branch",  # The branch name string
41 *800a58d9SAndroid Build Coastguard Worker    "build_id",  # The build id string
42 *800a58d9SAndroid Build Coastguard Worker    "build_target",  # The build target string
43 *800a58d9SAndroid Build Coastguard Worker    "release_build_id"])  # The release build id string
44 *800a58d9SAndroid Build Coastguard Worker_DEFAULT_BRANCH = "aosp-master"
45 *800a58d9SAndroid Build Coastguard Worker
46 *800a58d9SAndroid Build Coastguard Worker
47 *800a58d9SAndroid Build Coastguard Workerclass AndroidBuildClient(base_cloud_client.BaseCloudApiClient):
48 *800a58d9SAndroid Build Coastguard Worker    """Client that manages Android Build."""
49 *800a58d9SAndroid Build Coastguard Worker
50 *800a58d9SAndroid Build Coastguard Worker    # API settings, used by BaseCloudApiClient.
51 *800a58d9SAndroid Build Coastguard Worker    API_NAME = "androidbuildinternal"
52 *800a58d9SAndroid Build Coastguard Worker    API_VERSION = "v2beta1"
53 *800a58d9SAndroid Build Coastguard Worker    SCOPE = "https://www.googleapis.com/auth/androidbuild.internal"
54 *800a58d9SAndroid Build Coastguard Worker
55 *800a58d9SAndroid Build Coastguard Worker    # other variables.
56 *800a58d9SAndroid Build Coastguard Worker    DEFAULT_RESOURCE_ID = "0"
57 *800a58d9SAndroid Build Coastguard Worker    # TODO(b/27269552): We should use "latest".
58 *800a58d9SAndroid Build Coastguard Worker    DEFAULT_ATTEMPT_ID = "0"
59 *800a58d9SAndroid Build Coastguard Worker    DEFAULT_CHUNK_SIZE = 20 * 1024 * 1024
60 *800a58d9SAndroid Build Coastguard Worker    NO_ACCESS_ERROR_PATTERN = "does not have storage.objects.create access"
61 *800a58d9SAndroid Build Coastguard Worker    # LKGB variables.
62 *800a58d9SAndroid Build Coastguard Worker    BUILD_STATUS_COMPLETE = "complete"
63 *800a58d9SAndroid Build Coastguard Worker    BUILD_TYPE_SUBMITTED = "submitted"
64 *800a58d9SAndroid Build Coastguard Worker    ONE_RESULT = 1
65 *800a58d9SAndroid Build Coastguard Worker    BUILD_SUCCESSFUL = True
66 *800a58d9SAndroid Build Coastguard Worker    LATEST = "latest"
67 *800a58d9SAndroid Build Coastguard Worker    # FETCH_CVD variables.
68 *800a58d9SAndroid Build Coastguard Worker    FETCHER_NAME = "fetch_cvd"
69 *800a58d9SAndroid Build Coastguard Worker    FETCHER_BUILD_TARGET = "aosp_cf_x86_64_phone-trunk_staging-userdebug"
70 *800a58d9SAndroid Build Coastguard Worker    FETCHER_BUILD_TARGET_ARM = "aosp_cf_arm64_only_phone-trunk_staging-userdebug"
71 *800a58d9SAndroid Build Coastguard Worker    # TODO(b/297085994): cvd fetch is migrating from AOSP to github artifacts, so
72 *800a58d9SAndroid Build Coastguard Worker    # temporary returning hardcoded values instead of LKGB
73 *800a58d9SAndroid Build Coastguard Worker    FETCHER_BUILD_ID = 11559438
74 *800a58d9SAndroid Build Coastguard Worker    FETCHER_BUILD_ID_ARM = 11559085
75 *800a58d9SAndroid Build Coastguard Worker    MAX_RETRY = 3
76 *800a58d9SAndroid Build Coastguard Worker    RETRY_SLEEP_SECS = 3
77 *800a58d9SAndroid Build Coastguard Worker
78 *800a58d9SAndroid Build Coastguard Worker    # Message constant
79 *800a58d9SAndroid Build Coastguard Worker    COPY_TO_MSG = ("build artifact (target: %s, build_id: %s, "
80 *800a58d9SAndroid Build Coastguard Worker                   "artifact: %s, attempt_id: %s) to "
81 *800a58d9SAndroid Build Coastguard Worker                   "google storage (bucket: %s, path: %s)")
82 *800a58d9SAndroid Build Coastguard Worker    # pylint: disable=invalid-name
83 *800a58d9SAndroid Build Coastguard Worker    def DownloadArtifact(self,
84 *800a58d9SAndroid Build Coastguard Worker                         build_target,
85 *800a58d9SAndroid Build Coastguard Worker                         build_id,
86 *800a58d9SAndroid Build Coastguard Worker                         resource_id,
87 *800a58d9SAndroid Build Coastguard Worker                         local_dest,
88 *800a58d9SAndroid Build Coastguard Worker                         attempt_id=None):
89 *800a58d9SAndroid Build Coastguard Worker        """Get Android build attempt information.
90 *800a58d9SAndroid Build Coastguard Worker
91 *800a58d9SAndroid Build Coastguard Worker        Args:
92 *800a58d9SAndroid Build Coastguard Worker            build_target: Target name, e.g. "aosp_cf_x86_64_phone-userdebug"
93 *800a58d9SAndroid Build Coastguard Worker            build_id: Build id, a string, e.g. "2263051", "P2804227"
94 *800a58d9SAndroid Build Coastguard Worker            resource_id: Id of the resource, e.g "avd-system.tar.gz".
95 *800a58d9SAndroid Build Coastguard Worker            local_dest: A local path where the artifact should be stored.
96 *800a58d9SAndroid Build Coastguard Worker                        e.g. "/tmp/avd-system.tar.gz"
97 *800a58d9SAndroid Build Coastguard Worker            attempt_id: String, attempt id, will default to DEFAULT_ATTEMPT_ID.
98 *800a58d9SAndroid Build Coastguard Worker        """
99 *800a58d9SAndroid Build Coastguard Worker        attempt_id = attempt_id or self.DEFAULT_ATTEMPT_ID
100 *800a58d9SAndroid Build Coastguard Worker        api = self.service.buildartifact().get_media(
101 *800a58d9SAndroid Build Coastguard Worker            buildId=build_id,
102 *800a58d9SAndroid Build Coastguard Worker            target=build_target,
103 *800a58d9SAndroid Build Coastguard Worker            attemptId=attempt_id,
104 *800a58d9SAndroid Build Coastguard Worker            resourceId=resource_id)
105 *800a58d9SAndroid Build Coastguard Worker        logger.info("Downloading artifact: target: %s, build_id: %s, "
106 *800a58d9SAndroid Build Coastguard Worker                    "resource_id: %s, dest: %s", build_target, build_id,
107 *800a58d9SAndroid Build Coastguard Worker                    resource_id, local_dest)
108 *800a58d9SAndroid Build Coastguard Worker        try:
109 *800a58d9SAndroid Build Coastguard Worker            with io.FileIO(local_dest, mode="wb") as fh:
110 *800a58d9SAndroid Build Coastguard Worker                downloader = apiclient.http.MediaIoBaseDownload(
111 *800a58d9SAndroid Build Coastguard Worker                    fh, api, chunksize=self.DEFAULT_CHUNK_SIZE)
112 *800a58d9SAndroid Build Coastguard Worker                done = False
113 *800a58d9SAndroid Build Coastguard Worker                while not done:
114 *800a58d9SAndroid Build Coastguard Worker                    _, done = downloader.next_chunk()
115 *800a58d9SAndroid Build Coastguard Worker            logger.info("Downloaded artifact: %s", local_dest)
116 *800a58d9SAndroid Build Coastguard Worker        except (OSError, apiclient.errors.HttpError) as e:
117 *800a58d9SAndroid Build Coastguard Worker            logger.error("Downloading artifact failed: %s", str(e))
118 *800a58d9SAndroid Build Coastguard Worker            raise errors.DriverError(str(e))
119 *800a58d9SAndroid Build Coastguard Worker
120 *800a58d9SAndroid Build Coastguard Worker    def DownloadFetchcvd(
121 *800a58d9SAndroid Build Coastguard Worker            self,
122 *800a58d9SAndroid Build Coastguard Worker            local_dest,
123 *800a58d9SAndroid Build Coastguard Worker            fetch_cvd_version,
124 *800a58d9SAndroid Build Coastguard Worker            is_arm_version=False):
125 *800a58d9SAndroid Build Coastguard Worker        """Get fetch_cvd from Android Build.
126 *800a58d9SAndroid Build Coastguard Worker
127 *800a58d9SAndroid Build Coastguard Worker        Args:
128 *800a58d9SAndroid Build Coastguard Worker            local_dest: A local path where the artifact should be stored.
129 *800a58d9SAndroid Build Coastguard Worker                        e.g. "/tmp/fetch_cvd"
130 *800a58d9SAndroid Build Coastguard Worker            fetch_cvd_version: String of fetch_cvd version.
131 *800a58d9SAndroid Build Coastguard Worker            is_arm_version: is ARM version fetch_cvd.
132 *800a58d9SAndroid Build Coastguard Worker        """
133 *800a58d9SAndroid Build Coastguard Worker        if fetch_cvd_version == constants.LKGB:
134 *800a58d9SAndroid Build Coastguard Worker            fetch_cvd_version = self.GetFetcherVersion(is_arm_version)
135 *800a58d9SAndroid Build Coastguard Worker        fetch_cvd_build_target = (
136 *800a58d9SAndroid Build Coastguard Worker            self.FETCHER_BUILD_TARGET_ARM if is_arm_version
137 *800a58d9SAndroid Build Coastguard Worker            else self.FETCHER_BUILD_TARGET)
138 *800a58d9SAndroid Build Coastguard Worker        try:
139 *800a58d9SAndroid Build Coastguard Worker            utils.RetryExceptionType(
140 *800a58d9SAndroid Build Coastguard Worker                exception_types=(ssl.SSLError, errors.DriverError),
141 *800a58d9SAndroid Build Coastguard Worker                max_retries=self.MAX_RETRY,
142 *800a58d9SAndroid Build Coastguard Worker                functor=self.DownloadArtifact,
143 *800a58d9SAndroid Build Coastguard Worker                sleep_multiplier=self.RETRY_SLEEP_SECS,
144 *800a58d9SAndroid Build Coastguard Worker                retry_backoff_factor=utils.DEFAULT_RETRY_BACKOFF_FACTOR,
145 *800a58d9SAndroid Build Coastguard Worker                build_target=fetch_cvd_build_target,
146 *800a58d9SAndroid Build Coastguard Worker                build_id=fetch_cvd_version,
147 *800a58d9SAndroid Build Coastguard Worker                resource_id=self.FETCHER_NAME,
148 *800a58d9SAndroid Build Coastguard Worker                local_dest=local_dest,
149 *800a58d9SAndroid Build Coastguard Worker                attempt_id=self.LATEST)
150 *800a58d9SAndroid Build Coastguard Worker        except Exception:
151 *800a58d9SAndroid Build Coastguard Worker            logger.debug("Download fetch_cvd with build id: %s",
152 *800a58d9SAndroid Build Coastguard Worker                         constants.FETCH_CVD_SECOND_VERSION)
153 *800a58d9SAndroid Build Coastguard Worker            utils.RetryExceptionType(
154 *800a58d9SAndroid Build Coastguard Worker                exception_types=(ssl.SSLError, errors.DriverError),
155 *800a58d9SAndroid Build Coastguard Worker                max_retries=self.MAX_RETRY,
156 *800a58d9SAndroid Build Coastguard Worker                functor=self.DownloadArtifact,
157 *800a58d9SAndroid Build Coastguard Worker                sleep_multiplier=self.RETRY_SLEEP_SECS,
158 *800a58d9SAndroid Build Coastguard Worker                retry_backoff_factor=utils.DEFAULT_RETRY_BACKOFF_FACTOR,
159 *800a58d9SAndroid Build Coastguard Worker                build_target=fetch_cvd_build_target,
160 *800a58d9SAndroid Build Coastguard Worker                build_id=constants.FETCH_CVD_SECOND_VERSION,
161 *800a58d9SAndroid Build Coastguard Worker                resource_id=self.FETCHER_NAME,
162 *800a58d9SAndroid Build Coastguard Worker                local_dest=local_dest,
163 *800a58d9SAndroid Build Coastguard Worker                attempt_id=self.LATEST)
164 *800a58d9SAndroid Build Coastguard Worker        fetch_cvd_stat = os.stat(local_dest)
165 *800a58d9SAndroid Build Coastguard Worker        os.chmod(local_dest, fetch_cvd_stat.st_mode | stat.S_IEXEC)
166 *800a58d9SAndroid Build Coastguard Worker
167 *800a58d9SAndroid Build Coastguard Worker    @staticmethod
168 *800a58d9SAndroid Build Coastguard Worker    def ProcessBuild(build_info, ignore_artifact=False):
169 *800a58d9SAndroid Build Coastguard Worker        """Create a Cuttlefish fetch_cvd build string.
170 *800a58d9SAndroid Build Coastguard Worker
171 *800a58d9SAndroid Build Coastguard Worker        Args:
172 *800a58d9SAndroid Build Coastguard Worker            build_info: The dictionary that contains build information.
173 *800a58d9SAndroid Build Coastguard Worker            ignore_artifact: Avoid adding artifact part to fetch_cvd build string
174 *800a58d9SAndroid Build Coastguard Worker
175 *800a58d9SAndroid Build Coastguard Worker        Returns:
176 *800a58d9SAndroid Build Coastguard Worker            A string, used in the fetch_cvd cmd or None if all args are None.
177 *800a58d9SAndroid Build Coastguard Worker        """
178 *800a58d9SAndroid Build Coastguard Worker        build_id = build_info.get(constants.BUILD_ID)
179 *800a58d9SAndroid Build Coastguard Worker        build_target = build_info.get(constants.BUILD_TARGET)
180 *800a58d9SAndroid Build Coastguard Worker        branch = build_info.get(constants.BUILD_BRANCH)
181 *800a58d9SAndroid Build Coastguard Worker        artifact = build_info.get(constants.BUILD_ARTIFACT)
182 *800a58d9SAndroid Build Coastguard Worker
183 *800a58d9SAndroid Build Coastguard Worker        result = build_id or branch
184 *800a58d9SAndroid Build Coastguard Worker        if build_target is not None:
185 *800a58d9SAndroid Build Coastguard Worker            result = result or _DEFAULT_BRANCH
186 *800a58d9SAndroid Build Coastguard Worker            result += "/" + build_target
187 *800a58d9SAndroid Build Coastguard Worker
188 *800a58d9SAndroid Build Coastguard Worker        if not ignore_artifact and artifact:
189 *800a58d9SAndroid Build Coastguard Worker            result += "{" + artifact + "}"
190 *800a58d9SAndroid Build Coastguard Worker
191 *800a58d9SAndroid Build Coastguard Worker        return result
192 *800a58d9SAndroid Build Coastguard Worker
193 *800a58d9SAndroid Build Coastguard Worker    def GetFetchBuildArgs(self, default_build_info, system_build_info,
194 *800a58d9SAndroid Build Coastguard Worker                          kernel_build_info, boot_build_info,
195 *800a58d9SAndroid Build Coastguard Worker                          bootloader_build_info, android_efi_loader_build_info,
196 *800a58d9SAndroid Build Coastguard Worker                          ota_build_info, host_package_build_info):
197 *800a58d9SAndroid Build Coastguard Worker        """Get args from build information for fetch_cvd.
198 *800a58d9SAndroid Build Coastguard Worker
199 *800a58d9SAndroid Build Coastguard Worker        Each build_info is a dictionary that contains 3 items, for example,
200 *800a58d9SAndroid Build Coastguard Worker        {
201 *800a58d9SAndroid Build Coastguard Worker            constants.BUILD_ID: "2263051",
202 *800a58d9SAndroid Build Coastguard Worker            constants.BUILD_TARGET: "aosp_cf_x86_64_phone-userdebug",
203 *800a58d9SAndroid Build Coastguard Worker            constants.BUILD_BRANCH: "aosp-master",
204 *800a58d9SAndroid Build Coastguard Worker        }
205 *800a58d9SAndroid Build Coastguard Worker
206 *800a58d9SAndroid Build Coastguard Worker        Args:
207 *800a58d9SAndroid Build Coastguard Worker            default_build_info: The build that provides full cuttlefish images.
208 *800a58d9SAndroid Build Coastguard Worker            system_build_info: The build that provides the system image.
209 *800a58d9SAndroid Build Coastguard Worker            kernel_build_info: The build that provides the kernel.
210 *800a58d9SAndroid Build Coastguard Worker            boot_build_info: The build that provides the boot image. This
211 *800a58d9SAndroid Build Coastguard Worker                             dictionary may contain an additional key
212 *800a58d9SAndroid Build Coastguard Worker                             constants.BUILD_ARTIFACT which is mapped to the
213 *800a58d9SAndroid Build Coastguard Worker                             boot image name.
214 *800a58d9SAndroid Build Coastguard Worker            bootloader_build_info: The build that provides the bootloader.
215 *800a58d9SAndroid Build Coastguard Worker            android_efi_loader_build_info: The build that provides the Android EFI loader.
216 *800a58d9SAndroid Build Coastguard Worker            ota_build_info: The build that provides the OTA tools.
217 *800a58d9SAndroid Build Coastguard Worker            host_package_build_info: The build that provides the host package.
218 *800a58d9SAndroid Build Coastguard Worker
219 *800a58d9SAndroid Build Coastguard Worker        Returns:
220 *800a58d9SAndroid Build Coastguard Worker            List of string args for fetch_cvd.
221 *800a58d9SAndroid Build Coastguard Worker        """
222 *800a58d9SAndroid Build Coastguard Worker        fetch_cvd_args = []
223 *800a58d9SAndroid Build Coastguard Worker
224 *800a58d9SAndroid Build Coastguard Worker        default_build = self.ProcessBuild(default_build_info)
225 *800a58d9SAndroid Build Coastguard Worker        if default_build:
226 *800a58d9SAndroid Build Coastguard Worker            fetch_cvd_args.append(f"-default_build={default_build}")
227 *800a58d9SAndroid Build Coastguard Worker        system_build = self.ProcessBuild(system_build_info)
228 *800a58d9SAndroid Build Coastguard Worker        if system_build:
229 *800a58d9SAndroid Build Coastguard Worker            fetch_cvd_args.append(f"-system_build={system_build}")
230 *800a58d9SAndroid Build Coastguard Worker        bootloader_build = self.ProcessBuild(bootloader_build_info)
231 *800a58d9SAndroid Build Coastguard Worker        if bootloader_build:
232 *800a58d9SAndroid Build Coastguard Worker            fetch_cvd_args.append(f"-bootloader_build={bootloader_build}")
233 *800a58d9SAndroid Build Coastguard Worker        android_efi_loader_build = self.ProcessBuild(android_efi_loader_build_info)
234 *800a58d9SAndroid Build Coastguard Worker        if android_efi_loader_build:
235 *800a58d9SAndroid Build Coastguard Worker            fetch_cvd_args.append(f"-android_efi_loader_build {android_efi_loader_build}")
236 *800a58d9SAndroid Build Coastguard Worker        kernel_build = self.GetKernelBuild(kernel_build_info)
237 *800a58d9SAndroid Build Coastguard Worker        if kernel_build:
238 *800a58d9SAndroid Build Coastguard Worker            fetch_cvd_args.append(f"-kernel_build={kernel_build}")
239 *800a58d9SAndroid Build Coastguard Worker        boot_build = self.ProcessBuild(boot_build_info, ignore_artifact=True)
240 *800a58d9SAndroid Build Coastguard Worker        if boot_build:
241 *800a58d9SAndroid Build Coastguard Worker            fetch_cvd_args.append(f"-boot_build={boot_build}")
242 *800a58d9SAndroid Build Coastguard Worker            boot_artifact = boot_build_info.get(constants.BUILD_ARTIFACT)
243 *800a58d9SAndroid Build Coastguard Worker            if boot_artifact:
244 *800a58d9SAndroid Build Coastguard Worker                fetch_cvd_args.append(f"-boot_artifact={boot_artifact}")
245 *800a58d9SAndroid Build Coastguard Worker        ota_build = self.ProcessBuild(ota_build_info)
246 *800a58d9SAndroid Build Coastguard Worker        if ota_build:
247 *800a58d9SAndroid Build Coastguard Worker            fetch_cvd_args.append(f"-otatools_build={ota_build}")
248 *800a58d9SAndroid Build Coastguard Worker        host_package_build = self.ProcessBuild(host_package_build_info)
249 *800a58d9SAndroid Build Coastguard Worker        if host_package_build:
250 *800a58d9SAndroid Build Coastguard Worker            fetch_cvd_args.append(f"-host_package_build={host_package_build}")
251 *800a58d9SAndroid Build Coastguard Worker
252 *800a58d9SAndroid Build Coastguard Worker        return fetch_cvd_args
253 *800a58d9SAndroid Build Coastguard Worker
254 *800a58d9SAndroid Build Coastguard Worker    def GetFetcherVersion(self, is_arm_version=False):
255 *800a58d9SAndroid Build Coastguard Worker        """Get fetch_cvd build id from LKGB.
256 *800a58d9SAndroid Build Coastguard Worker
257 *800a58d9SAndroid Build Coastguard Worker        Returns:
258 *800a58d9SAndroid Build Coastguard Worker            The build id of fetch_cvd.
259 *800a58d9SAndroid Build Coastguard Worker        """
260 *800a58d9SAndroid Build Coastguard Worker        # TODO(b/297085994): currently returning hardcoded values
261 *800a58d9SAndroid Build Coastguard Worker        # For more information, please check the BUILD_ID constant definition
262 *800a58d9SAndroid Build Coastguard Worker        # comment section
263 *800a58d9SAndroid Build Coastguard Worker        return self.FETCHER_BUILD_ID_ARM if is_arm_version else self.FETCHER_BUILD_ID
264 *800a58d9SAndroid Build Coastguard Worker
265 *800a58d9SAndroid Build Coastguard Worker    @staticmethod
266 *800a58d9SAndroid Build Coastguard Worker    # pylint: disable=broad-except
267 *800a58d9SAndroid Build Coastguard Worker    def GetFetchCertArg(certification_file):
268 *800a58d9SAndroid Build Coastguard Worker        """Get cert arg from certification file for fetch_cvd.
269 *800a58d9SAndroid Build Coastguard Worker
270 *800a58d9SAndroid Build Coastguard Worker        Parse the certification file to get access token of the latest
271 *800a58d9SAndroid Build Coastguard Worker        credential data and pass it to fetch_cvd command.
272 *800a58d9SAndroid Build Coastguard Worker        Example of certification file:
273 *800a58d9SAndroid Build Coastguard Worker        {
274 *800a58d9SAndroid Build Coastguard Worker          "data": [
275 *800a58d9SAndroid Build Coastguard Worker          {
276 *800a58d9SAndroid Build Coastguard Worker            "credential": {
277 *800a58d9SAndroid Build Coastguard Worker              "_class": "OAuth2Credentials",
278 *800a58d9SAndroid Build Coastguard Worker              "_module": "oauth2client.client",
279 *800a58d9SAndroid Build Coastguard Worker              "access_token": "token_strings",
280 *800a58d9SAndroid Build Coastguard Worker              "client_id": "179485041932",
281 *800a58d9SAndroid Build Coastguard Worker            }
282 *800a58d9SAndroid Build Coastguard Worker          }]
283 *800a58d9SAndroid Build Coastguard Worker        }
284 *800a58d9SAndroid Build Coastguard Worker
285 *800a58d9SAndroid Build Coastguard Worker
286 *800a58d9SAndroid Build Coastguard Worker        Args:
287 *800a58d9SAndroid Build Coastguard Worker            certification_file: String of certification file path.
288 *800a58d9SAndroid Build Coastguard Worker
289 *800a58d9SAndroid Build Coastguard Worker        Returns:
290 *800a58d9SAndroid Build Coastguard Worker            String of certificate arg for fetch_cvd. If there is no
291 *800a58d9SAndroid Build Coastguard Worker            certification file, return empty string for aosp branch.
292 *800a58d9SAndroid Build Coastguard Worker        """
293 *800a58d9SAndroid Build Coastguard Worker        cert_arg = ""
294 *800a58d9SAndroid Build Coastguard Worker        try:
295 *800a58d9SAndroid Build Coastguard Worker            with open(certification_file) as cert_file:
296 *800a58d9SAndroid Build Coastguard Worker                auth_token = json.load(cert_file).get("data")[-1].get(
297 *800a58d9SAndroid Build Coastguard Worker                    "credential").get("access_token")
298 *800a58d9SAndroid Build Coastguard Worker                if auth_token:
299 *800a58d9SAndroid Build Coastguard Worker                    cert_arg = f"-credential_source={auth_token}"
300 *800a58d9SAndroid Build Coastguard Worker        except Exception as e:
301 *800a58d9SAndroid Build Coastguard Worker            utils.PrintColorString(
302 *800a58d9SAndroid Build Coastguard Worker                f"Fail to open the certification file "
303 *800a58d9SAndroid Build Coastguard Worker                f"({certification_file}): {e}",
304 *800a58d9SAndroid Build Coastguard Worker                utils.TextColors.WARNING)
305 *800a58d9SAndroid Build Coastguard Worker        return cert_arg
306 *800a58d9SAndroid Build Coastguard Worker
307 *800a58d9SAndroid Build Coastguard Worker    def GetKernelBuild(self, kernel_build_info):
308 *800a58d9SAndroid Build Coastguard Worker        """Get kernel build args for fetch_cvd.
309 *800a58d9SAndroid Build Coastguard Worker
310 *800a58d9SAndroid Build Coastguard Worker        Args:
311 *800a58d9SAndroid Build Coastguard Worker            kernel_build_info: The dictionary that contains build information.
312 *800a58d9SAndroid Build Coastguard Worker
313 *800a58d9SAndroid Build Coastguard Worker        Returns:
314 *800a58d9SAndroid Build Coastguard Worker            String of kernel build args for fetch_cvd.
315 *800a58d9SAndroid Build Coastguard Worker            If no kernel build then return None.
316 *800a58d9SAndroid Build Coastguard Worker        """
317 *800a58d9SAndroid Build Coastguard Worker        # kernel_target have default value "kernel". If user provide kernel_build_id
318 *800a58d9SAndroid Build Coastguard Worker        # or kernel_branch, then start to process kernel image.
319 *800a58d9SAndroid Build Coastguard Worker        if (kernel_build_info.get(constants.BUILD_ID) or
320 *800a58d9SAndroid Build Coastguard Worker                kernel_build_info.get(constants.BUILD_BRANCH)):
321 *800a58d9SAndroid Build Coastguard Worker            return self.ProcessBuild(kernel_build_info)
322 *800a58d9SAndroid Build Coastguard Worker        return None
323 *800a58d9SAndroid Build Coastguard Worker
324 *800a58d9SAndroid Build Coastguard Worker    def CopyTo(self,
325 *800a58d9SAndroid Build Coastguard Worker               build_target,
326 *800a58d9SAndroid Build Coastguard Worker               build_id,
327 *800a58d9SAndroid Build Coastguard Worker               artifact_name,
328 *800a58d9SAndroid Build Coastguard Worker               destination_bucket,
329 *800a58d9SAndroid Build Coastguard Worker               destination_path,
330 *800a58d9SAndroid Build Coastguard Worker               attempt_id=None):
331 *800a58d9SAndroid Build Coastguard Worker        """Copy an Android Build artifact to a storage bucket.
332 *800a58d9SAndroid Build Coastguard Worker
333 *800a58d9SAndroid Build Coastguard Worker        Args:
334 *800a58d9SAndroid Build Coastguard Worker            build_target: Target name, e.g. "aosp_cf_x86_64_phone-userdebug"
335 *800a58d9SAndroid Build Coastguard Worker            build_id: Build id, a string, e.g. "2263051", "P2804227"
336 *800a58d9SAndroid Build Coastguard Worker            artifact_name: Name of the artifact, e.g "avd-system.tar.gz".
337 *800a58d9SAndroid Build Coastguard Worker            destination_bucket: String, a google storage bucket name.
338 *800a58d9SAndroid Build Coastguard Worker            destination_path: String, "path/inside/bucket"
339 *800a58d9SAndroid Build Coastguard Worker            attempt_id: String, attempt id, will default to DEFAULT_ATTEMPT_ID.
340 *800a58d9SAndroid Build Coastguard Worker        """
341 *800a58d9SAndroid Build Coastguard Worker        attempt_id = attempt_id or self.DEFAULT_ATTEMPT_ID
342 *800a58d9SAndroid Build Coastguard Worker        copy_msg = "Copying %s" % self.COPY_TO_MSG
343 *800a58d9SAndroid Build Coastguard Worker        logger.info(copy_msg, build_target, build_id, artifact_name,
344 *800a58d9SAndroid Build Coastguard Worker                    attempt_id, destination_bucket, destination_path)
345 *800a58d9SAndroid Build Coastguard Worker        api = self.service.buildartifact().copyTo(
346 *800a58d9SAndroid Build Coastguard Worker            buildId=build_id,
347 *800a58d9SAndroid Build Coastguard Worker            target=build_target,
348 *800a58d9SAndroid Build Coastguard Worker            attemptId=attempt_id,
349 *800a58d9SAndroid Build Coastguard Worker            artifactName=artifact_name,
350 *800a58d9SAndroid Build Coastguard Worker            destinationBucket=destination_bucket,
351 *800a58d9SAndroid Build Coastguard Worker            destinationPath=destination_path)
352 *800a58d9SAndroid Build Coastguard Worker        try:
353 *800a58d9SAndroid Build Coastguard Worker            self.Execute(api)
354 *800a58d9SAndroid Build Coastguard Worker            finish_msg = "Finished copying %s" % self.COPY_TO_MSG
355 *800a58d9SAndroid Build Coastguard Worker            logger.info(finish_msg, build_target, build_id, artifact_name,
356 *800a58d9SAndroid Build Coastguard Worker                        attempt_id, destination_bucket, destination_path)
357 *800a58d9SAndroid Build Coastguard Worker        except errors.HttpError as e:
358 *800a58d9SAndroid Build Coastguard Worker            if e.code == 503:
359 *800a58d9SAndroid Build Coastguard Worker                if self.NO_ACCESS_ERROR_PATTERN in str(e):
360 *800a58d9SAndroid Build Coastguard Worker                    error_msg = "Please grant android build team's service account "
361 *800a58d9SAndroid Build Coastguard Worker                    error_msg += "write access to bucket %s. Original error: %s"
362 *800a58d9SAndroid Build Coastguard Worker                    error_msg %= (destination_bucket, str(e))
363 *800a58d9SAndroid Build Coastguard Worker                    raise errors.HttpError(e.code, message=error_msg)
364 *800a58d9SAndroid Build Coastguard Worker            raise
365 *800a58d9SAndroid Build Coastguard Worker
366 *800a58d9SAndroid Build Coastguard Worker    def GetBranch(self, build_target, build_id):
367 *800a58d9SAndroid Build Coastguard Worker        """Derives branch name.
368 *800a58d9SAndroid Build Coastguard Worker
369 *800a58d9SAndroid Build Coastguard Worker        Args:
370 *800a58d9SAndroid Build Coastguard Worker            build_target: Target name, e.g. "aosp_cf_x86_64_phone-userdebug"
371 *800a58d9SAndroid Build Coastguard Worker            build_id: Build ID, a string, e.g. "2263051", "P2804227"
372 *800a58d9SAndroid Build Coastguard Worker
373 *800a58d9SAndroid Build Coastguard Worker        Returns:
374 *800a58d9SAndroid Build Coastguard Worker            A string, the name of the branch
375 *800a58d9SAndroid Build Coastguard Worker        """
376 *800a58d9SAndroid Build Coastguard Worker        api = self.service.build().get(buildId=build_id, target=build_target)
377 *800a58d9SAndroid Build Coastguard Worker        build = self.Execute(api)
378 *800a58d9SAndroid Build Coastguard Worker        return build.get("branch", "")
379 *800a58d9SAndroid Build Coastguard Worker
380 *800a58d9SAndroid Build Coastguard Worker    def GetLKGB(self, build_target, build_branch):
381 *800a58d9SAndroid Build Coastguard Worker        """Get latest successful build id.
382 *800a58d9SAndroid Build Coastguard Worker
383 *800a58d9SAndroid Build Coastguard Worker        From branch and target, we can use api to query latest successful build id.
384 *800a58d9SAndroid Build Coastguard Worker        e.g. {u'nextPageToken':..., u'builds': [{u'completionTimestamp':u'1534157869286',
385 *800a58d9SAndroid Build Coastguard Worker        ... u'buildId': u'4949805', u'machineName'...}]}
386 *800a58d9SAndroid Build Coastguard Worker
387 *800a58d9SAndroid Build Coastguard Worker        Args:
388 *800a58d9SAndroid Build Coastguard Worker            build_target: String, target name, e.g. "aosp_cf_x86_64_phone-userdebug"
389 *800a58d9SAndroid Build Coastguard Worker            build_branch: String, git branch name, e.g. "aosp-master"
390 *800a58d9SAndroid Build Coastguard Worker
391 *800a58d9SAndroid Build Coastguard Worker        Returns:
392 *800a58d9SAndroid Build Coastguard Worker            A string, string of build id number.
393 *800a58d9SAndroid Build Coastguard Worker
394 *800a58d9SAndroid Build Coastguard Worker        Raises:
395 *800a58d9SAndroid Build Coastguard Worker            errors.CreateError: Can't get build id.
396 *800a58d9SAndroid Build Coastguard Worker        """
397 *800a58d9SAndroid Build Coastguard Worker        api = self.service.build().list(
398 *800a58d9SAndroid Build Coastguard Worker            branch=build_branch,
399 *800a58d9SAndroid Build Coastguard Worker            target=build_target,
400 *800a58d9SAndroid Build Coastguard Worker            buildAttemptStatus=self.BUILD_STATUS_COMPLETE,
401 *800a58d9SAndroid Build Coastguard Worker            buildType=self.BUILD_TYPE_SUBMITTED,
402 *800a58d9SAndroid Build Coastguard Worker            maxResults=self.ONE_RESULT,
403 *800a58d9SAndroid Build Coastguard Worker            successful=self.BUILD_SUCCESSFUL)
404 *800a58d9SAndroid Build Coastguard Worker        build = self.Execute(api)
405 *800a58d9SAndroid Build Coastguard Worker        logger.info("GetLKGB build API response: %s", build)
406 *800a58d9SAndroid Build Coastguard Worker        if build:
407 *800a58d9SAndroid Build Coastguard Worker            return str(build.get("builds")[0].get("buildId"))
408 *800a58d9SAndroid Build Coastguard Worker        raise errors.GetBuildIDError(
409 *800a58d9SAndroid Build Coastguard Worker            "No available good builds for branch: %s target: %s"
410 *800a58d9SAndroid Build Coastguard Worker            % (build_branch, build_target)
411 *800a58d9SAndroid Build Coastguard Worker        )
412 *800a58d9SAndroid Build Coastguard Worker
413 *800a58d9SAndroid Build Coastguard Worker    def GetBuildInfo(self, build_target, build_id, branch):
414 *800a58d9SAndroid Build Coastguard Worker        """Get build info namedtuple.
415 *800a58d9SAndroid Build Coastguard Worker
416 *800a58d9SAndroid Build Coastguard Worker        Args:
417 *800a58d9SAndroid Build Coastguard Worker          build_target: Target name.
418 *800a58d9SAndroid Build Coastguard Worker          build_id: Build id, a string or None, e.g. "2263051", "P2804227"
419 *800a58d9SAndroid Build Coastguard Worker                    If None or latest, the last green build id will be
420 *800a58d9SAndroid Build Coastguard Worker                    returned.
421 *800a58d9SAndroid Build Coastguard Worker          branch: Branch name, a string or None, e.g. git_master. If None, the
422 *800a58d9SAndroid Build Coastguard Worker                  returned branch will be searched by given build_id.
423 *800a58d9SAndroid Build Coastguard Worker
424 *800a58d9SAndroid Build Coastguard Worker        Returns:
425 *800a58d9SAndroid Build Coastguard Worker          A build info namedtuple with keys build_target, build_id, branch and
426 *800a58d9SAndroid Build Coastguard Worker          gcs_bucket_build_id
427 *800a58d9SAndroid Build Coastguard Worker        """
428 *800a58d9SAndroid Build Coastguard Worker        if build_id and build_id != self.LATEST:
429 *800a58d9SAndroid Build Coastguard Worker            # Get build from build_id and build_target
430 *800a58d9SAndroid Build Coastguard Worker            api = self.service.build().get(buildId=build_id,
431 *800a58d9SAndroid Build Coastguard Worker                                           target=build_target)
432 *800a58d9SAndroid Build Coastguard Worker            build = self.Execute(api) or {}
433 *800a58d9SAndroid Build Coastguard Worker        elif branch:
434 *800a58d9SAndroid Build Coastguard Worker            # Get last green build in the branch
435 *800a58d9SAndroid Build Coastguard Worker            api = self.service.build().list(
436 *800a58d9SAndroid Build Coastguard Worker                branch=branch,
437 *800a58d9SAndroid Build Coastguard Worker                target=build_target,
438 *800a58d9SAndroid Build Coastguard Worker                successful=True,
439 *800a58d9SAndroid Build Coastguard Worker                maxResults=1,
440 *800a58d9SAndroid Build Coastguard Worker                buildType="submitted")
441 *800a58d9SAndroid Build Coastguard Worker            builds = self.Execute(api).get("builds", [])
442 *800a58d9SAndroid Build Coastguard Worker            build = builds[0] if builds else {}
443 *800a58d9SAndroid Build Coastguard Worker        else:
444 *800a58d9SAndroid Build Coastguard Worker            build = {}
445 *800a58d9SAndroid Build Coastguard Worker
446 *800a58d9SAndroid Build Coastguard Worker        build_id = build.get("buildId")
447 *800a58d9SAndroid Build Coastguard Worker        build_target = build_target if build_id else None
448 *800a58d9SAndroid Build Coastguard Worker        return BuildInfo(build.get("branch"), build_id, build_target,
449 *800a58d9SAndroid Build Coastguard Worker                         build.get("releaseCandidateName"))
450