blob: 3766db93d689250eb4542b6addb640658a5a0ecf [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2019 The ChromiumOS Authors
Evan Hernandezf388cbf2019-04-01 11:15:23 -06002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Implements ArtifactService."""
6
Chris McDonald1672ddb2021-07-21 11:48:23 -06007import logging
Evan Hernandezf388cbf2019-04-01 11:15:23 -06008import os
Varun Somani04dccd72021-10-09 01:06:11 +00009from typing import Any, NamedTuple, Optional, TYPE_CHECKING
Evan Hernandezf388cbf2019-04-01 11:15:23 -060010
Alex Klein231d2da2019-07-22 16:44:45 -060011from chromite.api import controller
Alex Klein076841b2019-08-29 15:19:39 -060012from chromite.api import faux
Alex Klein2b236722019-06-19 15:44:26 -060013from chromite.api import validate
Alex Klein238d8862019-05-07 11:32:46 -060014from chromite.api.controller import controller_util
George Engelbrechtc9a8e812021-06-16 18:14:17 -060015from chromite.api.controller import image as image_controller
16from chromite.api.controller import sysroot as sysroot_controller
David Wellingc1433c22021-06-25 16:29:48 +000017from chromite.api.controller import test as test_controller
LaMont Jones58362a42021-02-04 17:40:08 -070018from chromite.api.gen.chromite.api import artifacts_pb2
Jaques Clapauchf616bcd2021-04-09 20:14:40 +000019from chromite.api.gen.chromiumos import common_pb2
Evan Hernandezf388cbf2019-04-01 11:15:23 -060020from chromite.lib import constants
21from chromite.lib import cros_build_lib
Alex Klein2275d692019-04-23 16:04:12 -060022from chromite.lib import sysroot_lib
23from chromite.service import artifacts
Greg Edelstondc941072021-08-11 12:32:30 -060024from chromite.service import test
Evan Hernandezf388cbf2019-04-01 11:15:23 -060025
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040026
Varun Somani04dccd72021-10-09 01:06:11 +000027if TYPE_CHECKING:
Alex Klein1699fab2022-09-08 08:46:06 -060028 from chromite.api import api_config
29
Evan Hernandezf388cbf2019-04-01 11:15:23 -060030
George Engelbrechtc9a8e812021-06-16 18:14:17 -060031class RegisteredGet(NamedTuple):
Alex Kleinb6847e22022-11-07 10:44:48 -070032 """A registered function for calling Get on an artifact type."""
Alex Klein1699fab2022-09-08 08:46:06 -060033
34 output_proto: artifacts_pb2.GetResponse
35 artifact_dict: Any
LaMont Jones0f5171b2021-01-29 12:28:56 -070036
37
Alex Kleinb6847e22022-11-07 10:44:48 -070038def ExampleGetResponse(_input_proto, _output_proto, _config) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -060039 """Give an example GetResponse with a minimal coverage set."""
40 _output_proto = artifacts_pb2.GetResponse(
41 artifacts=common_pb2.UploadedArtifactsByService(
42 image=image_controller.ExampleGetResponse(),
43 sysroot=sysroot_controller.ExampleGetResponse(),
44 )
45 )
46 return controller.RETURN_CODE_SUCCESS
George Engelbrechtc9a8e812021-06-16 18:14:17 -060047
48
LaMont Jones0f5171b2021-01-29 12:28:56 -070049@faux.empty_error
George Engelbrechtc9a8e812021-06-16 18:14:17 -060050@faux.success(ExampleGetResponse)
Alex Klein1699fab2022-09-08 08:46:06 -060051@validate.exists("result_path.path.path")
LaMont Jones0f5171b2021-01-29 12:28:56 -070052@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +000053def Get(
54 input_proto: artifacts_pb2.GetRequest,
55 output_proto: artifacts_pb2.GetResponse,
Alex Klein1699fab2022-09-08 08:46:06 -060056 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -070057) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -060058 """Get all artifacts.
LaMont Jones0f5171b2021-01-29 12:28:56 -070059
Alex Klein1699fab2022-09-08 08:46:06 -060060 Get all artifacts for the build.
LaMont Jones0f5171b2021-01-29 12:28:56 -070061
Alex Klein1699fab2022-09-08 08:46:06 -060062 Note: As the individual artifact_type bundlers are added here, they *must*
63 stop uploading it via the individual bundler function.
Alex Klein1699fab2022-09-08 08:46:06 -060064 """
65 output_dir = input_proto.result_path.path.path
Jaques Clapauchf616bcd2021-04-09 20:14:40 +000066
Alex Klein1699fab2022-09-08 08:46:06 -060067 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
68 # This endpoint does not currently support any artifacts that are built
69 # without a sysroot being present.
70 if not sysroot.path:
71 return controller.RETURN_CODE_SUCCESS
72
73 chroot = controller_util.ParseChroot(input_proto.chroot)
74 build_target = controller_util.ParseBuildTarget(
75 input_proto.sysroot.build_target
76 )
77
78 # A list of RegisteredGet tuples (input proto, output proto, get results).
79 get_res_list = [
80 RegisteredGet(
81 output_proto.artifacts.image,
82 image_controller.GetArtifacts(
83 input_proto.artifact_info.image,
84 chroot,
85 sysroot,
86 build_target,
87 output_dir,
88 ),
89 ),
90 RegisteredGet(
91 output_proto.artifacts.sysroot,
92 sysroot_controller.GetArtifacts(
93 input_proto.artifact_info.sysroot,
94 chroot,
95 sysroot,
96 build_target,
97 output_dir,
98 ),
99 ),
100 RegisteredGet(
101 output_proto.artifacts.test,
102 test_controller.GetArtifacts(
103 input_proto.artifact_info.test,
104 chroot,
105 sysroot,
106 build_target,
107 output_dir,
108 ),
109 ),
110 ]
111
112 for get_res in get_res_list:
113 for artifact_dict in get_res.artifact_dict:
Jack Neus26b94672022-10-27 17:33:21 +0000114 kwargs = {}
115 # TODO(b/255838545): Remove the kwargs funkness when these fields
116 # have been added for all services.
117 if "failed" in artifact_dict:
118 kwargs["failed"] = artifact_dict.get("failed", False)
119 kwargs["failure_reason"] = artifact_dict.get("failure_reason")
Alex Klein1699fab2022-09-08 08:46:06 -0600120 get_res.output_proto.artifacts.add(
121 artifact_type=artifact_dict["type"],
122 paths=[
123 common_pb2.Path(
124 path=x, location=common_pb2.Path.Location.OUTSIDE
125 )
Jack Neus26b94672022-10-27 17:33:21 +0000126 for x in artifact_dict.get("paths", [])
Alex Klein1699fab2022-09-08 08:46:06 -0600127 ],
Jack Neus26b94672022-10-27 17:33:21 +0000128 **kwargs,
Alex Klein1699fab2022-09-08 08:46:06 -0600129 )
LaMont Jones8b88e9d2021-06-28 16:37:34 -0600130 return controller.RETURN_CODE_SUCCESS
131
LaMont Jones0f5171b2021-01-29 12:28:56 -0700132
Alex Kleinb6847e22022-11-07 10:44:48 -0700133def _BuildSetupResponse(_input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600134 """Just return POINTLESS for now."""
Alex Kleinb6847e22022-11-07 10:44:48 -0700135 # All the artifact types we support claim that the build is POINTLESS.
Alex Klein1699fab2022-09-08 08:46:06 -0600136 output_proto.build_relevance = artifacts_pb2.BuildSetupResponse.POINTLESS
LaMont Jones58362a42021-02-04 17:40:08 -0700137
138
139@faux.success(_BuildSetupResponse)
140@faux.empty_error
141@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000142def BuildSetup(
143 _input_proto: artifacts_pb2.GetRequest,
144 output_proto: artifacts_pb2.GetResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600145 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700146) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600147 """Setup anything needed for building artifacts
LaMont Jones58362a42021-02-04 17:40:08 -0700148
Alex Klein1699fab2022-09-08 08:46:06 -0600149 If any artifact types require steps prior to building the package, they go
150 here. For example, see ToolchainService/PrepareForBuild.
LaMont Jones58362a42021-02-04 17:40:08 -0700151
Alex Klein1699fab2022-09-08 08:46:06 -0600152 Note: crbug/1034529 introduces this method as a noop. As the individual
153 artifact_type bundlers are added here, they *must* stop uploading it via the
154 individual bundler function.
Alex Klein1699fab2022-09-08 08:46:06 -0600155 """
156 # If any artifact_type says "NEEDED", the return is NEEDED.
157 # Otherwise, if any artifact_type says "UNKNOWN", the return is UNKNOWN.
158 # Otherwise, the return is POINTLESS.
159 output_proto.build_relevance = artifacts_pb2.BuildSetupResponse.POINTLESS
160 return controller.RETURN_CODE_SUCCESS
LaMont Jones58362a42021-02-04 17:40:08 -0700161
162
Varun Somani04dccd72021-10-09 01:06:11 +0000163def _GetImageDir(build_root: str, target: str) -> Optional[str]:
Alex Klein1699fab2022-09-08 08:46:06 -0600164 """Return path containing images for the given build target.
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600165
Alex Klein1699fab2022-09-08 08:46:06 -0600166 TODO(saklein) Expand image_lib.GetLatestImageLink to support this use case.
Alex Kleine2612a02019-04-18 13:51:06 -0600167
Alex Klein1699fab2022-09-08 08:46:06 -0600168 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600169 build_root: Path to checkout where build occurs.
170 target: Name of the build target.
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600171
Alex Klein1699fab2022-09-08 08:46:06 -0600172 Returns:
Alex Klein611dddd2022-10-11 17:02:01 -0600173 Path to the latest directory containing target images or None.
Alex Klein1699fab2022-09-08 08:46:06 -0600174 """
175 image_dir = os.path.join(build_root, "src/build/images", target, "latest")
176 if not os.path.exists(image_dir):
177 logging.warning(
178 "Expected to find image output for target %s at %s, but "
179 "path does not exist",
180 target,
181 image_dir,
182 )
183 return None
Alex Kleind2bf1462019-10-24 16:37:04 -0600184
Alex Klein1699fab2022-09-08 08:46:06 -0600185 return image_dir
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600186
187
Alex Kleinb6847e22022-11-07 10:44:48 -0700188def _BundleImageArchivesResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600189 """Add artifact paths to a successful response."""
190 output_proto.artifacts.add().path = os.path.join(
191 input_proto.output_dir, "path0.tar.xz"
192 )
193 output_proto.artifacts.add().path = os.path.join(
194 input_proto.output_dir, "path1.tar.xz"
195 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700196
197
198@faux.success(_BundleImageArchivesResponse)
199@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600200@validate.require("build_target.name")
201@validate.exists("output_dir")
Alex Kleind91e95a2019-09-17 10:39:02 -0600202@validate.validation_complete
Alex Kleinb6847e22022-11-07 10:44:48 -0700203def BundleImageArchives(
204 input_proto: artifacts_pb2.BundleRequest,
205 output_proto: artifacts_pb2.BundleResponse,
206 _config: "api_config.ApiConfig",
207) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600208 """Create a .tar.xz archive for each image that has been created."""
209 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
210 output_dir = input_proto.output_dir
211 image_dir = _GetImageDir(constants.SOURCE_ROOT, build_target.name)
212 if image_dir is None:
213 return
Alex Kleind91e95a2019-09-17 10:39:02 -0600214
Alex Klein1699fab2022-09-08 08:46:06 -0600215 archives = artifacts.ArchiveImages(image_dir, output_dir)
Alex Kleind91e95a2019-09-17 10:39:02 -0600216
Alex Klein1699fab2022-09-08 08:46:06 -0600217 for archive in archives:
218 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Kleind91e95a2019-09-17 10:39:02 -0600219
220
Alex Kleinb6847e22022-11-07 10:44:48 -0700221def _BundleImageZipResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600222 """Add artifact zip files to a successful response."""
223 output_proto.artifacts.add().path = os.path.join(
224 input_proto.output_dir, "image.zip"
225 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700226
227
228@faux.success(_BundleImageZipResponse)
229@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600230@validate.require("build_target.name", "output_dir")
231@validate.exists("output_dir")
Alex Klein231d2da2019-07-22 16:44:45 -0600232@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000233def BundleImageZip(
234 input_proto: artifacts_pb2.BundleRequest,
235 output_proto: artifacts_pb2.BundleResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600236 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700237) -> Optional[int]:
238 """Bundle image.zip."""
Alex Klein1699fab2022-09-08 08:46:06 -0600239 target = input_proto.build_target.name
240 output_dir = input_proto.output_dir
241 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
242 if image_dir is None:
Alex Kleinb6847e22022-11-07 10:44:48 -0700243 logging.warning("Image build directory not found.")
Alex Klein1699fab2022-09-08 08:46:06 -0600244 return None
Alex Klein231d2da2019-07-22 16:44:45 -0600245
Alex Klein1699fab2022-09-08 08:46:06 -0600246 archive = artifacts.BundleImageZip(output_dir, image_dir)
247 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600248
249
Alex Kleinb6847e22022-11-07 10:44:48 -0700250def _BundleTestUpdatePayloadsResponse(
251 input_proto, output_proto, _config
252) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600253 """Add test payload files to a successful response."""
254 output_proto.artifacts.add().path = os.path.join(
255 input_proto.output_dir, "payload1.bin"
256 )
257 output_proto.artifacts.add().path = os.path.join(
258 input_proto.output_dir, "payload1.json"
259 )
260 output_proto.artifacts.add().path = os.path.join(
261 input_proto.output_dir, "payload1.log"
262 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700263
264
265@faux.success(_BundleTestUpdatePayloadsResponse)
266@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600267@validate.require("build_target.name", "output_dir")
268@validate.exists("output_dir")
Alex Klein231d2da2019-07-22 16:44:45 -0600269@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000270def BundleTestUpdatePayloads(
271 input_proto: artifacts_pb2.BundleRequest,
272 output_proto: artifacts_pb2.BundleResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600273 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700274) -> Optional[int]:
275 """Generate minimal update payloads for the build target for testing."""
Alex Klein1699fab2022-09-08 08:46:06 -0600276 target = input_proto.build_target.name
277 output_dir = input_proto.output_dir
278 build_root = constants.SOURCE_ROOT
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600279
Alex Klein1699fab2022-09-08 08:46:06 -0600280 # Use the first available image to create the update payload.
281 img_dir = _GetImageDir(build_root, target)
282 if img_dir is None:
283 return None
Alex Kleind2bf1462019-10-24 16:37:04 -0600284
Alex Klein1699fab2022-09-08 08:46:06 -0600285 img_types = [
286 constants.IMAGE_TYPE_TEST,
287 constants.IMAGE_TYPE_DEV,
288 constants.IMAGE_TYPE_BASE,
289 ]
290 img_names = [constants.IMAGE_TYPE_TO_NAME[t] for t in img_types]
291 img_paths = [os.path.join(img_dir, x) for x in img_names]
292 valid_images = [x for x in img_paths if os.path.exists(x)]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600293
Alex Klein1699fab2022-09-08 08:46:06 -0600294 if not valid_images:
295 cros_build_lib.Die(
296 'Expected to find an image of type among %r for target "%s" '
297 "at path %s.",
298 img_types,
299 target,
300 img_dir,
301 )
302 image = valid_images[0]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600303
Greg Edelstone0419392023-06-22 22:13:43 +0000304 payloads = artifacts.BundleTestUpdatePayloads(image, output_dir)
Alex Klein1699fab2022-09-08 08:46:06 -0600305 for payload in payloads:
306 output_proto.artifacts.add().path = payload
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600307
308
Alex Kleinb6847e22022-11-07 10:44:48 -0700309def _BundleAutotestFilesResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600310 """Add test autotest files to a successful response."""
311 output_proto.artifacts.add().path = os.path.join(
312 input_proto.output_dir, "autotest-a.tar.gz"
313 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700314
315
316@faux.success(_BundleAutotestFilesResponse)
317@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600318@validate.require("sysroot.path")
319@validate.exists("output_dir")
Alex Klein036833d2022-06-01 13:05:01 -0600320@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600321def BundleAutotestFiles(
322 input_proto: artifacts_pb2.BundleRequest,
323 output_proto: artifacts_pb2.BundleResponse,
324 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700325) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600326 """Tar the autotest files for a build target."""
327 output_dir = input_proto.output_dir
328 chroot = controller_util.ParseChroot(input_proto.chroot)
329 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Alex Klein231d2da2019-07-22 16:44:45 -0600330
Alex Klein1699fab2022-09-08 08:46:06 -0600331 if not sysroot.Exists(chroot=chroot):
332 logging.warning("Sysroot does not exist: %s", sysroot.path)
333 return
Alex Klein238d8862019-05-07 11:32:46 -0600334
Alex Klein1699fab2022-09-08 08:46:06 -0600335 try:
336 # Note that this returns the full path to *multiple* tarballs.
337 archives = artifacts.BundleAutotestFiles(chroot, sysroot, output_dir)
338 except artifacts.Error as e:
339 logging.warning(e)
340 return
Alex Klein238d8862019-05-07 11:32:46 -0600341
Alex Klein1699fab2022-09-08 08:46:06 -0600342 for archive in archives.values():
343 output_proto.artifacts.add().path = archive
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600344
345
Alex Kleinb6847e22022-11-07 10:44:48 -0700346def _BundleTastFilesResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600347 """Add test tast files to a successful response."""
348 output_proto.artifacts.add().path = os.path.join(
349 input_proto.output_dir, "tast_bundles.tar.gz"
350 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700351
352
353@faux.success(_BundleTastFilesResponse)
354@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600355@validate.require("sysroot.path")
356@validate.exists("output_dir")
Alex Klein036833d2022-06-01 13:05:01 -0600357@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600358def BundleTastFiles(
359 input_proto: artifacts_pb2.BundleRequest,
360 output_proto: artifacts_pb2.BundleResponse,
361 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700362) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600363 """Tar the tast files for a build target."""
364 output_dir = input_proto.output_dir
365 chroot = controller_util.ParseChroot(input_proto.chroot)
366 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Alex Kleinb9d810b2019-07-01 12:38:02 -0600367
Alex Klein1699fab2022-09-08 08:46:06 -0600368 if not sysroot.Exists(chroot=chroot):
369 logging.warning("Sysroot does not exist: %s", sysroot.path)
370 return
Alex Kleinb9d810b2019-07-01 12:38:02 -0600371
Alex Klein1699fab2022-09-08 08:46:06 -0600372 archive = artifacts.BundleTastFiles(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600373
Alex Klein1699fab2022-09-08 08:46:06 -0600374 if not archive:
375 logging.warning("Found no tast files for %s.", sysroot.path)
376 return
Alex Klein036833d2022-06-01 13:05:01 -0600377
Alex Klein1699fab2022-09-08 08:46:06 -0600378 output_proto.artifacts.add().path = archive
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600379
380
Fergus Dall34d74e12020-09-29 15:52:32 +1000381def BundlePinnedGuestImages(_input_proto, _output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600382 # TODO(crbug/1034529): Remove this endpoint
383 pass
384
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700385
Fergus Dall34d74e12020-09-29 15:52:32 +1000386def FetchPinnedGuestImageUris(_input_proto, _output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600387 # TODO(crbug/1034529): Remove this endpoint
388 pass
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600389
390
Alex Kleinb6847e22022-11-07 10:44:48 -0700391def _FetchMetadataResponse(
392 _input_proto, output_proto, _config
393) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600394 """Populate the output_proto with sample data."""
395 for fp in ("/metadata/foo.txt", "/metadata/bar.jsonproto"):
396 output_proto.filepaths.add(
397 path=common_pb2.Path(path=fp, location=common_pb2.Path.OUTSIDE)
398 )
399 return controller.RETURN_CODE_SUCCESS
Greg Edelstondc941072021-08-11 12:32:30 -0600400
401
402@faux.success(_FetchMetadataResponse)
403@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600404@validate.exists("chroot.path")
405@validate.require("sysroot.path")
Greg Edelstondc941072021-08-11 12:32:30 -0600406@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000407def FetchMetadata(
408 input_proto: artifacts_pb2.FetchMetadataRequest,
409 output_proto: artifacts_pb2.FetchMetadataResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600410 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700411) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600412 """FetchMetadata returns the paths to all build/test metadata files.
Greg Edelstondc941072021-08-11 12:32:30 -0600413
Alex Klein1699fab2022-09-08 08:46:06 -0600414 This implements ArtifactsService.FetchMetadata.
Alex Klein1699fab2022-09-08 08:46:06 -0600415 """
416 chroot = controller_util.ParseChroot(input_proto.chroot)
417 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
418 for path in test.FindAllMetadataFiles(chroot, sysroot):
419 output_proto.filepaths.add(
420 path=common_pb2.Path(path=path, location=common_pb2.Path.OUTSIDE)
421 )
422 return controller.RETURN_CODE_SUCCESS
Greg Edelstondc941072021-08-11 12:32:30 -0600423
424
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700425def _BundleFirmwareResponse(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600426 """Add test firmware image files to a successful response."""
427 output_proto.artifacts.add().path = os.path.join(
428 input_proto.output_dir, "firmware.tar.gz"
429 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700430
431
432@faux.success(_BundleFirmwareResponse)
433@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600434@validate.require("sysroot.path")
435@validate.exists("output_dir")
Alex Klein231d2da2019-07-22 16:44:45 -0600436@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600437def BundleFirmware(
438 input_proto: artifacts_pb2.BundleRequest,
439 output_proto: artifacts_pb2.BundleResponse,
440 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700441) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600442 """Tar the firmware images for a build target."""
443 output_dir = input_proto.output_dir
444 chroot = controller_util.ParseChroot(input_proto.chroot)
445 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Alex Klein231d2da2019-07-22 16:44:45 -0600446
Alex Klein1699fab2022-09-08 08:46:06 -0600447 if not chroot.exists():
448 logging.warning("Chroot does not exist: %s", chroot.path)
449 return
450 elif not sysroot.Exists(chroot=chroot):
451 logging.warning("Sysroot does not exist: %s", sysroot.path)
452 return
Alex Klein231d2da2019-07-22 16:44:45 -0600453
Alex Klein1699fab2022-09-08 08:46:06 -0600454 archive = artifacts.BuildFirmwareArchive(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600455
Alex Klein1699fab2022-09-08 08:46:06 -0600456 if not archive:
457 logging.warning(
458 "Could not create firmware archive. No firmware found for %s.",
459 sysroot.path,
460 )
461 return
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600462
Alex Klein1699fab2022-09-08 08:46:06 -0600463 output_proto.artifacts.add().path = archive
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600464
465
Alex Kleinb6847e22022-11-07 10:44:48 -0700466def _BundleFpmcuUnittestsResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600467 """Add fingerprint MCU unittest binaries to a successful response."""
468 output_proto.artifacts.add().path = os.path.join(
469 input_proto.output_dir, "fpmcu_unittests.tar.gz"
470 )
Yicheng Liea1181f2020-09-22 11:51:10 -0700471
472
473@faux.success(_BundleFpmcuUnittestsResponse)
474@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600475@validate.require("sysroot.path")
476@validate.exists("output_dir")
Yicheng Liea1181f2020-09-22 11:51:10 -0700477@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600478def BundleFpmcuUnittests(
479 input_proto: artifacts_pb2.BundleRequest,
480 output_proto: artifacts_pb2.BundleResponse,
481 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700482) -> Optional[int]:
483 """Tar the fingerprint MCU unittest binaries for a build target."""
Alex Klein1699fab2022-09-08 08:46:06 -0600484 output_dir = input_proto.output_dir
485 chroot = controller_util.ParseChroot(input_proto.chroot)
486 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Yicheng Liea1181f2020-09-22 11:51:10 -0700487
Alex Klein1699fab2022-09-08 08:46:06 -0600488 if not chroot.exists():
489 logging.warning("Chroot does not exist: %s", chroot.path)
490 return
491 elif not sysroot.Exists(chroot=chroot):
492 logging.warning("Sysroot does not exist: %s", sysroot.path)
493 return
Yicheng Liea1181f2020-09-22 11:51:10 -0700494
Alex Klein1699fab2022-09-08 08:46:06 -0600495 archive = artifacts.BundleFpmcuUnittests(chroot, sysroot, output_dir)
Yicheng Liea1181f2020-09-22 11:51:10 -0700496
Alex Klein1699fab2022-09-08 08:46:06 -0600497 if not archive:
498 logging.warning("No fpmcu unittests found for %s.", sysroot.path)
499 return
Yicheng Liea1181f2020-09-22 11:51:10 -0700500
Alex Klein1699fab2022-09-08 08:46:06 -0600501 output_proto.artifacts.add().path = archive
Yicheng Liea1181f2020-09-22 11:51:10 -0700502
503
Alex Kleinb6847e22022-11-07 10:44:48 -0700504def _BundleEbuildLogsResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600505 """Add test log files to a successful response."""
506 output_proto.artifacts.add().path = os.path.join(
507 input_proto.output_dir, "ebuild-logs.tar.gz"
508 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700509
510
511@faux.success(_BundleEbuildLogsResponse)
512@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600513@validate.require("sysroot.path")
514@validate.exists("output_dir")
Alex Klein036833d2022-06-01 13:05:01 -0600515@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600516def BundleEbuildLogs(
517 input_proto: artifacts_pb2.BundleRequest,
518 output_proto: artifacts_pb2.BundleResponse,
519 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700520) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600521 """Tar the ebuild logs for a build target."""
522 output_dir = input_proto.output_dir
523 chroot = controller_util.ParseChroot(input_proto.chroot)
524 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Evan Hernandeza478d802019-04-08 15:08:24 -0600525
Alex Klein1699fab2022-09-08 08:46:06 -0600526 if not sysroot.Exists(chroot=chroot):
527 logging.warning("Sysroot does not exist: %s", sysroot.path)
528 return
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600529
Alex Klein1699fab2022-09-08 08:46:06 -0600530 archive = artifacts.BundleEBuildLogsTarball(chroot, sysroot, output_dir)
Alex Klein036833d2022-06-01 13:05:01 -0600531
Alex Klein1699fab2022-09-08 08:46:06 -0600532 if not archive:
533 logging.warning(
534 "Could not create ebuild logs archive. No logs found for %s.",
535 sysroot.path,
536 )
537 return
Alex Klein036833d2022-06-01 13:05:01 -0600538
Alex Klein1699fab2022-09-08 08:46:06 -0600539 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Klein6504eca2019-04-18 15:37:56 -0600540
541
Alex Kleinb6847e22022-11-07 10:44:48 -0700542def _BundleChromeOSConfigResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600543 """Add test config files to a successful response."""
544 output_proto.artifacts.add().path = os.path.join(
545 input_proto.output_dir, "config.yaml"
546 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700547
548
549@faux.success(_BundleChromeOSConfigResponse)
550@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600551@validate.require("sysroot.path")
552@validate.exists("output_dir")
Andrew Lamb811aead2019-08-12 10:25:05 -0600553@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000554def BundleChromeOSConfig(
555 input_proto: artifacts_pb2.BundleRequest,
556 output_proto: artifacts_pb2.BundleResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600557 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700558) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600559 """Output the ChromeOS Config payload for a build target."""
560 output_dir = input_proto.output_dir
561 chroot = controller_util.ParseChroot(input_proto.chroot)
562 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Andrew Lamb811aead2019-08-12 10:25:05 -0600563
Alex Klein1699fab2022-09-08 08:46:06 -0600564 chromeos_config = artifacts.BundleChromeOSConfig(
565 chroot, sysroot, output_dir
566 )
Alex Klein2d8333c2022-06-01 13:29:01 -0600567
Alex Klein1699fab2022-09-08 08:46:06 -0600568 if not chromeos_config:
569 logging.warning(
570 "Could not create ChromeOS Config for %s.", sysroot.path
571 )
572 return
Alex Klein383a7a32021-12-07 16:01:19 -0700573
Alex Klein1699fab2022-09-08 08:46:06 -0600574 output_proto.artifacts.add().path = os.path.join(
575 output_dir, chromeos_config
576 )
Andrew Lamb811aead2019-08-12 10:25:05 -0600577
578
Alex Kleinb6847e22022-11-07 10:44:48 -0700579def _BundleSimpleChromeArtifactsResponse(
580 input_proto, output_proto, _config
581) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600582 """Add test simple chrome files to a successful response."""
583 output_proto.artifacts.add().path = os.path.join(
584 input_proto.output_dir, "simple_chrome.txt"
585 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700586
587
588@faux.success(_BundleSimpleChromeArtifactsResponse)
589@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600590@validate.require("output_dir", "sysroot.build_target.name", "sysroot.path")
591@validate.exists("output_dir")
Alex Klein231d2da2019-07-22 16:44:45 -0600592@validate.validation_complete
Alex Kleinb6847e22022-11-07 10:44:48 -0700593def BundleSimpleChromeArtifacts(
594 input_proto, output_proto, _config
595) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600596 """Create the simple chrome artifacts."""
597 sysroot_path = input_proto.sysroot.path
598 output_dir = input_proto.output_dir
Alex Klein2275d692019-04-23 16:04:12 -0600599
Alex Klein1699fab2022-09-08 08:46:06 -0600600 # Build out the argument instances.
601 build_target = controller_util.ParseBuildTarget(
602 input_proto.sysroot.build_target
603 )
604 chroot = controller_util.ParseChroot(input_proto.chroot)
605 # Sysroot.path needs to be the fully qualified path, including the chroot.
606 full_sysroot_path = os.path.join(chroot.path, sysroot_path.lstrip(os.sep))
607 sysroot = sysroot_lib.Sysroot(full_sysroot_path)
Alex Klein2275d692019-04-23 16:04:12 -0600608
Alex Klein1699fab2022-09-08 08:46:06 -0600609 # Check that the sysroot exists before we go on.
610 if not sysroot.Exists():
Alex Kleinb6847e22022-11-07 10:44:48 -0700611 logging.warning("The sysroot does not exist.")
612 return
Alex Klein2275d692019-04-23 16:04:12 -0600613
Alex Klein1699fab2022-09-08 08:46:06 -0600614 try:
615 results = artifacts.BundleSimpleChromeArtifacts(
616 chroot, sysroot, build_target, output_dir
617 )
618 except artifacts.Error as e:
Alex Kleinb6847e22022-11-07 10:44:48 -0700619 logging.warning(
Alex Klein1699fab2022-09-08 08:46:06 -0600620 "Error %s raised in BundleSimpleChromeArtifacts: %s", type(e), e
621 )
Alex Kleinb6847e22022-11-07 10:44:48 -0700622 return
Alex Klein2275d692019-04-23 16:04:12 -0600623
Alex Klein1699fab2022-09-08 08:46:06 -0600624 for file_name in results:
625 output_proto.artifacts.add().path = file_name
Alex Klein2275d692019-04-23 16:04:12 -0600626
627
Alex Kleinb6847e22022-11-07 10:44:48 -0700628def _BundleVmFilesResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600629 """Add test vm files to a successful response."""
630 output_proto.artifacts.add().path = os.path.join(
631 input_proto.output_dir, "f1.tar"
632 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700633
634
635@faux.success(_BundleVmFilesResponse)
636@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600637@validate.require("chroot.path", "test_results_dir", "output_dir")
638@validate.exists("output_dir")
Alex Klein231d2da2019-07-22 16:44:45 -0600639@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000640def BundleVmFiles(
641 input_proto: artifacts_pb2.BundleVmFilesRequest,
642 output_proto: artifacts_pb2.BundleResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600643 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700644) -> None:
645 """Tar VM disk and memory files."""
Alex Klein1699fab2022-09-08 08:46:06 -0600646 chroot = controller_util.ParseChroot(input_proto.chroot)
647 test_results_dir = input_proto.test_results_dir
648 output_dir = input_proto.output_dir
Alex Klein6504eca2019-04-18 15:37:56 -0600649
Alex Klein1699fab2022-09-08 08:46:06 -0600650 archives = artifacts.BundleVmFiles(chroot, test_results_dir, output_dir)
651 for archive in archives:
652 output_proto.artifacts.add().path = archive
653
Tiancong Wangc4805b72019-06-11 12:12:03 -0700654
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700655def _ExportCpeReportResponse(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600656 """Add test cpe results to a successful response."""
657 output_proto.artifacts.add().path = os.path.join(
658 input_proto.output_dir, "cpe_report.txt"
659 )
660 output_proto.artifacts.add().path = os.path.join(
661 input_proto.output_dir, "cpe_warnings.txt"
662 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700663
664
665@faux.success(_ExportCpeReportResponse)
666@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600667@validate.require("sysroot.path")
668@validate.exists("output_dir")
Alex Klein036833d2022-06-01 13:05:01 -0600669@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600670def ExportCpeReport(
671 input_proto: artifacts_pb2.BundleRequest,
672 output_proto: artifacts_pb2.BundleResponse,
673 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700674) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600675 """Export a CPE report."""
676 chroot = controller_util.ParseChroot(input_proto.chroot)
677 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
678 output_dir = input_proto.output_dir
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600679
Alex Klein1699fab2022-09-08 08:46:06 -0600680 if not sysroot.Exists(chroot=chroot):
681 logging.warning("Sysroot does not exist: %s", sysroot.path)
682 return
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600683
Alex Klein1699fab2022-09-08 08:46:06 -0600684 cpe_result = artifacts.GenerateCpeReport(chroot, sysroot, output_dir)
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600685
Alex Klein1699fab2022-09-08 08:46:06 -0600686 output_proto.artifacts.add().path = cpe_result.report
687 output_proto.artifacts.add().path = cpe_result.warnings
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +0900688
689
Alex Kleinb6847e22022-11-07 10:44:48 -0700690def _BundleGceTarballResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600691 """Add artifact tarball to a successful response."""
692 output_proto.artifacts.add().path = os.path.join(
693 input_proto.output_dir, constants.TEST_IMAGE_GCE_TAR
694 )
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +0900695
696
697@faux.success(_BundleGceTarballResponse)
698@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600699@validate.require("build_target.name", "output_dir")
700@validate.exists("output_dir")
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +0900701@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000702def BundleGceTarball(
703 input_proto: artifacts_pb2.BundleRequest,
704 output_proto: artifacts_pb2.BundleResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600705 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700706) -> Optional[int]:
707 """Bundle the test image into a tarball suitable for importing into GCE."""
Alex Klein1699fab2022-09-08 08:46:06 -0600708 target = input_proto.build_target.name
709 output_dir = input_proto.output_dir
710 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
711 if image_dir is None:
712 return None
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +0900713
Alex Klein1699fab2022-09-08 08:46:06 -0600714 tarball = artifacts.BundleGceTarball(output_dir, image_dir)
715 output_proto.artifacts.add().path = tarball