blob: c7f37932a4b32d28353f0ac1f480953f18ad3eac [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 build_target_util
20from chromite.lib import chroot_lib
Evan Hernandezf388cbf2019-04-01 11:15:23 -060021from chromite.lib import constants
22from chromite.lib import cros_build_lib
Evan Hernandezde445982019-04-22 13:42:34 -060023from chromite.lib import cros_logging as logging
Alex Klein2275d692019-04-23 16:04:12 -060024from chromite.lib import sysroot_lib
25from chromite.service import artifacts
Evan Hernandezf388cbf2019-04-01 11:15:23 -060026
27
Mike Frysingeref94e4c2020-02-10 23:59:54 -050028assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
29
30
Evan Hernandez9f125ac2019-04-08 17:18:47 -060031def _GetImageDir(build_root, target):
32 """Return path containing images for the given build target.
33
Alex Kleine2612a02019-04-18 13:51:06 -060034 TODO(saklein) Expand image_lib.GetLatestImageLink to support this use case.
35
Evan Hernandez9f125ac2019-04-08 17:18:47 -060036 Args:
37 build_root (str): Path to checkout where build occurs.
38 target (str): Name of the build target.
39
40 Returns:
Alex Kleind2bf1462019-10-24 16:37:04 -060041 Path to the latest directory containing target images or None.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060042 """
43 image_dir = os.path.join(build_root, 'src/build/images', target, 'latest')
44 if not os.path.exists(image_dir):
Alex Kleind2bf1462019-10-24 16:37:04 -060045 logging.warning('Expected to find image output for target %s at %s, but '
46 'path does not exist', target, image_dir)
47 return None
48
Evan Hernandez9f125ac2019-04-08 17:18:47 -060049 return image_dir
50
51
Michael Mortensen2d6a2402019-11-26 13:40:40 -070052def _BundleImageArchivesResponse(input_proto, output_proto, _config):
53 """Add artifact paths to a successful response."""
54 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
55 'path0.tar.xz')
56 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
57 'path1.tar.xz')
58
59
60@faux.success(_BundleImageArchivesResponse)
61@faux.empty_error
Alex Kleind91e95a2019-09-17 10:39:02 -060062@validate.require('build_target.name')
63@validate.exists('output_dir')
64@validate.validation_complete
65def BundleImageArchives(input_proto, output_proto, _config):
66 """Create a .tar.xz archive for each image that has been created."""
67 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
68 output_dir = input_proto.output_dir
69 image_dir = _GetImageDir(constants.SOURCE_ROOT, build_target.name)
Alex Kleind2bf1462019-10-24 16:37:04 -060070 if image_dir is None:
71 return
Alex Kleind91e95a2019-09-17 10:39:02 -060072
73 archives = artifacts.ArchiveImages(image_dir, output_dir)
74
75 for archive in archives:
76 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
77
78
Michael Mortensen2d6a2402019-11-26 13:40:40 -070079def _BundleImageZipResponse(input_proto, output_proto, _config):
80 """Add artifact zip files to a successful response."""
81 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
82 'image.zip')
83
84
85@faux.success(_BundleImageZipResponse)
86@faux.empty_error
Michael Mortensen01910922019-07-24 14:48:10 -060087@validate.require('build_target.name', 'output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -060088@validate.exists('output_dir')
89@validate.validation_complete
90def BundleImageZip(input_proto, output_proto, _config):
Evan Hernandez9f125ac2019-04-08 17:18:47 -060091 """Bundle image.zip.
92
93 Args:
94 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -060095 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -060096 _config (api_config.ApiConfig): The API call config.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060097 """
98 target = input_proto.build_target.name
99 output_dir = input_proto.output_dir
100 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
Alex Kleind2bf1462019-10-24 16:37:04 -0600101 if image_dir is None:
102 return None
Alex Klein231d2da2019-07-22 16:44:45 -0600103
Michael Mortensen01910922019-07-24 14:48:10 -0600104 archive = artifacts.BundleImageZip(output_dir, image_dir)
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600105 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
106
107
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700108def _BundleTestUpdatePayloadsResponse(input_proto, output_proto, _config):
109 """Add test payload files to a successful response."""
110 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
111 'payload1.bin')
112
113
114@faux.success(_BundleTestUpdatePayloadsResponse)
115@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600116@validate.require('build_target.name', 'output_dir')
117@validate.exists('output_dir')
118@validate.validation_complete
119def BundleTestUpdatePayloads(input_proto, output_proto, _config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600120 """Generate minimal update payloads for the build target for testing.
121
122 Args:
123 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600124 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600125 _config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600126 """
127 target = input_proto.build_target.name
128 output_dir = input_proto.output_dir
129 build_root = constants.SOURCE_ROOT
130
131 # Use the first available image to create the update payload.
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600132 img_dir = _GetImageDir(build_root, target)
Alex Kleind2bf1462019-10-24 16:37:04 -0600133 if img_dir is None:
134 return None
135
Alex Kleincb541e82019-06-26 15:06:11 -0600136 img_types = [constants.IMAGE_TYPE_TEST, constants.IMAGE_TYPE_DEV,
137 constants.IMAGE_TYPE_BASE]
138 img_names = [constants.IMAGE_TYPE_TO_NAME[t] for t in img_types]
Mike Frysinger66ce4132019-07-17 22:52:52 -0400139 img_paths = [os.path.join(img_dir, x) for x in img_names]
Mike Frysingera552be42018-08-17 14:39:32 -0400140 valid_images = [x for x in img_paths if os.path.exists(x)]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600141
Alex Kleincb541e82019-06-26 15:06:11 -0600142 if not valid_images:
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600143 cros_build_lib.Die(
144 'Expected to find an image of type among %r for target "%s" '
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600145 'at path %s.', img_types, target, img_dir)
Alex Kleincb541e82019-06-26 15:06:11 -0600146 image = valid_images[0]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600147
Alex Kleincb541e82019-06-26 15:06:11 -0600148 payloads = artifacts.BundleTestUpdatePayloads(image, output_dir)
149 for payload in payloads:
150 output_proto.artifacts.add().path = payload
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600151
152
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700153def _BundleAutotestFilesResponse(input_proto, output_proto, _config):
154 """Add test autotest files to a successful response."""
155 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
156 'autotest-a.tar.gz')
157
158
159@faux.success(_BundleAutotestFilesResponse)
160@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600161@validate.require('output_dir')
162@validate.exists('output_dir')
163def BundleAutotestFiles(input_proto, output_proto, config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600164 """Tar the autotest files for a build target.
165
166 Args:
167 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600168 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600169 config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600170 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600171 output_dir = input_proto.output_dir
Alex Klein238d8862019-05-07 11:32:46 -0600172 target = input_proto.build_target.name
Alex Kleine21a0952019-08-23 16:08:16 -0600173 chroot = controller_util.ParseChroot(input_proto.chroot)
174
Alex Klein238d8862019-05-07 11:32:46 -0600175 if target:
Alex Kleine21a0952019-08-23 16:08:16 -0600176 sysroot_path = os.path.join('/build', target)
Alex Klein238d8862019-05-07 11:32:46 -0600177 else:
178 # New style call, use chroot and sysroot.
Alex Klein238d8862019-05-07 11:32:46 -0600179 sysroot_path = input_proto.sysroot.path
180 if not sysroot_path:
181 cros_build_lib.Die('sysroot.path is required.')
182
Alex Kleine21a0952019-08-23 16:08:16 -0600183 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Klein238d8862019-05-07 11:32:46 -0600184
Alex Klein231d2da2019-07-22 16:44:45 -0600185 # TODO(saklein): Switch to the validate_only decorator when legacy handling
186 # is removed.
187 if config.validate_only:
188 return controller.RETURN_CODE_VALID_INPUT
189
Alex Kleine21a0952019-08-23 16:08:16 -0600190 if not sysroot.Exists(chroot=chroot):
Alex Klein238d8862019-05-07 11:32:46 -0600191 cros_build_lib.Die('Sysroot path must exist: %s', sysroot.path)
192
193 try:
194 # Note that this returns the full path to *multiple* tarballs.
Alex Kleine21a0952019-08-23 16:08:16 -0600195 archives = artifacts.BundleAutotestFiles(chroot, sysroot, output_dir)
Alex Klein238d8862019-05-07 11:32:46 -0600196 except artifacts.Error as e:
Mike Frysinger6b5c3cd2019-08-27 16:51:00 -0400197 cros_build_lib.Die(e)
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
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600250 if archive is None:
251 cros_build_lib.Die(
252 'Could not bundle Tast files. '
253 'No Tast directories found for %s.', target)
254
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600255 output_proto.artifacts.add().path = archive
256
257
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700258def _BundlePinnedGuestImagesResponse(input_proto, output_proto, _config):
259 """Add test pinned guest image files to a successful response."""
260 output_proto.artifacts.add().path = os.path.join(
261 input_proto.output_dir, 'pinned-guest-images.tar.gz')
262
263
264@faux.success(_BundlePinnedGuestImagesResponse)
265@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600266@validate.require('build_target.name', 'output_dir')
267@validate.exists('output_dir')
268@validate.validation_complete
269def BundlePinnedGuestImages(input_proto, output_proto, _config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600270 """Tar the pinned guest images for a build target.
271
272 Args:
273 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600274 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600275 _config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600276 """
277 target = input_proto.build_target.name
278 output_dir = input_proto.output_dir
279 build_root = constants.SOURCE_ROOT
280
Alex Kleine2612a02019-04-18 13:51:06 -0600281 # TODO(crbug.com/954299): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600282 archive = commands.BuildPinnedGuestImagesTarball(build_root, target,
283 output_dir)
284
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600285 if archive is None:
Evan Hernandezde445982019-04-22 13:42:34 -0600286 logging.warning('Found no pinned guest images for %s.', target)
287 return
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600288
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600289 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
290
291
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700292def _FetchPinnedGuestImagesResponse(_input_proto, output_proto, _config):
293 """Add test fetched pinned guest image files to a successful response."""
294 pinned_image = output_proto.pinned_images.add()
295 pinned_image.filename = 'pinned_file.tar.gz'
296 pinned_image.uri = 'https://testuri.com'
297
298
299@faux.success(_FetchPinnedGuestImagesResponse)
300@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600301@validate.require('sysroot.path')
302@validate.validation_complete
303def FetchPinnedGuestImages(input_proto, output_proto, _config):
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600304 """Get the pinned guest image information."""
305 sysroot_path = input_proto.sysroot.path
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600306
307 chroot = controller_util.ParseChroot(input_proto.chroot)
308 sysroot = sysroot_lib.Sysroot(sysroot_path)
309
310 if not chroot.exists():
311 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
Alex Klein231d2da2019-07-22 16:44:45 -0600312 elif not sysroot.Exists(chroot=chroot):
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600313 cros_build_lib.Die('Sysroot does not exist: %s',
314 chroot.full_path(sysroot.path))
315
316 pins = artifacts.FetchPinnedGuestImages(chroot, sysroot)
317
318 for pin in pins:
319 pinned_image = output_proto.pinned_images.add()
320 pinned_image.filename = pin.filename
321 pinned_image.uri = pin.uri
322
323
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700324def _BundleFirmwareResponse(input_proto, output_proto, _config):
325 """Add test firmware image files to a successful response."""
326 output_proto.artifacts.add().path = os.path.join(
327 input_proto.output_dir, 'firmware.tar.gz')
328
329
330@faux.success(_BundleFirmwareResponse)
331@faux.empty_error
Michael Mortensen38675192019-06-28 16:52:55 +0000332@validate.require('output_dir', 'sysroot.path')
Alex Klein231d2da2019-07-22 16:44:45 -0600333@validate.exists('output_dir')
334@validate.validation_complete
335def BundleFirmware(input_proto, output_proto, _config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600336 """Tar the firmware images for a build target.
337
338 Args:
339 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600340 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600341 _config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600342 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600343 output_dir = input_proto.output_dir
Michael Mortensen38675192019-06-28 16:52:55 +0000344 chroot = controller_util.ParseChroot(input_proto.chroot)
345 sysroot_path = input_proto.sysroot.path
346 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Klein231d2da2019-07-22 16:44:45 -0600347
348 if not chroot.exists():
349 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
350 elif not sysroot.Exists(chroot=chroot):
351 cros_build_lib.Die('Sysroot does not exist: %s',
352 chroot.full_path(sysroot.path))
353
Michael Mortensen38675192019-06-28 16:52:55 +0000354 archive = artifacts.BuildFirmwareArchive(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600355
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600356 if archive is None:
357 cros_build_lib.Die(
Michael Mortensen38675192019-06-28 16:52:55 +0000358 'Could not create firmware archive. No firmware found for %s.',
359 sysroot_path)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600360
Alex Klein231d2da2019-07-22 16:44:45 -0600361 output_proto.artifacts.add().path = archive
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600362
363
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700364def _BundleEbuildLogsResponse(input_proto, output_proto, _config):
365 """Add test log files to a successful response."""
366 output_proto.artifacts.add().path = os.path.join(
367 input_proto.output_dir, 'ebuild-logs.tar.gz')
368
369
370@faux.success(_BundleEbuildLogsResponse)
371@faux.empty_error
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600372@validate.exists('output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600373def BundleEbuildLogs(input_proto, output_proto, config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600374 """Tar the ebuild logs for a build target.
375
376 Args:
377 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600378 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600379 config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600380 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600381 output_dir = input_proto.output_dir
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600382 sysroot_path = input_proto.sysroot.path
383 chroot = controller_util.ParseChroot(input_proto.chroot)
Evan Hernandeza478d802019-04-08 15:08:24 -0600384
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600385 # TODO(mmortensen) Cleanup legacy handling after it has been switched over.
386 target = input_proto.build_target.name
387 if target:
388 # Legacy handling.
389 build_root = constants.SOURCE_ROOT
Alex Klein171da612019-08-06 14:00:42 -0600390 chroot = chroot_lib.Chroot(path=os.path.join(build_root, 'chroot'))
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600391 sysroot_path = os.path.join('/build', target)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600392
Alex Klein231d2da2019-07-22 16:44:45 -0600393 # TODO(saklein): Switch to validation_complete decorator after legacy
394 # handling has been cleaned up.
395 if config.validate_only:
396 return controller.RETURN_CODE_VALID_INPUT
397
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600398 sysroot = sysroot_lib.Sysroot(sysroot_path)
399 archive = artifacts.BundleEBuildLogsTarball(chroot, sysroot, output_dir)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600400 if archive is None:
401 cros_build_lib.Die(
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600402 'Could not create ebuild logs archive. No logs found for %s.',
403 sysroot.path)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600404 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Klein6504eca2019-04-18 15:37:56 -0600405
406
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700407def _BundleChromeOSConfigResponse(input_proto, output_proto, _config):
408 """Add test config files to a successful response."""
409 output_proto.artifacts.add().path = os.path.join(
410 input_proto.output_dir, 'config.yaml')
411
412
413@faux.success(_BundleChromeOSConfigResponse)
414@faux.empty_error
Andrew Lamb811aead2019-08-12 10:25:05 -0600415@validate.exists('output_dir')
416@validate.validation_complete
417def BundleChromeOSConfig(input_proto, output_proto, _config):
418 """Output the ChromeOS Config payload for a build target.
419
420 Args:
421 input_proto (BundleRequest): The input proto.
422 output_proto (BundleResponse): The output proto.
423 _config (api_config.ApiConfig): The API call config.
424 """
425 output_dir = input_proto.output_dir
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600426 sysroot_path = input_proto.sysroot.path
Andrew Lamb811aead2019-08-12 10:25:05 -0600427 chroot = controller_util.ParseChroot(input_proto.chroot)
428
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600429 # TODO(mmortensen) Cleanup legacy handling after it has been switched over.
430 target = input_proto.build_target.name
431 if target:
432 # Legacy handling.
433 build_root = constants.SOURCE_ROOT
434 chroot = chroot_lib.Chroot(path=os.path.join(build_root, 'chroot'))
435 sysroot_path = os.path.join('/build', target)
436
437 sysroot = sysroot_lib.Sysroot(sysroot_path)
Andrew Lamb811aead2019-08-12 10:25:05 -0600438 chromeos_config = artifacts.BundleChromeOSConfig(chroot, sysroot, output_dir)
439 if chromeos_config is None:
440 cros_build_lib.Die(
441 'Could not create ChromeOS Config payload. No config found for %s.',
442 sysroot.path)
443 output_proto.artifacts.add().path = os.path.join(output_dir, chromeos_config)
444
445
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700446def _BundleSimpleChromeArtifactsResponse(input_proto, output_proto, _config):
447 """Add test simple chrome files to a successful response."""
448 output_proto.artifacts.add().path = os.path.join(
449 input_proto.output_dir, 'simple_chrome.txt')
450
451
452@faux.success(_BundleSimpleChromeArtifactsResponse)
453@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600454@validate.require('output_dir', 'sysroot.build_target.name', 'sysroot.path')
455@validate.exists('output_dir')
456@validate.validation_complete
457def BundleSimpleChromeArtifacts(input_proto, output_proto, _config):
Alex Klein2275d692019-04-23 16:04:12 -0600458 """Create the simple chrome artifacts."""
459 # Required args.
460 sysroot_path = input_proto.sysroot.path
461 build_target_name = input_proto.sysroot.build_target.name
462 output_dir = input_proto.output_dir
463
Alex Klein2275d692019-04-23 16:04:12 -0600464 # Optional args.
465 chroot_path = input_proto.chroot.path or constants.DEFAULT_CHROOT_PATH
466 cache_dir = input_proto.chroot.cache_dir
467
468 # Build out the argument instances.
469 build_target = build_target_util.BuildTarget(build_target_name)
470 chroot = chroot_lib.Chroot(path=chroot_path, cache_dir=cache_dir)
471 # Sysroot.path needs to be the fully qualified path, including the chroot.
472 full_sysroot_path = os.path.join(chroot.path, sysroot_path.lstrip(os.sep))
473 sysroot = sysroot_lib.Sysroot(full_sysroot_path)
474
475 # Quick sanity check that the sysroot exists before we go on.
476 if not sysroot.Exists():
477 cros_build_lib.Die('The sysroot does not exist.')
478
479 try:
480 results = artifacts.BundleSimpleChromeArtifacts(chroot, sysroot,
481 build_target, output_dir)
482 except artifacts.Error as e:
483 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
484 type(e), e)
485
486 for file_name in results:
487 output_proto.artifacts.add().path = file_name
488
489
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700490def _BundleVmFilesResponse(input_proto, output_proto, _config):
491 """Add test vm files to a successful response."""
492 output_proto.artifacts.add().path = os.path.join(
493 input_proto.output_dir, 'f1.tar')
494
495
496@faux.success(_BundleVmFilesResponse)
497@faux.empty_error
Michael Mortensen51f06722019-07-18 09:55:50 -0600498@validate.require('chroot.path', 'test_results_dir', 'output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600499@validate.exists('output_dir')
500@validate.validation_complete
501def BundleVmFiles(input_proto, output_proto, _config):
Alex Klein6504eca2019-04-18 15:37:56 -0600502 """Tar VM disk and memory files.
503
504 Args:
Trent Begin008cade2019-10-31 13:40:59 -0600505 input_proto (BundleVmFilesRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600506 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600507 _config (api_config.ApiConfig): The API call config.
Alex Klein6504eca2019-04-18 15:37:56 -0600508 """
Michael Mortensen51f06722019-07-18 09:55:50 -0600509 chroot = controller_util.ParseChroot(input_proto.chroot)
510 test_results_dir = input_proto.test_results_dir
Alex Klein6504eca2019-04-18 15:37:56 -0600511 output_dir = input_proto.output_dir
512
Michael Mortensen51f06722019-07-18 09:55:50 -0600513 archives = artifacts.BundleVmFiles(
514 chroot, test_results_dir, output_dir)
Alex Klein6504eca2019-04-18 15:37:56 -0600515 for archive in archives:
516 output_proto.artifacts.add().path = archive
Tiancong Wangc4805b72019-06-11 12:12:03 -0700517
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700518def _BundleAFDOGenerationArtifactsResponse(input_proto, output_proto, _config):
519 """Add test tarball AFDO file to a successful response."""
520 output_proto.artifacts.add().path = os.path.join(
521 input_proto.output_dir, 'artifact1')
522
Alex Klein231d2da2019-07-22 16:44:45 -0600523
Tiancong Wang24a3df72019-08-20 15:48:51 -0700524_VALID_ARTIFACT_TYPES = [toolchain_pb2.BENCHMARK_AFDO,
525 toolchain_pb2.ORDERFILE]
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700526@faux.success(_BundleAFDOGenerationArtifactsResponse)
527@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600528@validate.require('build_target.name', 'output_dir')
Tiancong Wang50b80a92019-08-01 14:46:15 -0700529@validate.is_in('artifact_type', _VALID_ARTIFACT_TYPES)
Alex Klein231d2da2019-07-22 16:44:45 -0600530@validate.exists('output_dir')
Tiancong Wang2ade7932019-09-27 14:15:40 -0700531@validate.exists('chroot.chrome_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600532@validate.validation_complete
Tiancong Wang50b80a92019-08-01 14:46:15 -0700533def BundleAFDOGenerationArtifacts(input_proto, output_proto, _config):
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700534 """Generic function for creating tarballs of both AFDO and orderfile.
Tiancong Wangc4805b72019-06-11 12:12:03 -0700535
536 Args:
Tiancong Wang50b80a92019-08-01 14:46:15 -0700537 input_proto (BundleChromeAFDORequest): The input proto.
Tiancong Wangc4805b72019-06-11 12:12:03 -0700538 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600539 _config (api_config.ApiConfig): The API call config.
Tiancong Wangc4805b72019-06-11 12:12:03 -0700540 """
Tiancong Wang50b80a92019-08-01 14:46:15 -0700541
Tiancong Wangc4805b72019-06-11 12:12:03 -0700542 # Required args.
Alex Klein231d2da2019-07-22 16:44:45 -0600543 build_target = build_target_util.BuildTarget(input_proto.build_target.name)
Tiancong Wang2ade7932019-09-27 14:15:40 -0700544 chrome_root = input_proto.chroot.chrome_dir
545 if not chrome_root:
546 cros_build_lib.Die('chrome_root is not included in chroot')
Tiancong Wangc4805b72019-06-11 12:12:03 -0700547 output_dir = input_proto.output_dir
Tiancong Wang50b80a92019-08-01 14:46:15 -0700548 artifact_type = input_proto.artifact_type
Tiancong Wangc4805b72019-06-11 12:12:03 -0700549
Tiancong Wangc4805b72019-06-11 12:12:03 -0700550 chroot = controller_util.ParseChroot(input_proto.chroot)
551
552 try:
Tiancong Wang24a3df72019-08-20 15:48:51 -0700553 is_orderfile = bool(artifact_type is toolchain_pb2.ORDERFILE)
Tiancong Wang50b80a92019-08-01 14:46:15 -0700554 results = artifacts.BundleAFDOGenerationArtifacts(
Tiancong Wang2ade7932019-09-27 14:15:40 -0700555 is_orderfile, chroot, chrome_root,
Tiancong Wang50b80a92019-08-01 14:46:15 -0700556 build_target, output_dir)
Tiancong Wangc4805b72019-06-11 12:12:03 -0700557 except artifacts.Error as e:
558 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
559 type(e), e)
560
561 for file_name in results:
562 output_proto.artifacts.add().path = file_name
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600563
564
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700565def _ExportCpeReportResponse(input_proto, output_proto, _config):
566 """Add test cpe results to a successful response."""
567 output_proto.artifacts.add().path = os.path.join(
568 input_proto.output_dir, 'cpe_report.txt')
569 output_proto.artifacts.add().path = os.path.join(
570 input_proto.output_dir, 'cpe_warnings.txt')
571
572
573@faux.success(_ExportCpeReportResponse)
574@faux.empty_error
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600575@validate.exists('output_dir')
576def ExportCpeReport(input_proto, output_proto, config):
577 """Export a CPE report.
578
579 Args:
580 input_proto (BundleRequest): The input proto.
581 output_proto (BundleResponse): The output proto.
582 config (api_config.ApiConfig): The API call config.
583 """
584 chroot = controller_util.ParseChroot(input_proto.chroot)
585 output_dir = input_proto.output_dir
586
587 if input_proto.build_target.name:
588 # Legacy handling - use the default sysroot path for the build target.
589 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
590 sysroot = sysroot_lib.Sysroot(build_target.root)
591 elif input_proto.sysroot.path:
592 sysroot = sysroot_lib.Sysroot(input_proto.sysroot.path)
593 else:
594 # TODO(saklein): Switch to validate decorators once legacy handling can be
595 # cleaned up.
596 cros_build_lib.Die('sysroot.path is required.')
597
598 if config.validate_only:
599 return controller.RETURN_CODE_VALID_INPUT
600
601 cpe_result = artifacts.GenerateCpeReport(chroot, sysroot, output_dir)
602
603 output_proto.artifacts.add().path = cpe_result.report
604 output_proto.artifacts.add().path = cpe_result.warnings