blob: 42bb1cd3dc7fe73e5e826cf4a823b9b9cb4a8c67 [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
Mike Frysingeref94e4c2020-02-10 23:59:54 -050011import sys
Evan Hernandezf388cbf2019-04-01 11:15:23 -060012
Alex Klein231d2da2019-07-22 16:44:45 -060013from chromite.api import controller
Alex Klein076841b2019-08-29 15:19:39 -060014from chromite.api import faux
Alex Klein2b236722019-06-19 15:44:26 -060015from chromite.api import validate
Alex Klein238d8862019-05-07 11:32:46 -060016from chromite.api.controller import controller_util
Tiancong Wang24a3df72019-08-20 15:48:51 -070017from chromite.api.gen.chromite.api import toolchain_pb2
Evan Hernandezf388cbf2019-04-01 11:15:23 -060018from chromite.cbuildbot import commands
Alex Klein2275d692019-04-23 16:04:12 -060019from chromite.lib import chroot_lib
Evan Hernandezf388cbf2019-04-01 11:15:23 -060020from chromite.lib import constants
21from chromite.lib import cros_build_lib
Evan Hernandezde445982019-04-22 13:42:34 -060022from chromite.lib import cros_logging as logging
Alex Klein2275d692019-04-23 16:04:12 -060023from chromite.lib import sysroot_lib
24from chromite.service import artifacts
Evan Hernandezf388cbf2019-04-01 11:15:23 -060025
26
Mike Frysingeref94e4c2020-02-10 23:59:54 -050027assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
28
29
Evan Hernandez9f125ac2019-04-08 17:18:47 -060030def _GetImageDir(build_root, target):
31 """Return path containing images for the given build target.
32
Alex Kleine2612a02019-04-18 13:51:06 -060033 TODO(saklein) Expand image_lib.GetLatestImageLink to support this use case.
34
Evan Hernandez9f125ac2019-04-08 17:18:47 -060035 Args:
36 build_root (str): Path to checkout where build occurs.
37 target (str): Name of the build target.
38
39 Returns:
Alex Kleind2bf1462019-10-24 16:37:04 -060040 Path to the latest directory containing target images or None.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060041 """
42 image_dir = os.path.join(build_root, 'src/build/images', target, 'latest')
43 if not os.path.exists(image_dir):
Alex Kleind2bf1462019-10-24 16:37:04 -060044 logging.warning('Expected to find image output for target %s at %s, but '
45 'path does not exist', target, image_dir)
46 return None
47
Evan Hernandez9f125ac2019-04-08 17:18:47 -060048 return image_dir
49
50
Michael Mortensen2d6a2402019-11-26 13:40:40 -070051def _BundleImageArchivesResponse(input_proto, output_proto, _config):
52 """Add artifact paths to a successful response."""
53 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
54 'path0.tar.xz')
55 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
56 'path1.tar.xz')
57
58
59@faux.success(_BundleImageArchivesResponse)
60@faux.empty_error
Alex Kleind91e95a2019-09-17 10:39:02 -060061@validate.require('build_target.name')
62@validate.exists('output_dir')
63@validate.validation_complete
64def BundleImageArchives(input_proto, output_proto, _config):
65 """Create a .tar.xz archive for each image that has been created."""
66 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
67 output_dir = input_proto.output_dir
68 image_dir = _GetImageDir(constants.SOURCE_ROOT, build_target.name)
Alex Kleind2bf1462019-10-24 16:37:04 -060069 if image_dir is None:
70 return
Alex Kleind91e95a2019-09-17 10:39:02 -060071
72 archives = artifacts.ArchiveImages(image_dir, output_dir)
73
74 for archive in archives:
75 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
76
77
Michael Mortensen2d6a2402019-11-26 13:40:40 -070078def _BundleImageZipResponse(input_proto, output_proto, _config):
79 """Add artifact zip files to a successful response."""
80 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
81 'image.zip')
82
83
84@faux.success(_BundleImageZipResponse)
85@faux.empty_error
Michael Mortensen01910922019-07-24 14:48:10 -060086@validate.require('build_target.name', 'output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -060087@validate.exists('output_dir')
88@validate.validation_complete
89def BundleImageZip(input_proto, output_proto, _config):
Evan Hernandez9f125ac2019-04-08 17:18:47 -060090 """Bundle image.zip.
91
92 Args:
93 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -060094 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -060095 _config (api_config.ApiConfig): The API call config.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060096 """
97 target = input_proto.build_target.name
98 output_dir = input_proto.output_dir
99 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
Alex Kleind2bf1462019-10-24 16:37:04 -0600100 if image_dir is None:
101 return None
Alex Klein231d2da2019-07-22 16:44:45 -0600102
Michael Mortensen01910922019-07-24 14:48:10 -0600103 archive = artifacts.BundleImageZip(output_dir, image_dir)
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600104 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
105
106
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700107def _BundleTestUpdatePayloadsResponse(input_proto, output_proto, _config):
108 """Add test payload files to a successful response."""
109 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
110 'payload1.bin')
111
112
113@faux.success(_BundleTestUpdatePayloadsResponse)
114@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600115@validate.require('build_target.name', 'output_dir')
116@validate.exists('output_dir')
117@validate.validation_complete
118def BundleTestUpdatePayloads(input_proto, output_proto, _config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600119 """Generate minimal update payloads for the build target for testing.
120
121 Args:
122 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600123 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600124 _config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600125 """
126 target = input_proto.build_target.name
127 output_dir = input_proto.output_dir
128 build_root = constants.SOURCE_ROOT
129
130 # Use the first available image to create the update payload.
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600131 img_dir = _GetImageDir(build_root, target)
Alex Kleind2bf1462019-10-24 16:37:04 -0600132 if img_dir is None:
133 return None
134
Alex Kleincb541e82019-06-26 15:06:11 -0600135 img_types = [constants.IMAGE_TYPE_TEST, constants.IMAGE_TYPE_DEV,
136 constants.IMAGE_TYPE_BASE]
137 img_names = [constants.IMAGE_TYPE_TO_NAME[t] for t in img_types]
Mike Frysinger66ce4132019-07-17 22:52:52 -0400138 img_paths = [os.path.join(img_dir, x) for x in img_names]
Mike Frysingera552be42018-08-17 14:39:32 -0400139 valid_images = [x for x in img_paths if os.path.exists(x)]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600140
Alex Kleincb541e82019-06-26 15:06:11 -0600141 if not valid_images:
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600142 cros_build_lib.Die(
143 'Expected to find an image of type among %r for target "%s" '
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600144 'at path %s.', img_types, target, img_dir)
Alex Kleincb541e82019-06-26 15:06:11 -0600145 image = valid_images[0]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600146
Alex Kleincb541e82019-06-26 15:06:11 -0600147 payloads = artifacts.BundleTestUpdatePayloads(image, output_dir)
148 for payload in payloads:
149 output_proto.artifacts.add().path = payload
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600150
151
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700152def _BundleAutotestFilesResponse(input_proto, output_proto, _config):
153 """Add test autotest files to a successful response."""
154 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
155 'autotest-a.tar.gz')
156
157
158@faux.success(_BundleAutotestFilesResponse)
159@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600160@validate.require('output_dir')
161@validate.exists('output_dir')
162def BundleAutotestFiles(input_proto, output_proto, config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600163 """Tar the autotest files for a build target.
164
165 Args:
166 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600167 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600168 config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600169 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600170 output_dir = input_proto.output_dir
Alex Klein238d8862019-05-07 11:32:46 -0600171 target = input_proto.build_target.name
Alex Kleine21a0952019-08-23 16:08:16 -0600172 chroot = controller_util.ParseChroot(input_proto.chroot)
173
Alex Klein238d8862019-05-07 11:32:46 -0600174 if target:
Alex Kleine21a0952019-08-23 16:08:16 -0600175 sysroot_path = os.path.join('/build', target)
Alex Klein238d8862019-05-07 11:32:46 -0600176 else:
177 # New style call, use chroot and sysroot.
Alex Klein238d8862019-05-07 11:32:46 -0600178 sysroot_path = input_proto.sysroot.path
179 if not sysroot_path:
180 cros_build_lib.Die('sysroot.path is required.')
181
Alex Kleine21a0952019-08-23 16:08:16 -0600182 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Klein238d8862019-05-07 11:32:46 -0600183
Alex Klein231d2da2019-07-22 16:44:45 -0600184 # TODO(saklein): Switch to the validate_only decorator when legacy handling
185 # is removed.
186 if config.validate_only:
187 return controller.RETURN_CODE_VALID_INPUT
188
Alex Kleine21a0952019-08-23 16:08:16 -0600189 if not sysroot.Exists(chroot=chroot):
Alex Klein238d8862019-05-07 11:32:46 -0600190 cros_build_lib.Die('Sysroot path must exist: %s', sysroot.path)
191
192 try:
193 # Note that this returns the full path to *multiple* tarballs.
Alex Kleine21a0952019-08-23 16:08:16 -0600194 archives = artifacts.BundleAutotestFiles(chroot, sysroot, output_dir)
Alex Klein238d8862019-05-07 11:32:46 -0600195 except artifacts.Error as e:
Alex Klein03890312020-06-30 09:59:50 -0600196 logging.warning(e)
197 return
Alex Klein238d8862019-05-07 11:32:46 -0600198
199 for archive in archives.values():
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600200 output_proto.artifacts.add().path = archive
201
202
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700203def _BundleTastFilesResponse(input_proto, output_proto, _config):
204 """Add test tast files to a successful response."""
205 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
206 'tast_bundles.tar.gz')
207
208
209@faux.success(_BundleTastFilesResponse)
210@faux.empty_error
Alex Kleinb9d810b2019-07-01 12:38:02 -0600211@validate.require('output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600212@validate.exists('output_dir')
213def BundleTastFiles(input_proto, output_proto, config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600214 """Tar the tast files for a build target.
215
216 Args:
217 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600218 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600219 config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600220 """
221 target = input_proto.build_target.name
222 output_dir = input_proto.output_dir
223 build_root = constants.SOURCE_ROOT
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600224
Alex Kleinb9d810b2019-07-01 12:38:02 -0600225 chroot = controller_util.ParseChroot(input_proto.chroot)
226 sysroot_path = input_proto.sysroot.path
227
228 # TODO(saklein) Cleanup legacy handling after it has been switched over.
229 if target:
230 # Legacy handling.
Alex Klein171da612019-08-06 14:00:42 -0600231 chroot = chroot_lib.Chroot(path=os.path.join(build_root, 'chroot'))
Alex Kleinb9d810b2019-07-01 12:38:02 -0600232 sysroot_path = os.path.join('/build', target)
233
234 # New handling - chroot & sysroot based.
235 # TODO(saklein) Switch this to the require decorator when legacy is removed.
236 if not sysroot_path:
237 cros_build_lib.Die('sysroot.path is required.')
238
Alex Klein231d2da2019-07-22 16:44:45 -0600239 # TODO(saklein): Switch to the validation_complete decorator when legacy
240 # handling is removed.
241 if config.validate_only:
242 return controller.RETURN_CODE_VALID_INPUT
243
Alex Kleinb9d810b2019-07-01 12:38:02 -0600244 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Klein231d2da2019-07-22 16:44:45 -0600245 if not sysroot.Exists(chroot=chroot):
Alex Kleinb9d810b2019-07-01 12:38:02 -0600246 cros_build_lib.Die('Sysroot must exist.')
247
248 archive = artifacts.BundleTastFiles(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600249
LaMont Jonesb9793cd2020-06-11 08:14:46 -0600250 if archive:
251 output_proto.artifacts.add().path = archive
252 else:
253 logging.warning('Found no tast files for %s.', target)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600254
255
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700256def _BundlePinnedGuestImagesResponse(input_proto, output_proto, _config):
257 """Add test pinned guest image files to a successful response."""
258 output_proto.artifacts.add().path = os.path.join(
259 input_proto.output_dir, 'pinned-guest-images.tar.gz')
260
261
262@faux.success(_BundlePinnedGuestImagesResponse)
263@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600264@validate.require('build_target.name', 'output_dir')
265@validate.exists('output_dir')
266@validate.validation_complete
267def BundlePinnedGuestImages(input_proto, output_proto, _config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600268 """Tar the pinned guest images for a build target.
269
270 Args:
271 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600272 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600273 _config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600274 """
275 target = input_proto.build_target.name
276 output_dir = input_proto.output_dir
277 build_root = constants.SOURCE_ROOT
278
Alex Kleine2612a02019-04-18 13:51:06 -0600279 # TODO(crbug.com/954299): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600280 archive = commands.BuildPinnedGuestImagesTarball(build_root, target,
281 output_dir)
282
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600283 if archive is None:
Evan Hernandezde445982019-04-22 13:42:34 -0600284 logging.warning('Found no pinned guest images for %s.', target)
285 return
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600286
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600287 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
288
289
Alex Kleinc3e8d0c2020-05-15 11:20:22 -0600290def _FetchPinnedGuestImageUrisResponse(_input_proto, output_proto, _config):
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700291 """Add test fetched pinned guest image files to a successful response."""
292 pinned_image = output_proto.pinned_images.add()
293 pinned_image.filename = 'pinned_file.tar.gz'
294 pinned_image.uri = 'https://testuri.com'
295
296
Alex Kleinc3e8d0c2020-05-15 11:20:22 -0600297@faux.success(_FetchPinnedGuestImageUrisResponse)
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700298@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600299@validate.require('sysroot.path')
300@validate.validation_complete
Alex Kleinc3e8d0c2020-05-15 11:20:22 -0600301def FetchPinnedGuestImageUris(input_proto, output_proto, _config):
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600302 """Get the pinned guest image information."""
303 sysroot_path = input_proto.sysroot.path
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600304
305 chroot = controller_util.ParseChroot(input_proto.chroot)
306 sysroot = sysroot_lib.Sysroot(sysroot_path)
307
308 if not chroot.exists():
309 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
Alex Klein231d2da2019-07-22 16:44:45 -0600310 elif not sysroot.Exists(chroot=chroot):
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600311 cros_build_lib.Die('Sysroot does not exist: %s',
312 chroot.full_path(sysroot.path))
313
314 pins = artifacts.FetchPinnedGuestImages(chroot, sysroot)
315
316 for pin in pins:
317 pinned_image = output_proto.pinned_images.add()
318 pinned_image.filename = pin.filename
319 pinned_image.uri = pin.uri
320
321
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700322def _BundleFirmwareResponse(input_proto, output_proto, _config):
323 """Add test firmware image files to a successful response."""
324 output_proto.artifacts.add().path = os.path.join(
325 input_proto.output_dir, 'firmware.tar.gz')
326
327
328@faux.success(_BundleFirmwareResponse)
329@faux.empty_error
Michael Mortensen38675192019-06-28 16:52:55 +0000330@validate.require('output_dir', 'sysroot.path')
Alex Klein231d2da2019-07-22 16:44:45 -0600331@validate.exists('output_dir')
332@validate.validation_complete
333def BundleFirmware(input_proto, output_proto, _config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600334 """Tar the firmware images for a build target.
335
336 Args:
337 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600338 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600339 _config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600340 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600341 output_dir = input_proto.output_dir
Michael Mortensen38675192019-06-28 16:52:55 +0000342 chroot = controller_util.ParseChroot(input_proto.chroot)
343 sysroot_path = input_proto.sysroot.path
344 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Klein231d2da2019-07-22 16:44:45 -0600345
346 if not chroot.exists():
347 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
348 elif not sysroot.Exists(chroot=chroot):
349 cros_build_lib.Die('Sysroot does not exist: %s',
350 chroot.full_path(sysroot.path))
351
Michael Mortensen38675192019-06-28 16:52:55 +0000352 archive = artifacts.BuildFirmwareArchive(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600353
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600354 if archive is None:
355 cros_build_lib.Die(
Michael Mortensen38675192019-06-28 16:52:55 +0000356 'Could not create firmware archive. No firmware found for %s.',
357 sysroot_path)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600358
Alex Klein231d2da2019-07-22 16:44:45 -0600359 output_proto.artifacts.add().path = archive
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600360
361
Yicheng Liea1181f2020-09-22 11:51:10 -0700362def _BundleFpmcuUnittestsResponse(input_proto, output_proto, _config):
363 """Add fingerprint MCU unittest binaries to a successful response."""
364 output_proto.artifacts.add().path = os.path.join(
365 input_proto.output_dir, 'fpmcu_unittests.tar.gz')
366
367
368@faux.success(_BundleFpmcuUnittestsResponse)
369@faux.empty_error
370@validate.require('output_dir', 'sysroot.path')
371@validate.exists('output_dir')
372@validate.validation_complete
373def BundleFpmcuUnittests(input_proto, output_proto, _config):
374 """Tar the fingerprint MCU unittest binaries for a build target.
375
376 Args:
377 input_proto (BundleRequest): The input proto.
378 output_proto (BundleResponse): The output proto.
379 _config (api_config.ApiConfig): The API call config.
380 """
381 output_dir = input_proto.output_dir
382 chroot = controller_util.ParseChroot(input_proto.chroot)
383 sysroot_path = input_proto.sysroot.path
384 sysroot = sysroot_lib.Sysroot(sysroot_path)
385
386 if not chroot.exists():
387 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
388 elif not sysroot.Exists(chroot=chroot):
389 cros_build_lib.Die('Sysroot does not exist: %s',
390 chroot.full_path(sysroot.path))
391
392 archive = artifacts.BundleFpmcuUnittests(chroot, sysroot, output_dir)
393
394 if archive is None:
395 logging.warning(
396 'No fpmcu unittests found for %s.', sysroot_path)
397 return
398
399 output_proto.artifacts.add().path = archive
400
401
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700402def _BundleEbuildLogsResponse(input_proto, output_proto, _config):
403 """Add test log files to a successful response."""
404 output_proto.artifacts.add().path = os.path.join(
405 input_proto.output_dir, 'ebuild-logs.tar.gz')
406
407
408@faux.success(_BundleEbuildLogsResponse)
409@faux.empty_error
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600410@validate.exists('output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600411def BundleEbuildLogs(input_proto, output_proto, config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600412 """Tar the ebuild logs for a build target.
413
414 Args:
415 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600416 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600417 config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600418 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600419 output_dir = input_proto.output_dir
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600420 sysroot_path = input_proto.sysroot.path
421 chroot = controller_util.ParseChroot(input_proto.chroot)
Evan Hernandeza478d802019-04-08 15:08:24 -0600422
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600423 # TODO(mmortensen) Cleanup legacy handling after it has been switched over.
424 target = input_proto.build_target.name
425 if target:
426 # Legacy handling.
427 build_root = constants.SOURCE_ROOT
Alex Klein171da612019-08-06 14:00:42 -0600428 chroot = chroot_lib.Chroot(path=os.path.join(build_root, 'chroot'))
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600429 sysroot_path = os.path.join('/build', target)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600430
Alex Klein231d2da2019-07-22 16:44:45 -0600431 # TODO(saklein): Switch to validation_complete decorator after legacy
432 # handling has been cleaned up.
433 if config.validate_only:
434 return controller.RETURN_CODE_VALID_INPUT
435
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600436 sysroot = sysroot_lib.Sysroot(sysroot_path)
437 archive = artifacts.BundleEBuildLogsTarball(chroot, sysroot, output_dir)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600438 if archive is None:
439 cros_build_lib.Die(
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600440 'Could not create ebuild logs archive. No logs found for %s.',
441 sysroot.path)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600442 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Klein6504eca2019-04-18 15:37:56 -0600443
444
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700445def _BundleChromeOSConfigResponse(input_proto, output_proto, _config):
446 """Add test config files to a successful response."""
447 output_proto.artifacts.add().path = os.path.join(
448 input_proto.output_dir, 'config.yaml')
449
450
451@faux.success(_BundleChromeOSConfigResponse)
452@faux.empty_error
Andrew Lamb811aead2019-08-12 10:25:05 -0600453@validate.exists('output_dir')
454@validate.validation_complete
455def BundleChromeOSConfig(input_proto, output_proto, _config):
456 """Output the ChromeOS Config payload for a build target.
457
458 Args:
459 input_proto (BundleRequest): The input proto.
460 output_proto (BundleResponse): The output proto.
461 _config (api_config.ApiConfig): The API call config.
462 """
463 output_dir = input_proto.output_dir
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600464 sysroot_path = input_proto.sysroot.path
Andrew Lamb811aead2019-08-12 10:25:05 -0600465 chroot = controller_util.ParseChroot(input_proto.chroot)
466
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600467 # TODO(mmortensen) Cleanup legacy handling after it has been switched over.
468 target = input_proto.build_target.name
469 if target:
470 # Legacy handling.
471 build_root = constants.SOURCE_ROOT
472 chroot = chroot_lib.Chroot(path=os.path.join(build_root, 'chroot'))
473 sysroot_path = os.path.join('/build', target)
474
475 sysroot = sysroot_lib.Sysroot(sysroot_path)
Andrew Lamb811aead2019-08-12 10:25:05 -0600476 chromeos_config = artifacts.BundleChromeOSConfig(chroot, sysroot, output_dir)
477 if chromeos_config is None:
478 cros_build_lib.Die(
479 'Could not create ChromeOS Config payload. No config found for %s.',
480 sysroot.path)
481 output_proto.artifacts.add().path = os.path.join(output_dir, chromeos_config)
482
483
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700484def _BundleSimpleChromeArtifactsResponse(input_proto, output_proto, _config):
485 """Add test simple chrome files to a successful response."""
486 output_proto.artifacts.add().path = os.path.join(
487 input_proto.output_dir, 'simple_chrome.txt')
488
489
490@faux.success(_BundleSimpleChromeArtifactsResponse)
491@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600492@validate.require('output_dir', 'sysroot.build_target.name', 'sysroot.path')
493@validate.exists('output_dir')
494@validate.validation_complete
495def BundleSimpleChromeArtifacts(input_proto, output_proto, _config):
Alex Klein2275d692019-04-23 16:04:12 -0600496 """Create the simple chrome artifacts."""
Alex Klein2275d692019-04-23 16:04:12 -0600497 sysroot_path = input_proto.sysroot.path
Alex Klein2275d692019-04-23 16:04:12 -0600498 output_dir = input_proto.output_dir
499
Alex Klein2275d692019-04-23 16:04:12 -0600500 # Build out the argument instances.
Alex Klein26e472b2020-03-10 14:35:01 -0600501 build_target = controller_util.ParseBuildTarget(
502 input_proto.sysroot.build_target)
503 chroot = controller_util.ParseChroot(input_proto.chroot)
Alex Klein2275d692019-04-23 16:04:12 -0600504 # Sysroot.path needs to be the fully qualified path, including the chroot.
505 full_sysroot_path = os.path.join(chroot.path, sysroot_path.lstrip(os.sep))
506 sysroot = sysroot_lib.Sysroot(full_sysroot_path)
507
508 # Quick sanity check that the sysroot exists before we go on.
509 if not sysroot.Exists():
510 cros_build_lib.Die('The sysroot does not exist.')
511
512 try:
513 results = artifacts.BundleSimpleChromeArtifacts(chroot, sysroot,
514 build_target, output_dir)
515 except artifacts.Error as e:
516 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
517 type(e), e)
518
519 for file_name in results:
520 output_proto.artifacts.add().path = file_name
521
522
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700523def _BundleVmFilesResponse(input_proto, output_proto, _config):
524 """Add test vm files to a successful response."""
525 output_proto.artifacts.add().path = os.path.join(
526 input_proto.output_dir, 'f1.tar')
527
528
529@faux.success(_BundleVmFilesResponse)
530@faux.empty_error
Michael Mortensen51f06722019-07-18 09:55:50 -0600531@validate.require('chroot.path', 'test_results_dir', 'output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600532@validate.exists('output_dir')
533@validate.validation_complete
534def BundleVmFiles(input_proto, output_proto, _config):
Alex Klein6504eca2019-04-18 15:37:56 -0600535 """Tar VM disk and memory files.
536
537 Args:
Trent Begin008cade2019-10-31 13:40:59 -0600538 input_proto (BundleVmFilesRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600539 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600540 _config (api_config.ApiConfig): The API call config.
Alex Klein6504eca2019-04-18 15:37:56 -0600541 """
Michael Mortensen51f06722019-07-18 09:55:50 -0600542 chroot = controller_util.ParseChroot(input_proto.chroot)
543 test_results_dir = input_proto.test_results_dir
Alex Klein6504eca2019-04-18 15:37:56 -0600544 output_dir = input_proto.output_dir
545
Michael Mortensen51f06722019-07-18 09:55:50 -0600546 archives = artifacts.BundleVmFiles(
547 chroot, test_results_dir, output_dir)
Alex Klein6504eca2019-04-18 15:37:56 -0600548 for archive in archives:
549 output_proto.artifacts.add().path = archive
Tiancong Wangc4805b72019-06-11 12:12:03 -0700550
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700551def _BundleAFDOGenerationArtifactsResponse(input_proto, output_proto, _config):
552 """Add test tarball AFDO file to a successful response."""
553 output_proto.artifacts.add().path = os.path.join(
554 input_proto.output_dir, 'artifact1')
555
Alex Klein231d2da2019-07-22 16:44:45 -0600556
Tiancong Wang24a3df72019-08-20 15:48:51 -0700557_VALID_ARTIFACT_TYPES = [toolchain_pb2.BENCHMARK_AFDO,
558 toolchain_pb2.ORDERFILE]
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700559@faux.success(_BundleAFDOGenerationArtifactsResponse)
560@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600561@validate.require('build_target.name', 'output_dir')
Tiancong Wang50b80a92019-08-01 14:46:15 -0700562@validate.is_in('artifact_type', _VALID_ARTIFACT_TYPES)
Alex Klein231d2da2019-07-22 16:44:45 -0600563@validate.exists('output_dir')
Tiancong Wang2ade7932019-09-27 14:15:40 -0700564@validate.exists('chroot.chrome_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600565@validate.validation_complete
Tiancong Wang50b80a92019-08-01 14:46:15 -0700566def BundleAFDOGenerationArtifacts(input_proto, output_proto, _config):
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700567 """Generic function for creating tarballs of both AFDO and orderfile.
Tiancong Wangc4805b72019-06-11 12:12:03 -0700568
569 Args:
Tiancong Wang50b80a92019-08-01 14:46:15 -0700570 input_proto (BundleChromeAFDORequest): The input proto.
Tiancong Wangc4805b72019-06-11 12:12:03 -0700571 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600572 _config (api_config.ApiConfig): The API call config.
Tiancong Wangc4805b72019-06-11 12:12:03 -0700573 """
Tiancong Wang2ade7932019-09-27 14:15:40 -0700574 chrome_root = input_proto.chroot.chrome_dir
Tiancong Wangc4805b72019-06-11 12:12:03 -0700575 output_dir = input_proto.output_dir
Tiancong Wang50b80a92019-08-01 14:46:15 -0700576 artifact_type = input_proto.artifact_type
Tiancong Wangc4805b72019-06-11 12:12:03 -0700577
Alex Klein26e472b2020-03-10 14:35:01 -0600578 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
Tiancong Wangc4805b72019-06-11 12:12:03 -0700579 chroot = controller_util.ParseChroot(input_proto.chroot)
580
581 try:
Tiancong Wang24a3df72019-08-20 15:48:51 -0700582 is_orderfile = bool(artifact_type is toolchain_pb2.ORDERFILE)
Tiancong Wang50b80a92019-08-01 14:46:15 -0700583 results = artifacts.BundleAFDOGenerationArtifacts(
Tiancong Wang2ade7932019-09-27 14:15:40 -0700584 is_orderfile, chroot, chrome_root,
Tiancong Wang50b80a92019-08-01 14:46:15 -0700585 build_target, output_dir)
Tiancong Wangc4805b72019-06-11 12:12:03 -0700586 except artifacts.Error as e:
587 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
588 type(e), e)
589
590 for file_name in results:
591 output_proto.artifacts.add().path = file_name
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600592
593
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700594def _ExportCpeReportResponse(input_proto, output_proto, _config):
595 """Add test cpe results to a successful response."""
596 output_proto.artifacts.add().path = os.path.join(
597 input_proto.output_dir, 'cpe_report.txt')
598 output_proto.artifacts.add().path = os.path.join(
599 input_proto.output_dir, 'cpe_warnings.txt')
600
601
602@faux.success(_ExportCpeReportResponse)
603@faux.empty_error
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600604@validate.exists('output_dir')
605def ExportCpeReport(input_proto, output_proto, config):
606 """Export a CPE report.
607
608 Args:
609 input_proto (BundleRequest): The input proto.
610 output_proto (BundleResponse): The output proto.
611 config (api_config.ApiConfig): The API call config.
612 """
613 chroot = controller_util.ParseChroot(input_proto.chroot)
614 output_dir = input_proto.output_dir
615
616 if input_proto.build_target.name:
617 # Legacy handling - use the default sysroot path for the build target.
618 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
619 sysroot = sysroot_lib.Sysroot(build_target.root)
620 elif input_proto.sysroot.path:
621 sysroot = sysroot_lib.Sysroot(input_proto.sysroot.path)
622 else:
623 # TODO(saklein): Switch to validate decorators once legacy handling can be
624 # cleaned up.
625 cros_build_lib.Die('sysroot.path is required.')
626
627 if config.validate_only:
628 return controller.RETURN_CODE_VALID_INPUT
629
630 cpe_result = artifacts.GenerateCpeReport(chroot, sysroot, output_dir)
631
632 output_proto.artifacts.add().path = cpe_result.report
633 output_proto.artifacts.add().path = cpe_result.warnings