blob: 26de0f0af1c4c716f65be88a6e388a9f75121b97 [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
Evan Hernandezf388cbf2019-04-01 11:15:23 -060017from chromite.cbuildbot import commands
Alex Klein2275d692019-04-23 16:04:12 -060018from chromite.lib import chroot_lib
Evan Hernandezf388cbf2019-04-01 11:15:23 -060019from chromite.lib import constants
20from chromite.lib import cros_build_lib
Evan Hernandezde445982019-04-22 13:42:34 -060021from chromite.lib import cros_logging as logging
Alex Klein2275d692019-04-23 16:04:12 -060022from chromite.lib import sysroot_lib
23from chromite.service import artifacts
Evan Hernandezf388cbf2019-04-01 11:15:23 -060024
25
Evan Hernandez9f125ac2019-04-08 17:18:47 -060026def _GetImageDir(build_root, target):
27 """Return path containing images for the given build target.
28
Alex Kleine2612a02019-04-18 13:51:06 -060029 TODO(saklein) Expand image_lib.GetLatestImageLink to support this use case.
30
Evan Hernandez9f125ac2019-04-08 17:18:47 -060031 Args:
32 build_root (str): Path to checkout where build occurs.
33 target (str): Name of the build target.
34
35 Returns:
Alex Kleind2bf1462019-10-24 16:37:04 -060036 Path to the latest directory containing target images or None.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060037 """
38 image_dir = os.path.join(build_root, 'src/build/images', target, 'latest')
39 if not os.path.exists(image_dir):
Alex Kleind2bf1462019-10-24 16:37:04 -060040 logging.warning('Expected to find image output for target %s at %s, but '
41 'path does not exist', target, image_dir)
42 return None
43
Evan Hernandez9f125ac2019-04-08 17:18:47 -060044 return image_dir
45
46
Michael Mortensen2d6a2402019-11-26 13:40:40 -070047def _BundleImageArchivesResponse(input_proto, output_proto, _config):
48 """Add artifact paths to a successful response."""
49 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
50 'path0.tar.xz')
51 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
52 'path1.tar.xz')
53
54
55@faux.success(_BundleImageArchivesResponse)
56@faux.empty_error
Alex Kleind91e95a2019-09-17 10:39:02 -060057@validate.require('build_target.name')
58@validate.exists('output_dir')
59@validate.validation_complete
60def BundleImageArchives(input_proto, output_proto, _config):
61 """Create a .tar.xz archive for each image that has been created."""
62 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
63 output_dir = input_proto.output_dir
64 image_dir = _GetImageDir(constants.SOURCE_ROOT, build_target.name)
Alex Kleind2bf1462019-10-24 16:37:04 -060065 if image_dir is None:
66 return
Alex Kleind91e95a2019-09-17 10:39:02 -060067
68 archives = artifacts.ArchiveImages(image_dir, output_dir)
69
70 for archive in archives:
71 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
72
73
Michael Mortensen2d6a2402019-11-26 13:40:40 -070074def _BundleImageZipResponse(input_proto, output_proto, _config):
75 """Add artifact zip files to a successful response."""
76 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
77 'image.zip')
78
79
80@faux.success(_BundleImageZipResponse)
81@faux.empty_error
Michael Mortensen01910922019-07-24 14:48:10 -060082@validate.require('build_target.name', 'output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -060083@validate.exists('output_dir')
84@validate.validation_complete
85def BundleImageZip(input_proto, output_proto, _config):
Evan Hernandez9f125ac2019-04-08 17:18:47 -060086 """Bundle image.zip.
87
88 Args:
89 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -060090 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -060091 _config (api_config.ApiConfig): The API call config.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060092 """
93 target = input_proto.build_target.name
94 output_dir = input_proto.output_dir
95 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
Alex Kleind2bf1462019-10-24 16:37:04 -060096 if image_dir is None:
97 return None
Alex Klein231d2da2019-07-22 16:44:45 -060098
Michael Mortensen01910922019-07-24 14:48:10 -060099 archive = artifacts.BundleImageZip(output_dir, image_dir)
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600100 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
101
102
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700103def _BundleTestUpdatePayloadsResponse(input_proto, output_proto, _config):
104 """Add test payload files to a successful response."""
105 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
106 'payload1.bin')
107
108
109@faux.success(_BundleTestUpdatePayloadsResponse)
110@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600111@validate.require('build_target.name', 'output_dir')
112@validate.exists('output_dir')
113@validate.validation_complete
114def BundleTestUpdatePayloads(input_proto, output_proto, _config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600115 """Generate minimal update payloads for the build target for testing.
116
117 Args:
118 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600119 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600120 _config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600121 """
122 target = input_proto.build_target.name
123 output_dir = input_proto.output_dir
124 build_root = constants.SOURCE_ROOT
125
126 # Use the first available image to create the update payload.
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600127 img_dir = _GetImageDir(build_root, target)
Alex Kleind2bf1462019-10-24 16:37:04 -0600128 if img_dir is None:
129 return None
130
Alex Kleincb541e82019-06-26 15:06:11 -0600131 img_types = [constants.IMAGE_TYPE_TEST, constants.IMAGE_TYPE_DEV,
132 constants.IMAGE_TYPE_BASE]
133 img_names = [constants.IMAGE_TYPE_TO_NAME[t] for t in img_types]
Mike Frysinger66ce4132019-07-17 22:52:52 -0400134 img_paths = [os.path.join(img_dir, x) for x in img_names]
Mike Frysingera552be42018-08-17 14:39:32 -0400135 valid_images = [x for x in img_paths if os.path.exists(x)]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600136
Alex Kleincb541e82019-06-26 15:06:11 -0600137 if not valid_images:
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600138 cros_build_lib.Die(
139 'Expected to find an image of type among %r for target "%s" '
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600140 'at path %s.', img_types, target, img_dir)
Alex Kleincb541e82019-06-26 15:06:11 -0600141 image = valid_images[0]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600142
Alex Kleincb541e82019-06-26 15:06:11 -0600143 payloads = artifacts.BundleTestUpdatePayloads(image, output_dir)
144 for payload in payloads:
145 output_proto.artifacts.add().path = payload
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600146
147
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700148def _BundleAutotestFilesResponse(input_proto, output_proto, _config):
149 """Add test autotest files to a successful response."""
150 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
151 'autotest-a.tar.gz')
152
153
154@faux.success(_BundleAutotestFilesResponse)
155@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600156@validate.require('output_dir')
157@validate.exists('output_dir')
158def BundleAutotestFiles(input_proto, output_proto, config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600159 """Tar the autotest files for a build target.
160
161 Args:
162 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600163 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600164 config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600165 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600166 output_dir = input_proto.output_dir
Alex Klein238d8862019-05-07 11:32:46 -0600167 target = input_proto.build_target.name
Alex Kleine21a0952019-08-23 16:08:16 -0600168 chroot = controller_util.ParseChroot(input_proto.chroot)
169
Alex Klein238d8862019-05-07 11:32:46 -0600170 if target:
Alex Kleine21a0952019-08-23 16:08:16 -0600171 sysroot_path = os.path.join('/build', target)
Alex Klein238d8862019-05-07 11:32:46 -0600172 else:
173 # New style call, use chroot and sysroot.
Alex Klein238d8862019-05-07 11:32:46 -0600174 sysroot_path = input_proto.sysroot.path
175 if not sysroot_path:
176 cros_build_lib.Die('sysroot.path is required.')
177
Alex Kleine21a0952019-08-23 16:08:16 -0600178 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Klein238d8862019-05-07 11:32:46 -0600179
Alex Klein231d2da2019-07-22 16:44:45 -0600180 # TODO(saklein): Switch to the validate_only decorator when legacy handling
181 # is removed.
182 if config.validate_only:
183 return controller.RETURN_CODE_VALID_INPUT
184
Alex Kleine21a0952019-08-23 16:08:16 -0600185 if not sysroot.Exists(chroot=chroot):
Alex Klein238d8862019-05-07 11:32:46 -0600186 cros_build_lib.Die('Sysroot path must exist: %s', sysroot.path)
187
188 try:
189 # Note that this returns the full path to *multiple* tarballs.
Alex Kleine21a0952019-08-23 16:08:16 -0600190 archives = artifacts.BundleAutotestFiles(chroot, sysroot, output_dir)
Alex Klein238d8862019-05-07 11:32:46 -0600191 except artifacts.Error as e:
Alex Klein03890312020-06-30 09:59:50 -0600192 logging.warning(e)
193 return
Alex Klein238d8862019-05-07 11:32:46 -0600194
195 for archive in archives.values():
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600196 output_proto.artifacts.add().path = archive
197
198
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700199def _BundleTastFilesResponse(input_proto, output_proto, _config):
200 """Add test tast files to a successful response."""
201 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
202 'tast_bundles.tar.gz')
203
204
205@faux.success(_BundleTastFilesResponse)
206@faux.empty_error
Alex Kleinb9d810b2019-07-01 12:38:02 -0600207@validate.require('output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600208@validate.exists('output_dir')
209def BundleTastFiles(input_proto, output_proto, config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600210 """Tar the tast files for a build target.
211
212 Args:
213 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600214 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600215 config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600216 """
217 target = input_proto.build_target.name
218 output_dir = input_proto.output_dir
219 build_root = constants.SOURCE_ROOT
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600220
Alex Kleinb9d810b2019-07-01 12:38:02 -0600221 chroot = controller_util.ParseChroot(input_proto.chroot)
222 sysroot_path = input_proto.sysroot.path
223
224 # TODO(saklein) Cleanup legacy handling after it has been switched over.
225 if target:
226 # Legacy handling.
Alex Klein171da612019-08-06 14:00:42 -0600227 chroot = chroot_lib.Chroot(path=os.path.join(build_root, 'chroot'))
Alex Kleinb9d810b2019-07-01 12:38:02 -0600228 sysroot_path = os.path.join('/build', target)
229
230 # New handling - chroot & sysroot based.
231 # TODO(saklein) Switch this to the require decorator when legacy is removed.
232 if not sysroot_path:
233 cros_build_lib.Die('sysroot.path is required.')
234
Alex Klein231d2da2019-07-22 16:44:45 -0600235 # TODO(saklein): Switch to the validation_complete decorator when legacy
236 # handling is removed.
237 if config.validate_only:
238 return controller.RETURN_CODE_VALID_INPUT
239
Alex Kleinb9d810b2019-07-01 12:38:02 -0600240 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Klein231d2da2019-07-22 16:44:45 -0600241 if not sysroot.Exists(chroot=chroot):
Alex Kleinb9d810b2019-07-01 12:38:02 -0600242 cros_build_lib.Die('Sysroot must exist.')
243
244 archive = artifacts.BundleTastFiles(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600245
LaMont Jonesb9793cd2020-06-11 08:14:46 -0600246 if archive:
247 output_proto.artifacts.add().path = archive
248 else:
249 logging.warning('Found no tast files for %s.', target)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600250
251
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700252def _BundlePinnedGuestImagesResponse(input_proto, output_proto, _config):
253 """Add test pinned guest image files to a successful response."""
254 output_proto.artifacts.add().path = os.path.join(
255 input_proto.output_dir, 'pinned-guest-images.tar.gz')
256
257
258@faux.success(_BundlePinnedGuestImagesResponse)
259@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600260@validate.require('build_target.name', 'output_dir')
261@validate.exists('output_dir')
262@validate.validation_complete
263def BundlePinnedGuestImages(input_proto, output_proto, _config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600264 """Tar the pinned guest images for a build target.
265
266 Args:
267 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600268 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600269 _config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600270 """
271 target = input_proto.build_target.name
272 output_dir = input_proto.output_dir
273 build_root = constants.SOURCE_ROOT
274
Alex Kleine2612a02019-04-18 13:51:06 -0600275 # TODO(crbug.com/954299): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600276 archive = commands.BuildPinnedGuestImagesTarball(build_root, target,
277 output_dir)
278
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600279 if archive is None:
Evan Hernandezde445982019-04-22 13:42:34 -0600280 logging.warning('Found no pinned guest images for %s.', target)
281 return
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600282
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600283 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
284
285
Alex Kleinc3e8d0c2020-05-15 11:20:22 -0600286def _FetchPinnedGuestImageUrisResponse(_input_proto, output_proto, _config):
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700287 """Add test fetched pinned guest image files to a successful response."""
288 pinned_image = output_proto.pinned_images.add()
289 pinned_image.filename = 'pinned_file.tar.gz'
290 pinned_image.uri = 'https://testuri.com'
291
292
Alex Kleinc3e8d0c2020-05-15 11:20:22 -0600293@faux.success(_FetchPinnedGuestImageUrisResponse)
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700294@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600295@validate.require('sysroot.path')
296@validate.validation_complete
Alex Kleinc3e8d0c2020-05-15 11:20:22 -0600297def FetchPinnedGuestImageUris(input_proto, output_proto, _config):
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600298 """Get the pinned guest image information."""
299 sysroot_path = input_proto.sysroot.path
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600300
301 chroot = controller_util.ParseChroot(input_proto.chroot)
302 sysroot = sysroot_lib.Sysroot(sysroot_path)
303
304 if not chroot.exists():
305 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
Alex Klein231d2da2019-07-22 16:44:45 -0600306 elif not sysroot.Exists(chroot=chroot):
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600307 cros_build_lib.Die('Sysroot does not exist: %s',
308 chroot.full_path(sysroot.path))
309
310 pins = artifacts.FetchPinnedGuestImages(chroot, sysroot)
311
312 for pin in pins:
313 pinned_image = output_proto.pinned_images.add()
314 pinned_image.filename = pin.filename
315 pinned_image.uri = pin.uri
316
317
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700318def _BundleFirmwareResponse(input_proto, output_proto, _config):
319 """Add test firmware image files to a successful response."""
320 output_proto.artifacts.add().path = os.path.join(
321 input_proto.output_dir, 'firmware.tar.gz')
322
323
324@faux.success(_BundleFirmwareResponse)
325@faux.empty_error
Michael Mortensen38675192019-06-28 16:52:55 +0000326@validate.require('output_dir', 'sysroot.path')
Alex Klein231d2da2019-07-22 16:44:45 -0600327@validate.exists('output_dir')
328@validate.validation_complete
329def BundleFirmware(input_proto, output_proto, _config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600330 """Tar the firmware images for a build target.
331
332 Args:
333 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600334 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600335 _config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600336 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600337 output_dir = input_proto.output_dir
Michael Mortensen38675192019-06-28 16:52:55 +0000338 chroot = controller_util.ParseChroot(input_proto.chroot)
339 sysroot_path = input_proto.sysroot.path
340 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Klein231d2da2019-07-22 16:44:45 -0600341
342 if not chroot.exists():
343 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
344 elif not sysroot.Exists(chroot=chroot):
345 cros_build_lib.Die('Sysroot does not exist: %s',
346 chroot.full_path(sysroot.path))
347
Michael Mortensen38675192019-06-28 16:52:55 +0000348 archive = artifacts.BuildFirmwareArchive(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600349
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600350 if archive is None:
351 cros_build_lib.Die(
Michael Mortensen38675192019-06-28 16:52:55 +0000352 'Could not create firmware archive. No firmware found for %s.',
353 sysroot_path)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600354
Alex Klein231d2da2019-07-22 16:44:45 -0600355 output_proto.artifacts.add().path = archive
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600356
357
Yicheng Liea1181f2020-09-22 11:51:10 -0700358def _BundleFpmcuUnittestsResponse(input_proto, output_proto, _config):
359 """Add fingerprint MCU unittest binaries to a successful response."""
360 output_proto.artifacts.add().path = os.path.join(
361 input_proto.output_dir, 'fpmcu_unittests.tar.gz')
362
363
364@faux.success(_BundleFpmcuUnittestsResponse)
365@faux.empty_error
366@validate.require('output_dir', 'sysroot.path')
367@validate.exists('output_dir')
368@validate.validation_complete
369def BundleFpmcuUnittests(input_proto, output_proto, _config):
370 """Tar the fingerprint MCU unittest binaries for a build target.
371
372 Args:
373 input_proto (BundleRequest): The input proto.
374 output_proto (BundleResponse): The output proto.
375 _config (api_config.ApiConfig): The API call config.
376 """
377 output_dir = input_proto.output_dir
378 chroot = controller_util.ParseChroot(input_proto.chroot)
379 sysroot_path = input_proto.sysroot.path
380 sysroot = sysroot_lib.Sysroot(sysroot_path)
381
382 if not chroot.exists():
383 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
384 elif not sysroot.Exists(chroot=chroot):
385 cros_build_lib.Die('Sysroot does not exist: %s',
386 chroot.full_path(sysroot.path))
387
388 archive = artifacts.BundleFpmcuUnittests(chroot, sysroot, output_dir)
389
390 if archive is None:
391 logging.warning(
392 'No fpmcu unittests found for %s.', sysroot_path)
393 return
394
395 output_proto.artifacts.add().path = archive
396
397
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700398def _BundleEbuildLogsResponse(input_proto, output_proto, _config):
399 """Add test log files to a successful response."""
400 output_proto.artifacts.add().path = os.path.join(
401 input_proto.output_dir, 'ebuild-logs.tar.gz')
402
403
404@faux.success(_BundleEbuildLogsResponse)
405@faux.empty_error
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600406@validate.exists('output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600407def BundleEbuildLogs(input_proto, output_proto, config):
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600408 """Tar the ebuild logs for a build target.
409
410 Args:
411 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600412 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600413 config (api_config.ApiConfig): The API call config.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600414 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600415 output_dir = input_proto.output_dir
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600416 sysroot_path = input_proto.sysroot.path
417 chroot = controller_util.ParseChroot(input_proto.chroot)
Evan Hernandeza478d802019-04-08 15:08:24 -0600418
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600419 # TODO(mmortensen) Cleanup legacy handling after it has been switched over.
420 target = input_proto.build_target.name
421 if target:
422 # Legacy handling.
423 build_root = constants.SOURCE_ROOT
Alex Klein171da612019-08-06 14:00:42 -0600424 chroot = chroot_lib.Chroot(path=os.path.join(build_root, 'chroot'))
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600425 sysroot_path = os.path.join('/build', target)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600426
Alex Klein231d2da2019-07-22 16:44:45 -0600427 # TODO(saklein): Switch to validation_complete decorator after legacy
428 # handling has been cleaned up.
429 if config.validate_only:
430 return controller.RETURN_CODE_VALID_INPUT
431
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600432 sysroot = sysroot_lib.Sysroot(sysroot_path)
433 archive = artifacts.BundleEBuildLogsTarball(chroot, sysroot, output_dir)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600434 if archive is None:
435 cros_build_lib.Die(
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600436 'Could not create ebuild logs archive. No logs found for %s.',
437 sysroot.path)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600438 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Klein6504eca2019-04-18 15:37:56 -0600439
440
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700441def _BundleChromeOSConfigResponse(input_proto, output_proto, _config):
442 """Add test config files to a successful response."""
443 output_proto.artifacts.add().path = os.path.join(
444 input_proto.output_dir, 'config.yaml')
445
446
447@faux.success(_BundleChromeOSConfigResponse)
448@faux.empty_error
Andrew Lamb811aead2019-08-12 10:25:05 -0600449@validate.exists('output_dir')
450@validate.validation_complete
451def BundleChromeOSConfig(input_proto, output_proto, _config):
452 """Output the ChromeOS Config payload for a build target.
453
454 Args:
455 input_proto (BundleRequest): The input proto.
456 output_proto (BundleResponse): The output proto.
457 _config (api_config.ApiConfig): The API call config.
458 """
459 output_dir = input_proto.output_dir
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600460 sysroot_path = input_proto.sysroot.path
Andrew Lamb811aead2019-08-12 10:25:05 -0600461 chroot = controller_util.ParseChroot(input_proto.chroot)
462
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600463 # TODO(mmortensen) Cleanup legacy handling after it has been switched over.
464 target = input_proto.build_target.name
465 if target:
466 # Legacy handling.
467 build_root = constants.SOURCE_ROOT
468 chroot = chroot_lib.Chroot(path=os.path.join(build_root, 'chroot'))
469 sysroot_path = os.path.join('/build', target)
470
471 sysroot = sysroot_lib.Sysroot(sysroot_path)
Andrew Lamb811aead2019-08-12 10:25:05 -0600472 chromeos_config = artifacts.BundleChromeOSConfig(chroot, sysroot, output_dir)
473 if chromeos_config is None:
474 cros_build_lib.Die(
475 'Could not create ChromeOS Config payload. No config found for %s.',
476 sysroot.path)
477 output_proto.artifacts.add().path = os.path.join(output_dir, chromeos_config)
478
479
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700480def _BundleSimpleChromeArtifactsResponse(input_proto, output_proto, _config):
481 """Add test simple chrome files to a successful response."""
482 output_proto.artifacts.add().path = os.path.join(
483 input_proto.output_dir, 'simple_chrome.txt')
484
485
486@faux.success(_BundleSimpleChromeArtifactsResponse)
487@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600488@validate.require('output_dir', 'sysroot.build_target.name', 'sysroot.path')
489@validate.exists('output_dir')
490@validate.validation_complete
491def BundleSimpleChromeArtifacts(input_proto, output_proto, _config):
Alex Klein2275d692019-04-23 16:04:12 -0600492 """Create the simple chrome artifacts."""
Alex Klein2275d692019-04-23 16:04:12 -0600493 sysroot_path = input_proto.sysroot.path
Alex Klein2275d692019-04-23 16:04:12 -0600494 output_dir = input_proto.output_dir
495
Alex Klein2275d692019-04-23 16:04:12 -0600496 # Build out the argument instances.
Alex Klein26e472b2020-03-10 14:35:01 -0600497 build_target = controller_util.ParseBuildTarget(
498 input_proto.sysroot.build_target)
499 chroot = controller_util.ParseChroot(input_proto.chroot)
Alex Klein2275d692019-04-23 16:04:12 -0600500 # Sysroot.path needs to be the fully qualified path, including the chroot.
501 full_sysroot_path = os.path.join(chroot.path, sysroot_path.lstrip(os.sep))
502 sysroot = sysroot_lib.Sysroot(full_sysroot_path)
503
504 # Quick sanity check that the sysroot exists before we go on.
505 if not sysroot.Exists():
506 cros_build_lib.Die('The sysroot does not exist.')
507
508 try:
509 results = artifacts.BundleSimpleChromeArtifacts(chroot, sysroot,
510 build_target, output_dir)
511 except artifacts.Error as e:
512 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
513 type(e), e)
514
515 for file_name in results:
516 output_proto.artifacts.add().path = file_name
517
518
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700519def _BundleVmFilesResponse(input_proto, output_proto, _config):
520 """Add test vm files to a successful response."""
521 output_proto.artifacts.add().path = os.path.join(
522 input_proto.output_dir, 'f1.tar')
523
524
525@faux.success(_BundleVmFilesResponse)
526@faux.empty_error
Michael Mortensen51f06722019-07-18 09:55:50 -0600527@validate.require('chroot.path', 'test_results_dir', 'output_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600528@validate.exists('output_dir')
529@validate.validation_complete
530def BundleVmFiles(input_proto, output_proto, _config):
Alex Klein6504eca2019-04-18 15:37:56 -0600531 """Tar VM disk and memory files.
532
533 Args:
Trent Begin008cade2019-10-31 13:40:59 -0600534 input_proto (BundleVmFilesRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600535 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600536 _config (api_config.ApiConfig): The API call config.
Alex Klein6504eca2019-04-18 15:37:56 -0600537 """
Michael Mortensen51f06722019-07-18 09:55:50 -0600538 chroot = controller_util.ParseChroot(input_proto.chroot)
539 test_results_dir = input_proto.test_results_dir
Alex Klein6504eca2019-04-18 15:37:56 -0600540 output_dir = input_proto.output_dir
541
Michael Mortensen51f06722019-07-18 09:55:50 -0600542 archives = artifacts.BundleVmFiles(
543 chroot, test_results_dir, output_dir)
Alex Klein6504eca2019-04-18 15:37:56 -0600544 for archive in archives:
545 output_proto.artifacts.add().path = archive
Tiancong Wangc4805b72019-06-11 12:12:03 -0700546
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700547def _BundleAFDOGenerationArtifactsResponse(input_proto, output_proto, _config):
548 """Add test tarball AFDO file to a successful response."""
549 output_proto.artifacts.add().path = os.path.join(
550 input_proto.output_dir, 'artifact1')
551
Alex Klein231d2da2019-07-22 16:44:45 -0600552
Tiancong Wang24a3df72019-08-20 15:48:51 -0700553_VALID_ARTIFACT_TYPES = [toolchain_pb2.BENCHMARK_AFDO,
554 toolchain_pb2.ORDERFILE]
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700555@faux.success(_BundleAFDOGenerationArtifactsResponse)
556@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600557@validate.require('build_target.name', 'output_dir')
Tiancong Wang50b80a92019-08-01 14:46:15 -0700558@validate.is_in('artifact_type', _VALID_ARTIFACT_TYPES)
Alex Klein231d2da2019-07-22 16:44:45 -0600559@validate.exists('output_dir')
Tiancong Wang2ade7932019-09-27 14:15:40 -0700560@validate.exists('chroot.chrome_dir')
Alex Klein231d2da2019-07-22 16:44:45 -0600561@validate.validation_complete
Tiancong Wang50b80a92019-08-01 14:46:15 -0700562def BundleAFDOGenerationArtifacts(input_proto, output_proto, _config):
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700563 """Generic function for creating tarballs of both AFDO and orderfile.
Tiancong Wangc4805b72019-06-11 12:12:03 -0700564
565 Args:
Tiancong Wang50b80a92019-08-01 14:46:15 -0700566 input_proto (BundleChromeAFDORequest): The input proto.
Tiancong Wangc4805b72019-06-11 12:12:03 -0700567 output_proto (BundleResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600568 _config (api_config.ApiConfig): The API call config.
Tiancong Wangc4805b72019-06-11 12:12:03 -0700569 """
Tiancong Wang2ade7932019-09-27 14:15:40 -0700570 chrome_root = input_proto.chroot.chrome_dir
Tiancong Wangc4805b72019-06-11 12:12:03 -0700571 output_dir = input_proto.output_dir
Tiancong Wang50b80a92019-08-01 14:46:15 -0700572 artifact_type = input_proto.artifact_type
Tiancong Wangc4805b72019-06-11 12:12:03 -0700573
Alex Klein26e472b2020-03-10 14:35:01 -0600574 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
Tiancong Wangc4805b72019-06-11 12:12:03 -0700575 chroot = controller_util.ParseChroot(input_proto.chroot)
576
577 try:
Tiancong Wang24a3df72019-08-20 15:48:51 -0700578 is_orderfile = bool(artifact_type is toolchain_pb2.ORDERFILE)
Tiancong Wang50b80a92019-08-01 14:46:15 -0700579 results = artifacts.BundleAFDOGenerationArtifacts(
Tiancong Wang2ade7932019-09-27 14:15:40 -0700580 is_orderfile, chroot, chrome_root,
Tiancong Wang50b80a92019-08-01 14:46:15 -0700581 build_target, output_dir)
Tiancong Wangc4805b72019-06-11 12:12:03 -0700582 except artifacts.Error as e:
583 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
584 type(e), e)
585
586 for file_name in results:
587 output_proto.artifacts.add().path = file_name
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600588
589
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700590def _ExportCpeReportResponse(input_proto, output_proto, _config):
591 """Add test cpe results to a successful response."""
592 output_proto.artifacts.add().path = os.path.join(
593 input_proto.output_dir, 'cpe_report.txt')
594 output_proto.artifacts.add().path = os.path.join(
595 input_proto.output_dir, 'cpe_warnings.txt')
596
597
598@faux.success(_ExportCpeReportResponse)
599@faux.empty_error
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600600@validate.exists('output_dir')
601def ExportCpeReport(input_proto, output_proto, config):
602 """Export a CPE report.
603
604 Args:
605 input_proto (BundleRequest): The input proto.
606 output_proto (BundleResponse): The output proto.
607 config (api_config.ApiConfig): The API call config.
608 """
609 chroot = controller_util.ParseChroot(input_proto.chroot)
610 output_dir = input_proto.output_dir
611
612 if input_proto.build_target.name:
613 # Legacy handling - use the default sysroot path for the build target.
614 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
615 sysroot = sysroot_lib.Sysroot(build_target.root)
616 elif input_proto.sysroot.path:
617 sysroot = sysroot_lib.Sysroot(input_proto.sysroot.path)
618 else:
619 # TODO(saklein): Switch to validate decorators once legacy handling can be
620 # cleaned up.
621 cros_build_lib.Die('sysroot.path is required.')
622
623 if config.validate_only:
624 return controller.RETURN_CODE_VALID_INPUT
625
626 cpe_result = artifacts.GenerateCpeReport(chroot, sysroot, output_dir)
627
628 output_proto.artifacts.add().path = cpe_result.report
629 output_proto.artifacts.add().path = cpe_result.warnings
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +0900630
631
632def _BundleGceTarballResponse(input_proto, output_proto, _config):
633 """Add artifact tarball to a successful response."""
634 output_proto.artifacts.add().path = os.path.join(input_proto.output_dir,
635 constants.TEST_IMAGE_GCE_TAR)
636
637
638@faux.success(_BundleGceTarballResponse)
639@faux.empty_error
640@validate.require('build_target.name', 'output_dir')
641@validate.exists('output_dir')
642@validate.validation_complete
643def BundleGceTarball(input_proto, output_proto, _config):
644 """Bundle the test image into a tarball suitable for importing into GCE.
645
646 Args:
647 input_proto (BundleRequest): The input proto.
648 output_proto (BundleResponse): The output proto.
649 _config (api_config.ApiConfig): The API call config.
650 """
651 target = input_proto.build_target.name
652 output_dir = input_proto.output_dir
653 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
654 if image_dir is None:
655 return None
656
657 tarball = artifacts.BundleGceTarball(output_dir, image_dir)
658 output_proto.artifacts.add().path = tarball