blob: 14190c4aaf572b0cf937360ae46450eff42a3525 [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."""
Brian Norris40cb1732023-07-26 16:07:28 +0000190 output_proto.artifacts.add().path = os.path.join(
191 input_proto.output_dir, "path0.tar.xz"
Alex Klein1699fab2022-09-08 08:46:06 -0600192 )
Brian Norris40cb1732023-07-26 16:07:28 +0000193 output_proto.artifacts.add().path = os.path.join(
194 input_proto.output_dir, "path1.tar.xz"
Alex Klein1699fab2022-09-08 08:46:06 -0600195 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700196
197
198@faux.success(_BundleImageArchivesResponse)
199@faux.empty_error
Hsin-Yi Wang09663da2023-06-28 21:40:24 +0800200@validate.require("sysroot.build_target.name", "sysroot.path")
Brian Norris40cb1732023-07-26 16:07:28 +0000201@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."""
Hsin-Yi Wang09663da2023-06-28 21:40:24 +0800209 build_target = controller_util.ParseBuildTarget(
210 input_proto.sysroot.build_target
211 )
212 chroot = controller_util.ParseChroot(input_proto.chroot)
213 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Brian Norris40cb1732023-07-26 16:07:28 +0000214 output_dir = input_proto.output_dir
Alex Klein1699fab2022-09-08 08:46:06 -0600215 image_dir = _GetImageDir(constants.SOURCE_ROOT, build_target.name)
216 if image_dir is None:
217 return
Alex Kleind91e95a2019-09-17 10:39:02 -0600218
Hsin-Yi Wang09663da2023-06-28 21:40:24 +0800219 if not sysroot.Exists(chroot=chroot):
220 logging.warning("Sysroot does not exist: %s", sysroot.path)
221
222 archives = artifacts.ArchiveImages(chroot, sysroot, image_dir, output_dir)
Alex Kleind91e95a2019-09-17 10:39:02 -0600223
Alex Klein1699fab2022-09-08 08:46:06 -0600224 for archive in archives:
Brian Norris40cb1732023-07-26 16:07:28 +0000225 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Kleind91e95a2019-09-17 10:39:02 -0600226
227
Alex Kleinb6847e22022-11-07 10:44:48 -0700228def _BundleImageZipResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600229 """Add artifact zip files to a successful response."""
Brian Norris40cb1732023-07-26 16:07:28 +0000230 output_proto.artifacts.add().path = os.path.join(
231 input_proto.output_dir, "image.zip"
Alex Klein1699fab2022-09-08 08:46:06 -0600232 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700233
234
235@faux.success(_BundleImageZipResponse)
236@faux.empty_error
Brian Norris40cb1732023-07-26 16:07:28 +0000237@validate.require("build_target.name", "output_dir")
238@validate.exists("output_dir")
Alex Klein231d2da2019-07-22 16:44:45 -0600239@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000240def BundleImageZip(
241 input_proto: artifacts_pb2.BundleRequest,
242 output_proto: artifacts_pb2.BundleResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600243 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700244) -> Optional[int]:
245 """Bundle image.zip."""
Alex Klein1699fab2022-09-08 08:46:06 -0600246 target = input_proto.build_target.name
Brian Norris40cb1732023-07-26 16:07:28 +0000247 output_dir = input_proto.output_dir
Alex Klein1699fab2022-09-08 08:46:06 -0600248 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
249 if image_dir is None:
Alex Kleinb6847e22022-11-07 10:44:48 -0700250 logging.warning("Image build directory not found.")
Alex Klein1699fab2022-09-08 08:46:06 -0600251 return None
Alex Klein231d2da2019-07-22 16:44:45 -0600252
Alex Klein1699fab2022-09-08 08:46:06 -0600253 archive = artifacts.BundleImageZip(output_dir, image_dir)
Brian Norris40cb1732023-07-26 16:07:28 +0000254 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600255
256
Alex Kleinb6847e22022-11-07 10:44:48 -0700257def _BundleTestUpdatePayloadsResponse(
258 input_proto, output_proto, _config
259) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600260 """Add test payload files to a successful response."""
Brian Norris40cb1732023-07-26 16:07:28 +0000261 output_proto.artifacts.add().path = os.path.join(
262 input_proto.output_dir, "payload1.bin"
Alex Klein1699fab2022-09-08 08:46:06 -0600263 )
Brian Norris40cb1732023-07-26 16:07:28 +0000264 output_proto.artifacts.add().path = os.path.join(
265 input_proto.output_dir, "payload1.json"
Alex Klein1699fab2022-09-08 08:46:06 -0600266 )
Brian Norris40cb1732023-07-26 16:07:28 +0000267 output_proto.artifacts.add().path = os.path.join(
268 input_proto.output_dir, "payload1.log"
Alex Klein1699fab2022-09-08 08:46:06 -0600269 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700270
271
272@faux.success(_BundleTestUpdatePayloadsResponse)
273@faux.empty_error
Brian Norris40cb1732023-07-26 16:07:28 +0000274@validate.require("build_target.name", "output_dir")
275@validate.exists("output_dir")
Alex Klein231d2da2019-07-22 16:44:45 -0600276@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000277def BundleTestUpdatePayloads(
278 input_proto: artifacts_pb2.BundleRequest,
279 output_proto: artifacts_pb2.BundleResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600280 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700281) -> Optional[int]:
282 """Generate minimal update payloads for the build target for testing."""
Alex Klein1699fab2022-09-08 08:46:06 -0600283 target = input_proto.build_target.name
Brian Norris40cb1732023-07-26 16:07:28 +0000284 output_dir = input_proto.output_dir
Brian Norrisdd2e7e62023-06-16 14:07:32 -0700285 chroot = controller_util.ParseChroot(input_proto.chroot)
Alex Klein1699fab2022-09-08 08:46:06 -0600286 build_root = constants.SOURCE_ROOT
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600287
Alex Klein1699fab2022-09-08 08:46:06 -0600288 # Use the first available image to create the update payload.
289 img_dir = _GetImageDir(build_root, target)
290 if img_dir is None:
291 return None
Alex Kleind2bf1462019-10-24 16:37:04 -0600292
Alex Klein1699fab2022-09-08 08:46:06 -0600293 img_types = [
294 constants.IMAGE_TYPE_TEST,
295 constants.IMAGE_TYPE_DEV,
296 constants.IMAGE_TYPE_BASE,
297 ]
298 img_names = [constants.IMAGE_TYPE_TO_NAME[t] for t in img_types]
299 img_paths = [os.path.join(img_dir, x) for x in img_names]
300 valid_images = [x for x in img_paths if os.path.exists(x)]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600301
Alex Klein1699fab2022-09-08 08:46:06 -0600302 if not valid_images:
303 cros_build_lib.Die(
304 'Expected to find an image of type among %r for target "%s" '
305 "at path %s.",
306 img_types,
307 target,
308 img_dir,
309 )
310 image = valid_images[0]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600311
Brian Norris99291322023-07-26 00:27:45 +0000312 payloads = artifacts.BundleTestUpdatePayloads(chroot, image, output_dir)
Alex Klein1699fab2022-09-08 08:46:06 -0600313 for payload in payloads:
Brian Norris40cb1732023-07-26 16:07:28 +0000314 output_proto.artifacts.add().path = payload
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600315
316
Alex Kleinb6847e22022-11-07 10:44:48 -0700317def _BundleAutotestFilesResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600318 """Add test autotest files to a successful response."""
Brian Norris40cb1732023-07-26 16:07:28 +0000319 output_proto.artifacts.add().path = os.path.join(
320 input_proto.output_dir, "autotest-a.tar.gz"
Alex Klein1699fab2022-09-08 08:46:06 -0600321 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700322
323
324@faux.success(_BundleAutotestFilesResponse)
325@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600326@validate.require("sysroot.path")
Brian Norris40cb1732023-07-26 16:07:28 +0000327@validate.exists("output_dir")
Alex Klein036833d2022-06-01 13:05:01 -0600328@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600329def BundleAutotestFiles(
330 input_proto: artifacts_pb2.BundleRequest,
331 output_proto: artifacts_pb2.BundleResponse,
332 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700333) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600334 """Tar the autotest files for a build target."""
Brian Norris40cb1732023-07-26 16:07:28 +0000335 output_dir = input_proto.output_dir
Alex Klein1699fab2022-09-08 08:46:06 -0600336 chroot = controller_util.ParseChroot(input_proto.chroot)
337 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Alex Klein231d2da2019-07-22 16:44:45 -0600338
Alex Klein1699fab2022-09-08 08:46:06 -0600339 if not sysroot.Exists(chroot=chroot):
340 logging.warning("Sysroot does not exist: %s", sysroot.path)
341 return
Alex Klein238d8862019-05-07 11:32:46 -0600342
Alex Klein1699fab2022-09-08 08:46:06 -0600343 try:
344 # Note that this returns the full path to *multiple* tarballs.
345 archives = artifacts.BundleAutotestFiles(chroot, sysroot, output_dir)
346 except artifacts.Error as e:
347 logging.warning(e)
348 return
Alex Klein238d8862019-05-07 11:32:46 -0600349
Alex Klein1699fab2022-09-08 08:46:06 -0600350 for archive in archives.values():
Brian Norris40cb1732023-07-26 16:07:28 +0000351 output_proto.artifacts.add().path = archive
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600352
353
Alex Kleinb6847e22022-11-07 10:44:48 -0700354def _BundleTastFilesResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600355 """Add test tast files to a successful response."""
Brian Norris40cb1732023-07-26 16:07:28 +0000356 output_proto.artifacts.add().path = os.path.join(
357 input_proto.output_dir, "tast_bundles.tar.gz"
Alex Klein1699fab2022-09-08 08:46:06 -0600358 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700359
360
361@faux.success(_BundleTastFilesResponse)
362@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600363@validate.require("sysroot.path")
Brian Norris40cb1732023-07-26 16:07:28 +0000364@validate.exists("output_dir")
Alex Klein036833d2022-06-01 13:05:01 -0600365@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600366def BundleTastFiles(
367 input_proto: artifacts_pb2.BundleRequest,
368 output_proto: artifacts_pb2.BundleResponse,
369 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700370) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600371 """Tar the tast files for a build target."""
Brian Norris40cb1732023-07-26 16:07:28 +0000372 output_dir = input_proto.output_dir
Alex Klein1699fab2022-09-08 08:46:06 -0600373 chroot = controller_util.ParseChroot(input_proto.chroot)
374 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Alex Kleinb9d810b2019-07-01 12:38:02 -0600375
Alex Klein1699fab2022-09-08 08:46:06 -0600376 if not sysroot.Exists(chroot=chroot):
377 logging.warning("Sysroot does not exist: %s", sysroot.path)
378 return
Alex Kleinb9d810b2019-07-01 12:38:02 -0600379
Alex Klein1699fab2022-09-08 08:46:06 -0600380 archive = artifacts.BundleTastFiles(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600381
Alex Klein1699fab2022-09-08 08:46:06 -0600382 if not archive:
383 logging.warning("Found no tast files for %s.", sysroot.path)
384 return
Alex Klein036833d2022-06-01 13:05:01 -0600385
Brian Norris40cb1732023-07-26 16:07:28 +0000386 output_proto.artifacts.add().path = archive
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600387
388
Fergus Dall34d74e12020-09-29 15:52:32 +1000389def BundlePinnedGuestImages(_input_proto, _output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600390 # TODO(crbug/1034529): Remove this endpoint
391 pass
392
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700393
Fergus Dall34d74e12020-09-29 15:52:32 +1000394def FetchPinnedGuestImageUris(_input_proto, _output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600395 # TODO(crbug/1034529): Remove this endpoint
396 pass
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600397
398
Alex Kleinb6847e22022-11-07 10:44:48 -0700399def _FetchMetadataResponse(
400 _input_proto, output_proto, _config
401) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600402 """Populate the output_proto with sample data."""
403 for fp in ("/metadata/foo.txt", "/metadata/bar.jsonproto"):
404 output_proto.filepaths.add(
405 path=common_pb2.Path(path=fp, location=common_pb2.Path.OUTSIDE)
406 )
407 return controller.RETURN_CODE_SUCCESS
Greg Edelstondc941072021-08-11 12:32:30 -0600408
409
410@faux.success(_FetchMetadataResponse)
411@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600412@validate.exists("chroot.path")
413@validate.require("sysroot.path")
Greg Edelstondc941072021-08-11 12:32:30 -0600414@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000415def FetchMetadata(
416 input_proto: artifacts_pb2.FetchMetadataRequest,
417 output_proto: artifacts_pb2.FetchMetadataResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600418 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700419) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600420 """FetchMetadata returns the paths to all build/test metadata files.
Greg Edelstondc941072021-08-11 12:32:30 -0600421
Alex Klein1699fab2022-09-08 08:46:06 -0600422 This implements ArtifactsService.FetchMetadata.
Alex Klein1699fab2022-09-08 08:46:06 -0600423 """
424 chroot = controller_util.ParseChroot(input_proto.chroot)
425 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
426 for path in test.FindAllMetadataFiles(chroot, sysroot):
427 output_proto.filepaths.add(
428 path=common_pb2.Path(path=path, location=common_pb2.Path.OUTSIDE)
429 )
430 return controller.RETURN_CODE_SUCCESS
Greg Edelstondc941072021-08-11 12:32:30 -0600431
432
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700433def _BundleFirmwareResponse(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600434 """Add test firmware image files to a successful response."""
Brian Norris40cb1732023-07-26 16:07:28 +0000435 output_proto.artifacts.add().path = os.path.join(
436 input_proto.output_dir, "firmware.tar.gz"
Alex Klein1699fab2022-09-08 08:46:06 -0600437 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700438
439
440@faux.success(_BundleFirmwareResponse)
441@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600442@validate.require("sysroot.path")
Brian Norris40cb1732023-07-26 16:07:28 +0000443@validate.exists("output_dir")
Alex Klein231d2da2019-07-22 16:44:45 -0600444@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600445def BundleFirmware(
446 input_proto: artifacts_pb2.BundleRequest,
447 output_proto: artifacts_pb2.BundleResponse,
448 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700449) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600450 """Tar the firmware images for a build target."""
Brian Norris40cb1732023-07-26 16:07:28 +0000451 output_dir = input_proto.output_dir
Alex Klein1699fab2022-09-08 08:46:06 -0600452 chroot = controller_util.ParseChroot(input_proto.chroot)
453 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Alex Klein231d2da2019-07-22 16:44:45 -0600454
Alex Klein1699fab2022-09-08 08:46:06 -0600455 if not chroot.exists():
456 logging.warning("Chroot does not exist: %s", chroot.path)
457 return
458 elif not sysroot.Exists(chroot=chroot):
459 logging.warning("Sysroot does not exist: %s", sysroot.path)
460 return
Alex Klein231d2da2019-07-22 16:44:45 -0600461
Alex Klein1699fab2022-09-08 08:46:06 -0600462 archive = artifacts.BuildFirmwareArchive(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600463
Alex Klein1699fab2022-09-08 08:46:06 -0600464 if not archive:
465 logging.warning(
466 "Could not create firmware archive. No firmware found for %s.",
467 sysroot.path,
468 )
469 return
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600470
Brian Norris40cb1732023-07-26 16:07:28 +0000471 output_proto.artifacts.add().path = archive
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600472
473
Alex Kleinb6847e22022-11-07 10:44:48 -0700474def _BundleFpmcuUnittestsResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600475 """Add fingerprint MCU unittest binaries to a successful response."""
Brian Norris40cb1732023-07-26 16:07:28 +0000476 output_proto.artifacts.add().path = os.path.join(
477 input_proto.output_dir, "fpmcu_unittests.tar.gz"
Alex Klein1699fab2022-09-08 08:46:06 -0600478 )
Yicheng Liea1181f2020-09-22 11:51:10 -0700479
480
481@faux.success(_BundleFpmcuUnittestsResponse)
482@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600483@validate.require("sysroot.path")
Brian Norris40cb1732023-07-26 16:07:28 +0000484@validate.exists("output_dir")
Yicheng Liea1181f2020-09-22 11:51:10 -0700485@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600486def BundleFpmcuUnittests(
487 input_proto: artifacts_pb2.BundleRequest,
488 output_proto: artifacts_pb2.BundleResponse,
489 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700490) -> Optional[int]:
491 """Tar the fingerprint MCU unittest binaries for a build target."""
Brian Norris40cb1732023-07-26 16:07:28 +0000492 output_dir = input_proto.output_dir
Alex Klein1699fab2022-09-08 08:46:06 -0600493 chroot = controller_util.ParseChroot(input_proto.chroot)
494 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Yicheng Liea1181f2020-09-22 11:51:10 -0700495
Alex Klein1699fab2022-09-08 08:46:06 -0600496 if not chroot.exists():
497 logging.warning("Chroot does not exist: %s", chroot.path)
498 return
499 elif not sysroot.Exists(chroot=chroot):
500 logging.warning("Sysroot does not exist: %s", sysroot.path)
501 return
Yicheng Liea1181f2020-09-22 11:51:10 -0700502
Alex Klein1699fab2022-09-08 08:46:06 -0600503 archive = artifacts.BundleFpmcuUnittests(chroot, sysroot, output_dir)
Yicheng Liea1181f2020-09-22 11:51:10 -0700504
Alex Klein1699fab2022-09-08 08:46:06 -0600505 if not archive:
506 logging.warning("No fpmcu unittests found for %s.", sysroot.path)
507 return
Yicheng Liea1181f2020-09-22 11:51:10 -0700508
Brian Norris40cb1732023-07-26 16:07:28 +0000509 output_proto.artifacts.add().path = archive
Yicheng Liea1181f2020-09-22 11:51:10 -0700510
511
Alex Kleinb6847e22022-11-07 10:44:48 -0700512def _BundleEbuildLogsResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600513 """Add test log files to a successful response."""
Brian Norris40cb1732023-07-26 16:07:28 +0000514 output_proto.artifacts.add().path = os.path.join(
515 input_proto.output_dir, "ebuild-logs.tar.gz"
Alex Klein1699fab2022-09-08 08:46:06 -0600516 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700517
518
519@faux.success(_BundleEbuildLogsResponse)
520@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600521@validate.require("sysroot.path")
Brian Norris40cb1732023-07-26 16:07:28 +0000522@validate.exists("output_dir")
Alex Klein036833d2022-06-01 13:05:01 -0600523@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600524def BundleEbuildLogs(
525 input_proto: artifacts_pb2.BundleRequest,
526 output_proto: artifacts_pb2.BundleResponse,
527 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700528) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600529 """Tar the ebuild logs for a build target."""
Brian Norris40cb1732023-07-26 16:07:28 +0000530 output_dir = input_proto.output_dir
Alex Klein1699fab2022-09-08 08:46:06 -0600531 chroot = controller_util.ParseChroot(input_proto.chroot)
532 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Evan Hernandeza478d802019-04-08 15:08:24 -0600533
Alex Klein1699fab2022-09-08 08:46:06 -0600534 if not sysroot.Exists(chroot=chroot):
535 logging.warning("Sysroot does not exist: %s", sysroot.path)
536 return
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600537
Alex Klein1699fab2022-09-08 08:46:06 -0600538 archive = artifacts.BundleEBuildLogsTarball(chroot, sysroot, output_dir)
Alex Klein036833d2022-06-01 13:05:01 -0600539
Alex Klein1699fab2022-09-08 08:46:06 -0600540 if not archive:
541 logging.warning(
542 "Could not create ebuild logs archive. No logs found for %s.",
543 sysroot.path,
544 )
545 return
Alex Klein036833d2022-06-01 13:05:01 -0600546
Brian Norris40cb1732023-07-26 16:07:28 +0000547 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Klein6504eca2019-04-18 15:37:56 -0600548
549
Alex Kleinb6847e22022-11-07 10:44:48 -0700550def _BundleChromeOSConfigResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600551 """Add test config files to a successful response."""
Brian Norris40cb1732023-07-26 16:07:28 +0000552 output_proto.artifacts.add().path = os.path.join(
553 input_proto.output_dir, "config.yaml"
Alex Klein1699fab2022-09-08 08:46:06 -0600554 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700555
556
557@faux.success(_BundleChromeOSConfigResponse)
558@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600559@validate.require("sysroot.path")
Brian Norris40cb1732023-07-26 16:07:28 +0000560@validate.exists("output_dir")
Andrew Lamb811aead2019-08-12 10:25:05 -0600561@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000562def BundleChromeOSConfig(
563 input_proto: artifacts_pb2.BundleRequest,
564 output_proto: artifacts_pb2.BundleResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600565 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700566) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600567 """Output the ChromeOS Config payload for a build target."""
Brian Norris40cb1732023-07-26 16:07:28 +0000568 output_dir = input_proto.output_dir
Alex Klein1699fab2022-09-08 08:46:06 -0600569 chroot = controller_util.ParseChroot(input_proto.chroot)
570 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Andrew Lamb811aead2019-08-12 10:25:05 -0600571
Alex Klein1699fab2022-09-08 08:46:06 -0600572 chromeos_config = artifacts.BundleChromeOSConfig(
573 chroot, sysroot, output_dir
574 )
Alex Klein2d8333c2022-06-01 13:29:01 -0600575
Alex Klein1699fab2022-09-08 08:46:06 -0600576 if not chromeos_config:
577 logging.warning(
578 "Could not create ChromeOS Config for %s.", sysroot.path
579 )
580 return
Alex Klein383a7a32021-12-07 16:01:19 -0700581
Brian Norris40cb1732023-07-26 16:07:28 +0000582 output_proto.artifacts.add().path = os.path.join(
583 output_dir, chromeos_config
Alex Klein1699fab2022-09-08 08:46:06 -0600584 )
Andrew Lamb811aead2019-08-12 10:25:05 -0600585
586
Alex Kleinb6847e22022-11-07 10:44:48 -0700587def _BundleSimpleChromeArtifactsResponse(
588 input_proto, output_proto, _config
589) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600590 """Add test simple chrome files to a successful response."""
Brian Norris40cb1732023-07-26 16:07:28 +0000591 output_proto.artifacts.add().path = os.path.join(
592 input_proto.output_dir, "simple_chrome.txt"
Alex Klein1699fab2022-09-08 08:46:06 -0600593 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700594
595
596@faux.success(_BundleSimpleChromeArtifactsResponse)
597@faux.empty_error
Brian Norris40cb1732023-07-26 16:07:28 +0000598@validate.require("output_dir", "sysroot.build_target.name", "sysroot.path")
599@validate.exists("output_dir")
Alex Klein231d2da2019-07-22 16:44:45 -0600600@validate.validation_complete
Alex Kleinb6847e22022-11-07 10:44:48 -0700601def BundleSimpleChromeArtifacts(
602 input_proto, output_proto, _config
603) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600604 """Create the simple chrome artifacts."""
605 sysroot_path = input_proto.sysroot.path
Brian Norris40cb1732023-07-26 16:07:28 +0000606 output_dir = input_proto.output_dir
Alex Klein2275d692019-04-23 16:04:12 -0600607
Alex Klein1699fab2022-09-08 08:46:06 -0600608 # Build out the argument instances.
609 build_target = controller_util.ParseBuildTarget(
610 input_proto.sysroot.build_target
611 )
612 chroot = controller_util.ParseChroot(input_proto.chroot)
613 # Sysroot.path needs to be the fully qualified path, including the chroot.
Brian Norrisd3e391e2023-06-30 09:53:11 -0700614 full_sysroot_path = chroot.full_path(sysroot_path)
Alex Klein1699fab2022-09-08 08:46:06 -0600615 sysroot = sysroot_lib.Sysroot(full_sysroot_path)
Alex Klein2275d692019-04-23 16:04:12 -0600616
Alex Klein1699fab2022-09-08 08:46:06 -0600617 # Check that the sysroot exists before we go on.
618 if not sysroot.Exists():
Alex Kleinb6847e22022-11-07 10:44:48 -0700619 logging.warning("The sysroot does not exist.")
620 return
Alex Klein2275d692019-04-23 16:04:12 -0600621
Alex Klein1699fab2022-09-08 08:46:06 -0600622 try:
623 results = artifacts.BundleSimpleChromeArtifacts(
624 chroot, sysroot, build_target, output_dir
625 )
626 except artifacts.Error as e:
Alex Kleinb6847e22022-11-07 10:44:48 -0700627 logging.warning(
Alex Klein1699fab2022-09-08 08:46:06 -0600628 "Error %s raised in BundleSimpleChromeArtifacts: %s", type(e), e
629 )
Alex Kleinb6847e22022-11-07 10:44:48 -0700630 return
Alex Klein2275d692019-04-23 16:04:12 -0600631
Alex Klein1699fab2022-09-08 08:46:06 -0600632 for file_name in results:
Brian Norris40cb1732023-07-26 16:07:28 +0000633 output_proto.artifacts.add().path = file_name
Alex Klein2275d692019-04-23 16:04:12 -0600634
635
Alex Kleinb6847e22022-11-07 10:44:48 -0700636def _BundleVmFilesResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600637 """Add test vm files to a successful response."""
638 output_proto.artifacts.add().path = os.path.join(
639 input_proto.output_dir, "f1.tar"
640 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700641
642
643@faux.success(_BundleVmFilesResponse)
644@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600645@validate.require("chroot.path", "test_results_dir", "output_dir")
646@validate.exists("output_dir")
Alex Klein231d2da2019-07-22 16:44:45 -0600647@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000648def BundleVmFiles(
649 input_proto: artifacts_pb2.BundleVmFilesRequest,
650 output_proto: artifacts_pb2.BundleResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600651 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700652) -> None:
653 """Tar VM disk and memory files."""
Alex Klein1699fab2022-09-08 08:46:06 -0600654 chroot = controller_util.ParseChroot(input_proto.chroot)
655 test_results_dir = input_proto.test_results_dir
656 output_dir = input_proto.output_dir
Alex Klein6504eca2019-04-18 15:37:56 -0600657
Alex Klein1699fab2022-09-08 08:46:06 -0600658 archives = artifacts.BundleVmFiles(chroot, test_results_dir, output_dir)
659 for archive in archives:
660 output_proto.artifacts.add().path = archive
661
Tiancong Wangc4805b72019-06-11 12:12:03 -0700662
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700663def _ExportCpeReportResponse(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600664 """Add test cpe results to a successful response."""
Brian Norris40cb1732023-07-26 16:07:28 +0000665 output_proto.artifacts.add().path = os.path.join(
666 input_proto.output_dir, "cpe_report.txt"
Alex Klein1699fab2022-09-08 08:46:06 -0600667 )
Brian Norris40cb1732023-07-26 16:07:28 +0000668 output_proto.artifacts.add().path = os.path.join(
669 input_proto.output_dir, "cpe_warnings.txt"
Alex Klein1699fab2022-09-08 08:46:06 -0600670 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700671
672
673@faux.success(_ExportCpeReportResponse)
674@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600675@validate.require("sysroot.path")
Brian Norris40cb1732023-07-26 16:07:28 +0000676@validate.exists("output_dir")
Alex Klein036833d2022-06-01 13:05:01 -0600677@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600678def ExportCpeReport(
679 input_proto: artifacts_pb2.BundleRequest,
680 output_proto: artifacts_pb2.BundleResponse,
681 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700682) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600683 """Export a CPE report."""
684 chroot = controller_util.ParseChroot(input_proto.chroot)
685 sysroot = controller_util.ParseSysroot(input_proto.sysroot)
Brian Norris40cb1732023-07-26 16:07:28 +0000686 output_dir = input_proto.output_dir
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600687
Alex Klein1699fab2022-09-08 08:46:06 -0600688 if not sysroot.Exists(chroot=chroot):
689 logging.warning("Sysroot does not exist: %s", sysroot.path)
690 return
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600691
Alex Klein1699fab2022-09-08 08:46:06 -0600692 cpe_result = artifacts.GenerateCpeReport(chroot, sysroot, output_dir)
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600693
Brian Norris40cb1732023-07-26 16:07:28 +0000694 output_proto.artifacts.add().path = cpe_result.report
695 output_proto.artifacts.add().path = cpe_result.warnings
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +0900696
697
Alex Kleinb6847e22022-11-07 10:44:48 -0700698def _BundleGceTarballResponse(input_proto, output_proto, _config) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -0600699 """Add artifact tarball to a successful response."""
Brian Norris40cb1732023-07-26 16:07:28 +0000700 output_proto.artifacts.add().path = os.path.join(
701 input_proto.output_dir, constants.TEST_IMAGE_GCE_TAR
Alex Klein1699fab2022-09-08 08:46:06 -0600702 )
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +0900703
704
705@faux.success(_BundleGceTarballResponse)
706@faux.empty_error
Brian Norris40cb1732023-07-26 16:07:28 +0000707@validate.require("build_target.name", "output_dir")
708@validate.exists("output_dir")
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +0900709@validate.validation_complete
Varun Somani04dccd72021-10-09 01:06:11 +0000710def BundleGceTarball(
711 input_proto: artifacts_pb2.BundleRequest,
712 output_proto: artifacts_pb2.BundleResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600713 _config: "api_config.ApiConfig",
Alex Kleinb6847e22022-11-07 10:44:48 -0700714) -> Optional[int]:
715 """Bundle the test image into a tarball suitable for importing into GCE."""
Alex Klein1699fab2022-09-08 08:46:06 -0600716 target = input_proto.build_target.name
Brian Norris40cb1732023-07-26 16:07:28 +0000717 output_dir = input_proto.output_dir
Alex Klein1699fab2022-09-08 08:46:06 -0600718 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
719 if image_dir is None:
720 return None
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +0900721
Alex Klein1699fab2022-09-08 08:46:06 -0600722 tarball = artifacts.BundleGceTarball(output_dir, image_dir)
Brian Norris40cb1732023-07-26 16:07:28 +0000723 output_proto.artifacts.add().path = tarball