blob: 984f9ace65172045cf993f5d027c8a28f7052f1d [file] [log] [blame]
Evan Hernandezf388cbf2019-04-01 11:15:23 -06001# -*- coding: utf-8 -*-
2# Copyright 2019 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Implements ArtifactService."""
7
8from __future__ import print_function
9
10import os
11
Alex Klein231d2da2019-07-22 16:44:45 -060012from chromite.api import controller
Alex Klein076841b2019-08-29 15:19:39 -060013from chromite.api import faux
Alex Klein2b236722019-06-19 15:44:26 -060014from chromite.api import validate
Alex Klein238d8862019-05-07 11:32:46 -060015from chromite.api.controller import controller_util
Tiancong Wang24a3df72019-08-20 15:48:51 -070016from chromite.api.gen.chromite.api import toolchain_pb2
Alex Klein2275d692019-04-23 16:04:12 -060017from chromite.lib import chroot_lib
Evan Hernandezf388cbf2019-04-01 11:15:23 -060018from chromite.lib import constants
19from chromite.lib import cros_build_lib
Evan Hernandezde445982019-04-22 13:42:34 -060020from chromite.lib import cros_logging as logging
Alex Klein2275d692019-04-23 16:04:12 -060021from chromite.lib import sysroot_lib
22from chromite.service import artifacts
Evan Hernandezf388cbf2019-04-01 11:15:23 -060023
24
LaMont Jones0f5171b2021-01-29 12:28:56 -070025def _GetResponse(_input_proto, _output_proto, _config):
26 """Currently bundles nothing."""
27 # TODO(crbug/1034529): As methods migrate, begin populating them based on what
28 # input_proto has defined.
29
30
31@faux.success(_GetResponse)
32@faux.empty_error
33@validate.exists('result_path.path.path')
34@validate.validation_complete
35def Get(_input_proto, _output_proto, _config):
36 """Get all artifacts.
37
38 Get all artifacts for the build.
39
40 Note: crbug/1034529 introduces this method as a noop. As the individual
41 artifact_type bundlers are added here, they *must* stop uploading it via the
42 individual bundler function.
43
44 Args:
45 _input_proto (GetRequest): The input proto.
46 _output_proto (GetResponse): The output proto.
47 _config (api_config.ApiConfig): The API call config.
48 """
49 return controller.RETURN_CODE_SUCCESS
50
51
Evan Hernandez9f125ac2019-04-08 17:18:47 -060052def _GetImageDir(build_root, target):
53 """Return path containing images for the given build target.
54
Alex Kleine2612a02019-04-18 13:51:06 -060055 TODO(saklein) Expand image_lib.GetLatestImageLink to support this use case.
56
Evan Hernandez9f125ac2019-04-08 17:18:47 -060057 Args:
58 build_root (str): Path to checkout where build occurs.
59 target (str): Name of the build target.
60
61 Returns:
Alex Kleind2bf1462019-10-24 16:37:04 -060062 Path to the latest directory containing target images or None.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060063 """
64 image_dir = os.path.join(build_root, 'src/build/images', target, 'latest')
65 if not os.path.exists(image_dir):
Alex Kleind2bf1462019-10-24 16:37:04 -060066 logging.warning('Expected to find image output for target %s at %s, but '
67 'path does not exist', target, image_dir)
68 return None
69
Evan Hernandez9f125ac2019-04-08 17:18:47 -060070 return image_dir
71
72
Michael Mortensen2d6a2402019-11-26 13:40:40 -070073def _BundleImageArchivesResponse(input_proto, output_proto, _config):
74 """Add artifact paths to a successful response."""
75 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
76 'path0.tar.xz')
77 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
78 'path1.tar.xz')
79
80
81@faux.success(_BundleImageArchivesResponse)
82@faux.empty_error
Alex Kleind91e95a2019-09-17 10:39:02 -060083@validate.require('build_target.name')
84@validate.exists('output_dir')
85@validate.validation_complete
86def BundleImageArchives(input_proto, output_proto, _config):
87 """Create a .tar.xz archive for each image that has been created."""
88 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
89 output_dir = input_proto.output_dir
90 image_dir = _GetImageDir(constants.SOURCE_ROOT, build_target.name)
Alex Kleind2bf1462019-10-24 16:37:04 -060091 if image_dir is None:
92 return
Alex Kleind91e95a2019-09-17 10:39:02 -060093
94 archives = artifacts.ArchiveImages(image_dir, output_dir)
95
96 for archive in archives:
97 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
98
99
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700100def _BundleImageZipResponse(input_proto, output_proto, _config):
101 """Add artifact zip files to a successful response."""
102 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
103 'image.zip')
104
105
106@faux.success(_BundleImageZipResponse)
107@faux.empty_error
Michael Mortensen01910922019-07-24 14:48:10 -0600108@validate.require('build_target.name', 'output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600109@validate.exists('output_dir')
110@validate.validation_complete
111def BundleImageZip(input_proto, output_proto, _config):
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600112 """Bundle image.zip.
113
114 Args:
115 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600116 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600117 _config (api_config.ApiConfig): The API call config.
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600118 """
119 target = input_proto.build_target.name
120 output_dir = input_proto.output_dir
121 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
Alex Kleind2bf1462019-10-24 16:37:04 -0600122 if image_dir is None:
123 return None
Alex Klein231d2da2019-07-22 16:44:45 -0600124
Michael Mortensen01910922019-07-24 14:48:10 -0600125 archive = artifacts.BundleImageZip(output_dir, image_dir)
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600126 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
127
128
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700129def _BundleTestUpdatePayloadsResponse(input_proto, output_proto, _config):
130 """Add test payload files to a successful response."""
131 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
132 'payload1.bin')
133
134
135@faux.success(_BundleTestUpdatePayloadsResponse)
136@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600137@validate.require('build_target.name', 'output_dir')
138@validate.exists('output_dir')
139@validate.validation_complete
140def BundleTestUpdatePayloads(input_proto, output_proto, _config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600141 """Generate minimal update payloads for the build target for testing.
142
143 Args:
144 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600145 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600146 _config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600147 """
148 target = input_proto.build_target.name
149 output_dir = input_proto.output_dir
150 build_root = constants.SOURCE_ROOT
151
152 # Use the first available image to create the update payload.
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600153 img_dir = _GetImageDir(build_root, target)
Alex Kleind2bf1462019-10-24 16:37:04 -0600154 if img_dir is None:
155 return None
156
Alex Kleincb541e82019-06-26 15:06:11 -0600157 img_types = [constants.IMAGE_TYPE_TEST, constants.IMAGE_TYPE_DEV,
158 constants.IMAGE_TYPE_BASE]
159 img_names = [constants.IMAGE_TYPE_TO_NAME[t] for t in img_types]
Mike Frysinger66ce4132019-07-17 22:52:52 -0400160 img_paths = [os.path.join(img_dir, x) for x in img_names]
Mike Frysingera552be42018-08-17 14:39:32 -0400161 valid_images = [x for x in img_paths if os.path.exists(x)]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600162
Alex Kleincb541e82019-06-26 15:06:11 -0600163 if not valid_images:
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600164 cros_build_lib.Die(
165 'Expected to find an image of type among %r for target "%s" '
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600166 'at path %s.', img_types, target, img_dir)
Alex Kleincb541e82019-06-26 15:06:11 -0600167 image = valid_images[0]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600168
Alex Kleincb541e82019-06-26 15:06:11 -0600169 payloads = artifacts.BundleTestUpdatePayloads(image, output_dir)
170 for payload in payloads:
171 output_proto.artifacts.add().path = payload
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600172
173
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700174def _BundleAutotestFilesResponse(input_proto, output_proto, _config):
175 """Add test autotest files to a successful response."""
176 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
177 'autotest-a.tar.gz')
178
179
180@faux.success(_BundleAutotestFilesResponse)
181@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600182@validate.require('output_dir')
183@validate.exists('output_dir')
184def BundleAutotestFiles(input_proto, output_proto, config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600185 """Tar the autotest files for a build target.
186
187 Args:
188 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600189 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600190 config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600191 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600192 output_dir = input_proto.output_dir
Alex Klein238d8862019-05-07 11:32:46 -0600193 target = input_proto.build_target.name
Alex Kleine21a0952019-08-23 16:08:16 -0600194 chroot = controller_util.ParseChroot(input_proto.chroot)
195
Alex Klein238d8862019-05-07 11:32:46 -0600196 if target:
Alex Kleine21a0952019-08-23 16:08:16 -0600197 sysroot_path = os.path.join('/build', target)
Alex Klein238d8862019-05-07 11:32:46 -0600198 else:
199 # New style call, use chroot and sysroot.
Alex Klein238d8862019-05-07 11:32:46 -0600200 sysroot_path = input_proto.sysroot.path
201 if not sysroot_path:
202 cros_build_lib.Die('sysroot.path is required.')
203
Alex Kleine21a0952019-08-23 16:08:16 -0600204 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Klein238d8862019-05-07 11:32:46 -0600205
Alex Klein231d2da2019-07-22 16:44:45 -0600206 # TODO(saklein): Switch to the validate_only decorator when legacy handling
207 # is removed.
208 if config.validate_only:
209 return controller.RETURN_CODE_VALID_INPUT
210
Alex Kleine21a0952019-08-23 16:08:16 -0600211 if not sysroot.Exists(chroot=chroot):
Alex Klein238d8862019-05-07 11:32:46 -0600212 cros_build_lib.Die('Sysroot path must exist: %s', sysroot.path)
213
214 try:
215 # Note that this returns the full path to *multiple* tarballs.
Alex Kleine21a0952019-08-23 16:08:16 -0600216 archives = artifacts.BundleAutotestFiles(chroot, sysroot, output_dir)
Alex Klein238d8862019-05-07 11:32:46 -0600217 except artifacts.Error as e:
Alex Klein03890312020-06-30 09:59:50 -0600218 logging.warning(e)
219 return
Alex Klein238d8862019-05-07 11:32:46 -0600220
221 for archive in archives.values():
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600222 output_proto.artifacts.add().path = archive
223
224
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700225def _BundleTastFilesResponse(input_proto, output_proto, _config):
226 """Add test tast files to a successful response."""
227 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
228 'tast_bundles.tar.gz')
229
230
231@faux.success(_BundleTastFilesResponse)
232@faux.empty_error
Alex Kleinb9d810b2019-07-01 12:38:02 -0600233@validate.require('output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600234@validate.exists('output_dir')
235def BundleTastFiles(input_proto, output_proto, config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600236 """Tar the tast files for a build target.
237
238 Args:
239 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600240 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600241 config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600242 """
243 target = input_proto.build_target.name
244 output_dir = input_proto.output_dir
245 build_root = constants.SOURCE_ROOT
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600246
Alex Kleinb9d810b2019-07-01 12:38:02 -0600247 chroot = controller_util.ParseChroot(input_proto.chroot)
248 sysroot_path = input_proto.sysroot.path
249
250 # TODO(saklein) Cleanup legacy handling after it has been switched over.
251 if target:
252 # Legacy handling.
Alex Klein171da612019-08-06 14:00:42 -0600253 chroot = chroot_lib.Chroot(path=os.path.join(build_root, 'chroot'))
Alex Kleinb9d810b2019-07-01 12:38:02 -0600254 sysroot_path = os.path.join('/build', target)
255
256 # New handling - chroot & sysroot based.
257 # TODO(saklein) Switch this to the require decorator when legacy is removed.
258 if not sysroot_path:
259 cros_build_lib.Die('sysroot.path is required.')
260
Alex Klein231d2da2019-07-22 16:44:45 -0600261 # TODO(saklein): Switch to the validation_complete decorator when legacy
262 # handling is removed.
263 if config.validate_only:
264 return controller.RETURN_CODE_VALID_INPUT
265
Alex Kleinb9d810b2019-07-01 12:38:02 -0600266 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Klein231d2da2019-07-22 16:44:45 -0600267 if not sysroot.Exists(chroot=chroot):
Alex Kleinb9d810b2019-07-01 12:38:02 -0600268 cros_build_lib.Die('Sysroot must exist.')
269
270 archive = artifacts.BundleTastFiles(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600271
LaMont Jonesb9793cd2020-06-11 08:14:46 -0600272 if archive:
273 output_proto.artifacts.add().path = archive
274 else:
275 logging.warning('Found no tast files for %s.', target)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600276
277
Fergus Dall34d74e12020-09-29 15:52:32 +1000278def BundlePinnedGuestImages(_input_proto, _output_proto, _config):
279 # TODO(crbug/1034529): Remove this endpoint
280 pass
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700281
Fergus Dall34d74e12020-09-29 15:52:32 +1000282def FetchPinnedGuestImageUris(_input_proto, _output_proto, _config):
283 # TODO(crbug/1034529): Remove this endpoint
284 pass
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600285
286
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700287def _BundleFirmwareResponse(input_proto, output_proto, _config):
288 """Add test firmware image files to a successful response."""
289 output_proto.artifacts.add().path = os.path.join(
290 input_proto.output_dir, 'firmware.tar.gz')
291
292
293@faux.success(_BundleFirmwareResponse)
294@faux.empty_error
Michael Mortensen38675192019-06-28 16:52:55 +0000295@validate.require('output_dir', 'sysroot.path')
Alex Klein231d2da2019-07-22 16:44:45 -0600296@validate.exists('output_dir')
297@validate.validation_complete
298def BundleFirmware(input_proto, output_proto, _config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600299 """Tar the firmware images for a build target.
300
301 Args:
302 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600303 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600304 _config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600305 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600306 output_dir = input_proto.output_dir
Michael Mortensen38675192019-06-28 16:52:55 +0000307 chroot = controller_util.ParseChroot(input_proto.chroot)
308 sysroot_path = input_proto.sysroot.path
309 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Klein231d2da2019-07-22 16:44:45 -0600310
311 if not chroot.exists():
312 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
313 elif not sysroot.Exists(chroot=chroot):
314 cros_build_lib.Die('Sysroot does not exist: %s',
315 chroot.full_path(sysroot.path))
316
Michael Mortensen38675192019-06-28 16:52:55 +0000317 archive = artifacts.BuildFirmwareArchive(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600318
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600319 if archive is None:
320 cros_build_lib.Die(
Michael Mortensen38675192019-06-28 16:52:55 +0000321 'Could not create firmware archive. No firmware found for %s.',
322 sysroot_path)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600323
Alex Klein231d2da2019-07-22 16:44:45 -0600324 output_proto.artifacts.add().path = archive
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600325
326
Yicheng Liea1181f2020-09-22 11:51:10 -0700327def _BundleFpmcuUnittestsResponse(input_proto, output_proto, _config):
328 """Add fingerprint MCU unittest binaries to a successful response."""
329 output_proto.artifacts.add().path = os.path.join(
330 input_proto.output_dir, 'fpmcu_unittests.tar.gz')
331
332
333@faux.success(_BundleFpmcuUnittestsResponse)
334@faux.empty_error
335@validate.require('output_dir', 'sysroot.path')
336@validate.exists('output_dir')
337@validate.validation_complete
338def BundleFpmcuUnittests(input_proto, output_proto, _config):
339 """Tar the fingerprint MCU unittest binaries for a build target.
340
341 Args:
342 input_proto (BundleRequest): The input proto.
343 output_proto (BundleResponse): The output proto.
344 _config (api_config.ApiConfig): The API call config.
345 """
346 output_dir = input_proto.output_dir
347 chroot = controller_util.ParseChroot(input_proto.chroot)
348 sysroot_path = input_proto.sysroot.path
349 sysroot = sysroot_lib.Sysroot(sysroot_path)
350
351 if not chroot.exists():
352 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
353 elif not sysroot.Exists(chroot=chroot):
354 cros_build_lib.Die('Sysroot does not exist: %s',
355 chroot.full_path(sysroot.path))
356
357 archive = artifacts.BundleFpmcuUnittests(chroot, sysroot, output_dir)
358
359 if archive is None:
360 logging.warning(
361 'No fpmcu unittests found for %s.', sysroot_path)
362 return
363
364 output_proto.artifacts.add().path = archive
365
366
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700367def _BundleEbuildLogsResponse(input_proto, output_proto, _config):
368 """Add test log files to a successful response."""
369 output_proto.artifacts.add().path = os.path.join(
370 input_proto.output_dir, 'ebuild-logs.tar.gz')
371
372
373@faux.success(_BundleEbuildLogsResponse)
374@faux.empty_error
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600375@validate.exists('output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600376def BundleEbuildLogs(input_proto, output_proto, config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600377 """Tar the ebuild logs for a build target.
378
379 Args:
380 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600381 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600382 config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600383 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600384 output_dir = input_proto.output_dir
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600385 sysroot_path = input_proto.sysroot.path
386 chroot = controller_util.ParseChroot(input_proto.chroot)
Evan Hernandeza478d802019-04-08 15:08:24 -0600387
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600388 # TODO(mmortensen) Cleanup legacy handling after it has been switched over.
389 target = input_proto.build_target.name
390 if target:
391 # Legacy handling.
392 build_root = constants.SOURCE_ROOT
Alex Klein171da612019-08-06 14:00:42 -0600393 chroot = chroot_lib.Chroot(path=os.path.join(build_root, 'chroot'))
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600394 sysroot_path = os.path.join('/build', target)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600395
Alex Klein231d2da2019-07-22 16:44:45 -0600396 # TODO(saklein): Switch to validation_complete decorator after legacy
397 # handling has been cleaned up.
398 if config.validate_only:
399 return controller.RETURN_CODE_VALID_INPUT
400
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600401 sysroot = sysroot_lib.Sysroot(sysroot_path)
402 archive = artifacts.BundleEBuildLogsTarball(chroot, sysroot, output_dir)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600403 if archive is None:
404 cros_build_lib.Die(
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600405 'Could not create ebuild logs archive. No logs found for %s.',
406 sysroot.path)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600407 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Klein6504eca2019-04-18 15:37:56 -0600408
409
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700410def _BundleChromeOSConfigResponse(input_proto, output_proto, _config):
411 """Add test config files to a successful response."""
412 output_proto.artifacts.add().path = os.path.join(
413 input_proto.output_dir, 'config.yaml')
414
415
416@faux.success(_BundleChromeOSConfigResponse)
417@faux.empty_error
Andrew Lamb811aead2019-08-12 10:25:05 -0600418@validate.exists('output_dir')
419@validate.validation_complete
420def BundleChromeOSConfig(input_proto, output_proto, _config):
421 """Output the ChromeOS Config payload for a build target.
422
423 Args:
424 input_proto (BundleRequest): The input proto.
425 output_proto (BundleResponse): The output proto.
426 _config (api_config.ApiConfig): The API call config.
427 """
428 output_dir = input_proto.output_dir
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600429 sysroot_path = input_proto.sysroot.path
Andrew Lamb811aead2019-08-12 10:25:05 -0600430 chroot = controller_util.ParseChroot(input_proto.chroot)
431
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600432 # TODO(mmortensen) Cleanup legacy handling after it has been switched over.
433 target = input_proto.build_target.name
434 if target:
435 # Legacy handling.
436 build_root = constants.SOURCE_ROOT
437 chroot = chroot_lib.Chroot(path=os.path.join(build_root, 'chroot'))
438 sysroot_path = os.path.join('/build', target)
439
440 sysroot = sysroot_lib.Sysroot(sysroot_path)
Andrew Lamb811aead2019-08-12 10:25:05 -0600441 chromeos_config = artifacts.BundleChromeOSConfig(chroot, sysroot, output_dir)
442 if chromeos_config is None:
443 cros_build_lib.Die(
444 'Could not create ChromeOS Config payload. No config found for %s.',
445 sysroot.path)
446 output_proto.artifacts.add().path = os.path.join(output_dir, chromeos_config)
447
448
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700449def _BundleSimpleChromeArtifactsResponse(input_proto, output_proto, _config):
450 """Add test simple chrome files to a successful response."""
451 output_proto.artifacts.add().path = os.path.join(
452 input_proto.output_dir, 'simple_chrome.txt')
453
454
455@faux.success(_BundleSimpleChromeArtifactsResponse)
456@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600457@validate.require('output_dir', 'sysroot.build_target.name', 'sysroot.path')
458@validate.exists('output_dir')
459@validate.validation_complete
460def BundleSimpleChromeArtifacts(input_proto, output_proto, _config):
Alex Klein2275d692019-04-23 16:04:12 -0600461 """Create the simple chrome artifacts."""
Alex Klein2275d692019-04-23 16:04:12 -0600462 sysroot_path = input_proto.sysroot.path
Alex Klein2275d692019-04-23 16:04:12 -0600463 output_dir = input_proto.output_dir
464
Alex Klein2275d692019-04-23 16:04:12 -0600465 # Build out the argument instances.
Alex Klein26e472b2020-03-10 14:35:01 -0600466 build_target = controller_util.ParseBuildTarget(
467 input_proto.sysroot.build_target)
468 chroot = controller_util.ParseChroot(input_proto.chroot)
Alex Klein2275d692019-04-23 16:04:12 -0600469 # Sysroot.path needs to be the fully qualified path, including the chroot.
470 full_sysroot_path = os.path.join(chroot.path, sysroot_path.lstrip(os.sep))
471 sysroot = sysroot_lib.Sysroot(full_sysroot_path)
472
473 # Quick sanity check that the sysroot exists before we go on.
474 if not sysroot.Exists():
475 cros_build_lib.Die('The sysroot does not exist.')
476
477 try:
478 results = artifacts.BundleSimpleChromeArtifacts(chroot, sysroot,
479 build_target, output_dir)
480 except artifacts.Error as e:
481 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
482 type(e), e)
483
484 for file_name in results:
485 output_proto.artifacts.add().path = file_name
486
487
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700488def _BundleVmFilesResponse(input_proto, output_proto, _config):
489 """Add test vm files to a successful response."""
490 output_proto.artifacts.add().path = os.path.join(
491 input_proto.output_dir, 'f1.tar')
492
493
494@faux.success(_BundleVmFilesResponse)
495@faux.empty_error
Michael Mortensen51f06722019-07-18 09:55:50 -0600496@validate.require('chroot.path', 'test_results_dir', 'output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600497@validate.exists('output_dir')
498@validate.validation_complete
499def BundleVmFiles(input_proto, output_proto, _config):
Alex Klein6504eca2019-04-18 15:37:56 -0600500 """Tar VM disk and memory files.
501
502 Args:
Trent Begin008cade2019-10-31 13:40:59 -0600503 input_proto (BundleVmFilesRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600504 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600505 _config (api_config.ApiConfig): The API call config.
Alex Klein6504eca2019-04-18 15:37:56 -0600506 """
Michael Mortensen51f06722019-07-18 09:55:50 -0600507 chroot = controller_util.ParseChroot(input_proto.chroot)
508 test_results_dir = input_proto.test_results_dir
Alex Klein6504eca2019-04-18 15:37:56 -0600509 output_dir = input_proto.output_dir
510
Michael Mortensen51f06722019-07-18 09:55:50 -0600511 archives = artifacts.BundleVmFiles(
512 chroot, test_results_dir, output_dir)
Alex Klein6504eca2019-04-18 15:37:56 -0600513 for archive in archives:
514 output_proto.artifacts.add().path = archive
Tiancong Wangc4805b72019-06-11 12:12:03 -0700515
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700516def _BundleAFDOGenerationArtifactsResponse(input_proto, output_proto, _config):
517 """Add test tarball AFDO file to a successful response."""
518 output_proto.artifacts.add().path = os.path.join(
519 input_proto.output_dir, 'artifact1')
520
Alex Klein231d2da2019-07-22 16:44:45 -0600521
Tiancong Wang24a3df72019-08-20 15:48:51 -0700522_VALID_ARTIFACT_TYPES = [toolchain_pb2.BENCHMARK_AFDO,
523 toolchain_pb2.ORDERFILE]
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700524@faux.success(_BundleAFDOGenerationArtifactsResponse)
525@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600526@validate.require('build_target.name', 'output_dir')
Tiancong Wang50b80a92019-08-01 14:46:15 -0700527@validate.is_in('artifact_type', _VALID_ARTIFACT_TYPES)
Alex Klein231d2da2019-07-22 16:44:45 -0600528@validate.exists('output_dir')
Tiancong Wang2ade7932019-09-27 14:15:40 -0700529@validate.exists('chroot.chrome_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600530@validate.validation_complete
Tiancong Wang50b80a92019-08-01 14:46:15 -0700531def BundleAFDOGenerationArtifacts(input_proto, output_proto, _config):
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700532 """Generic function for creating tarballs of both AFDO and orderfile.
Tiancong Wangc4805b72019-06-11 12:12:03 -0700533
534 Args:
Tiancong Wang50b80a92019-08-01 14:46:15 -0700535 input_proto (BundleChromeAFDORequest): The input proto.
Tiancong Wangc4805b72019-06-11 12:12:03 -0700536 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600537 _config (api_config.ApiConfig): The API call config.
Tiancong Wangc4805b72019-06-11 12:12:03 -0700538 """
Tiancong Wang2ade7932019-09-27 14:15:40 -0700539 chrome_root = input_proto.chroot.chrome_dir
Tiancong Wangc4805b72019-06-11 12:12:03 -0700540 output_dir = input_proto.output_dir
Tiancong Wang50b80a92019-08-01 14:46:15 -0700541 artifact_type = input_proto.artifact_type
Tiancong Wangc4805b72019-06-11 12:12:03 -0700542
Alex Klein26e472b2020-03-10 14:35:01 -0600543 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
Tiancong Wangc4805b72019-06-11 12:12:03 -0700544 chroot = controller_util.ParseChroot(input_proto.chroot)
545
546 try:
Tiancong Wang24a3df72019-08-20 15:48:51 -0700547 is_orderfile = bool(artifact_type is toolchain_pb2.ORDERFILE)
Tiancong Wang50b80a92019-08-01 14:46:15 -0700548 results = artifacts.BundleAFDOGenerationArtifacts(
Tiancong Wang2ade7932019-09-27 14:15:40 -0700549 is_orderfile, chroot, chrome_root,
Tiancong Wang50b80a92019-08-01 14:46:15 -0700550 build_target, output_dir)
Tiancong Wangc4805b72019-06-11 12:12:03 -0700551 except artifacts.Error as e:
552 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
553 type(e), e)
554
555 for file_name in results:
556 output_proto.artifacts.add().path = file_name
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600557
558
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700559def _ExportCpeReportResponse(input_proto, output_proto, _config):
560 """Add test cpe results to a successful response."""
561 output_proto.artifacts.add().path = os.path.join(
562 input_proto.output_dir, 'cpe_report.txt')
563 output_proto.artifacts.add().path = os.path.join(
564 input_proto.output_dir, 'cpe_warnings.txt')
565
566
567@faux.success(_ExportCpeReportResponse)
568@faux.empty_error
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600569@validate.exists('output_dir')
570def ExportCpeReport(input_proto, output_proto, config):
571 """Export a CPE report.
572
573 Args:
574 input_proto (BundleRequest): The input proto.
575 output_proto (BundleResponse): The output proto.
576 config (api_config.ApiConfig): The API call config.
577 """
578 chroot = controller_util.ParseChroot(input_proto.chroot)
579 output_dir = input_proto.output_dir
580
581 if input_proto.build_target.name:
582 # Legacy handling - use the default sysroot path for the build target.
583 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
584 sysroot = sysroot_lib.Sysroot(build_target.root)
585 elif input_proto.sysroot.path:
586 sysroot = sysroot_lib.Sysroot(input_proto.sysroot.path)
587 else:
588 # TODO(saklein): Switch to validate decorators once legacy handling can be
589 # cleaned up.
590 cros_build_lib.Die('sysroot.path is required.')
591
592 if config.validate_only:
593 return controller.RETURN_CODE_VALID_INPUT
594
595 cpe_result = artifacts.GenerateCpeReport(chroot, sysroot, output_dir)
596
597 output_proto.artifacts.add().path = cpe_result.report
598 output_proto.artifacts.add().path = cpe_result.warnings
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +0900599
600
601def _BundleGceTarballResponse(input_proto, output_proto, _config):
602 """Add artifact tarball to a successful response."""
603 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
604 constants.TEST_IMAGE_GCE_TAR)
605
606
607@faux.success(_BundleGceTarballResponse)
608@faux.empty_error
609@validate.require('build_target.name', 'output_dir')
610@validate.exists('output_dir')
611@validate.validation_complete
612def BundleGceTarball(input_proto, output_proto, _config):
613 """Bundle the test image into a tarball suitable for importing into GCE.
614
615 Args:
616 input_proto (BundleRequest): The input proto.
617 output_proto (BundleResponse): The output proto.
618 _config (api_config.ApiConfig): The API call config.
619 """
620 target = input_proto.build_target.name
621 output_dir = input_proto.output_dir
622 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
623 if image_dir is None:
624 return None
625
626 tarball = artifacts.BundleGceTarball(output_dir, image_dir)
627 output_proto.artifacts.add().path = tarball
Michael Mortensen6667b542020-12-12 11:09:55 -0700628
629
630def _BundleDebugSymbolsResponse(input_proto, output_proto, _config):
631 """Add artifact tarball to a successful response."""
632 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
633 constants.DEBUG_SYMBOLS_TAR)
634
635
636@faux.success(_BundleDebugSymbolsResponse)
637@faux.empty_error
638@validate.require('build_target.name', 'output_dir')
639@validate.exists('output_dir')
640@validate.validation_complete
641def BundleDebugSymbols(input_proto, output_proto, _config):
642 """Bundle the debug symbols into a tarball suitable for importing into GCE.
643
644 Args:
645 input_proto (BundleRequest): The input proto.
646 output_proto (BundleResponse): The output proto.
647 _config (api_config.ApiConfig): The API call config.
648 """
649 target = input_proto.build_target.name
650 output_dir = input_proto.output_dir
651
652 chroot = controller_util.ParseChroot(input_proto.chroot)
653 result = artifacts.GenerateBreakpadSymbols(chroot,
654 target,
655 debug=True)
656
657 # Verify breakpad symbol generation before gathering the sym files.
658 if result.returncode != 0:
659 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
660
661 with chroot.tempdir() as symbol_tmpdir, chroot.tempdir() as dest_tmpdir:
662 breakpad_dir = os.path.join('/build', target, 'usr/lib/debug/breakpad')
663 sym_file_list = artifacts.GatherSymbolFiles(tempdir=symbol_tmpdir,
664 destdir=dest_tmpdir,
665 paths=[breakpad_dir])
666 if len(sym_file_list) == 0:
667 logging.warning('No sym files found in %s.', breakpad_dir)
668 # Create tarball from destination_tmp, then copy it...
669 tarball_path = os.path.join(output_dir, constants.DEBUG_SYMBOLS_TAR)
670 result = cros_build_lib.CreateTarball(tarball_path, dest_tmpdir)
671 if result.returncode != 0:
672 logging.error('Error (%d) when creating tarball %s from %s',
673 result.returncode,
674 tarball_path,
675 dest_tmpdir)
676 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
677 output_proto.artifacts.add().path = tarball_path
678
679 return controller.RETURN_CODE_SUCCESS