blob: f26fafc43448d34a8ff1c8f3655f1428171e7157 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2018 The ChromiumOS Authors
Alex Klein2966e302019-01-17 13:29:38 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Image API Service.
6
7The image related API endpoints should generally be found here.
8"""
9
Jack Neus5e56fef2021-06-18 16:57:28 +000010import functools
Chris McDonald1672ddb2021-07-21 11:48:23 -060011import logging
Alex Klein2966e302019-01-17 13:29:38 -070012import os
Jack Neus94a35be2021-09-10 15:18:06 +000013from pathlib import Path
Kevin Shelton5b21c8b2022-04-04 17:04:13 -070014from typing import List, NamedTuple, Set, TYPE_CHECKING, Union
Alex Klein2966e302019-01-17 13:29:38 -070015
Alex Klein8cb365a2019-05-15 16:24:53 -060016from chromite.api import controller
Alex Klein076841b2019-08-29 15:19:39 -060017from chromite.api import faux
Alex Klein2b236722019-06-19 15:44:26 -060018from chromite.api import validate
Alex Kleine9a7dbf2020-10-06 18:12:12 -060019from chromite.api.controller import controller_util
David Burgerb171d652019-05-13 16:07:00 -060020from chromite.api.gen.chromiumos import common_pb2
Will Bradley9bc85452019-10-10 10:48:21 -060021from chromite.api.metrics import deserialize_metrics_log
George Engelbrechtc9a8e812021-06-16 18:14:17 -060022from chromite.lib import build_target_lib
23from chromite.lib import chroot_lib
Alex Klein56355682019-02-07 10:36:54 -070024from chromite.lib import constants
Chris McDonald1672ddb2021-07-21 11:48:23 -060025from chromite.lib import cros_build_lib
Alex Klein56355682019-02-07 10:36:54 -070026from chromite.lib import image_lib
Alex Kleinaef41942022-04-19 14:13:17 -060027from chromite.lib import metrics_lib
George Engelbrechtc9a8e812021-06-16 18:14:17 -060028from chromite.lib import sysroot_lib
Jack Neus761e1842020-12-01 18:20:11 +000029from chromite.scripts import pushimage
Alex Kleinb7cdbe62019-02-22 11:41:32 -070030from chromite.service import image
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040031from chromite.service import packages as packages_service
32
Alex Klein2966e302019-01-17 13:29:38 -070033
Kevin Shelton5b21c8b2022-04-04 17:04:13 -070034if TYPE_CHECKING:
Alex Klein1699fab2022-09-08 08:46:06 -060035 from chromite.api import api_config
36 from chromite.api.gen.chromite.api import image_pb2
Kevin Shelton5b21c8b2022-04-04 17:04:13 -070037
Alex Klein56355682019-02-07 10:36:54 -070038# The image.proto ImageType enum ids.
George Engelbrechtc55d6312021-05-05 12:11:13 -060039_BASE_ID = common_pb2.IMAGE_TYPE_BASE
40_DEV_ID = common_pb2.IMAGE_TYPE_DEV
41_TEST_ID = common_pb2.IMAGE_TYPE_TEST
42_BASE_VM_ID = common_pb2.IMAGE_TYPE_BASE_VM
43_TEST_VM_ID = common_pb2.IMAGE_TYPE_TEST_VM
44_RECOVERY_ID = common_pb2.IMAGE_TYPE_RECOVERY
45_FACTORY_ID = common_pb2.IMAGE_TYPE_FACTORY
46_FIRMWARE_ID = common_pb2.IMAGE_TYPE_FIRMWARE
47_BASE_GUEST_VM_ID = common_pb2.IMAGE_TYPE_BASE_GUEST_VM
48_TEST_GUEST_VM_ID = common_pb2.IMAGE_TYPE_TEST_GUEST_VM
Alex Klein56355682019-02-07 10:36:54 -070049
50# Dict to allow easily translating names to enum ids and vice versa.
51_IMAGE_MAPPING = {
52 _BASE_ID: constants.IMAGE_TYPE_BASE,
53 constants.IMAGE_TYPE_BASE: _BASE_ID,
54 _DEV_ID: constants.IMAGE_TYPE_DEV,
55 constants.IMAGE_TYPE_DEV: _DEV_ID,
56 _TEST_ID: constants.IMAGE_TYPE_TEST,
57 constants.IMAGE_TYPE_TEST: _TEST_ID,
Michael Mortenseneefe8952019-08-12 15:37:15 -060058 _RECOVERY_ID: constants.IMAGE_TYPE_RECOVERY,
59 constants.IMAGE_TYPE_RECOVERY: _RECOVERY_ID,
Alex Klein9039a952021-07-27 13:52:39 -060060 _FACTORY_ID: constants.IMAGE_TYPE_FACTORY_SHIM,
61 constants.IMAGE_TYPE_FACTORY_SHIM: _FACTORY_ID,
Michael Mortenseneefe8952019-08-12 15:37:15 -060062 _FIRMWARE_ID: constants.IMAGE_TYPE_FIRMWARE,
63 constants.IMAGE_TYPE_FIRMWARE: _FIRMWARE_ID,
Alex Klein56355682019-02-07 10:36:54 -070064}
65
George Engelbrecht9f4f8322021-03-08 12:04:17 -070066# Dict to describe the prerequisite built images for each VM image type.
Alex Klein21b95022019-05-09 14:14:46 -060067_VM_IMAGE_MAPPING = {
68 _BASE_VM_ID: _IMAGE_MAPPING[_BASE_ID],
69 _TEST_VM_ID: _IMAGE_MAPPING[_TEST_ID],
Trent Begin008cade2019-10-31 13:40:59 -060070 _BASE_GUEST_VM_ID: _IMAGE_MAPPING[_BASE_ID],
71 _TEST_GUEST_VM_ID: _IMAGE_MAPPING[_TEST_ID],
Alex Klein21b95022019-05-09 14:14:46 -060072}
73
George Engelbrecht9f4f8322021-03-08 12:04:17 -070074# Dict to describe the prerequisite built images for each mod image type.
75_MOD_IMAGE_MAPPING = {
76 _RECOVERY_ID: _IMAGE_MAPPING[_BASE_ID],
77}
78
Jack Neus761e1842020-12-01 18:20:11 +000079# Supported image types for PushImage.
80SUPPORTED_IMAGE_TYPES = {
81 common_pb2.IMAGE_TYPE_RECOVERY: constants.IMAGE_TYPE_RECOVERY,
82 common_pb2.IMAGE_TYPE_FACTORY: constants.IMAGE_TYPE_FACTORY,
83 common_pb2.IMAGE_TYPE_FIRMWARE: constants.IMAGE_TYPE_FIRMWARE,
84 common_pb2.IMAGE_TYPE_ACCESSORY_USBPD: constants.IMAGE_TYPE_ACCESSORY_USBPD,
85 common_pb2.IMAGE_TYPE_ACCESSORY_RWSIG: constants.IMAGE_TYPE_ACCESSORY_RWSIG,
Evan Benn4d061102022-02-14 12:50:45 +110086 common_pb2.IMAGE_TYPE_HPS_FIRMWARE: constants.IMAGE_TYPE_HPS_FIRMWARE,
Jack Neus761e1842020-12-01 18:20:11 +000087 common_pb2.IMAGE_TYPE_BASE: constants.IMAGE_TYPE_BASE,
George Engelbrecht9f4f8322021-03-08 12:04:17 -070088 common_pb2.IMAGE_TYPE_GSC_FIRMWARE: constants.IMAGE_TYPE_GSC_FIRMWARE,
Jack Neus761e1842020-12-01 18:20:11 +000089}
90
Alex Klein27978a42021-07-27 14:18:10 -060091# Built image directory symlink names. These names allow specifying a static
92# location for creation to simplify later archival stages. In practice, this
93# sets the symlink argument to build_packages.
94# Core are the build/dev/test images.
95# Use "latest" until we do a better job of passing through image directories,
96# e.g. for artifacts.
Alex Klein1699fab2022-09-08 08:46:06 -060097LOCATION_CORE = "latest"
Alex Klein27978a42021-07-27 14:18:10 -060098# The factory_install image.
Alex Klein1699fab2022-09-08 08:46:06 -060099LOCATION_FACTORY = "factory_shim"
Alex Klein27978a42021-07-27 14:18:10 -0600100
101
102class ImageTypes(NamedTuple):
Alex Klein1699fab2022-09-08 08:46:06 -0600103 """Parsed image types."""
Alex Klein27978a42021-07-27 14:18:10 -0600104
Alex Klein1699fab2022-09-08 08:46:06 -0600105 images: Set[str]
106 vms: Set[int]
107 mod_images: Set[int]
Alex Klein27978a42021-07-27 14:18:10 -0600108
Alex Klein1699fab2022-09-08 08:46:06 -0600109 @property
110 def core_images(self) -> List[str]:
111 """The core images (base/dev/test) as a list."""
112 return list(self.images - {_IMAGE_MAPPING[_FACTORY_ID]}) or []
Alex Klein27978a42021-07-27 14:18:10 -0600113
Alex Klein1699fab2022-09-08 08:46:06 -0600114 @property
115 def has_factory(self) -> bool:
116 """Whether the factory image is present."""
117 return _IMAGE_MAPPING[_FACTORY_ID] in self.images
118
119 @property
120 def factory(self) -> List[str]:
121 """A list with the factory type if set."""
122 return [_IMAGE_MAPPING[_FACTORY_ID]] if self.has_factory else []
Alex Klein27978a42021-07-27 14:18:10 -0600123
Alex Klein56355682019-02-07 10:36:54 -0700124
Alex Klein1699fab2022-09-08 08:46:06 -0600125def _add_image_to_proto(
126 output_proto, path: Union["Path", str], image_type: int, board: str
127):
128 """Quick helper function to add a new image to the output proto."""
129 new_image = output_proto.images.add()
130 new_image.path = str(path)
131 new_image.type = image_type
132 new_image.build_target.name = board
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700133
134
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600135def ExampleGetResponse():
Alex Klein1699fab2022-09-08 08:46:06 -0600136 """Give an example response to assemble upstream in caller artifacts."""
137 uabs = common_pb2.UploadedArtifactsByService
138 cabs = common_pb2.ArtifactsByService
139 return uabs.Sysroot(
140 artifacts=[
141 uabs.Image.ArtifactPaths(
142 artifact_type=cabs.Image.ArtifactType.DLC_IMAGE,
143 paths=[
144 common_pb2.Path(
145 path="/tmp/dlc/dlc.img",
146 location=common_pb2.Path.OUTSIDE,
147 )
148 ],
149 )
150 ]
151 )
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600152
153
Alex Klein1699fab2022-09-08 08:46:06 -0600154def GetArtifacts(
155 in_proto: common_pb2.ArtifactsByService.Image,
156 chroot: chroot_lib.Chroot,
157 sysroot_class: sysroot_lib.Sysroot,
158 build_target: build_target_lib.BuildTarget,
159 output_dir,
160) -> list:
161 """Builds and copies images to specified output_dir.
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600162
Alex Klein1699fab2022-09-08 08:46:06 -0600163 Copies (after optionally bundling) all required images into the output_dir,
164 returning a mapping of image type to a list of (output_dir) paths to
165 the desired files. Note that currently it is only processing one image (DLC),
166 but the future direction is to process all required images. Required images
167 are located within output_artifact.artifact_type.
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600168
Alex Klein1699fab2022-09-08 08:46:06 -0600169 Args:
170 in_proto: Proto request defining reqs.
171 chroot: The chroot proto used for these artifacts.
172 sysroot_class: The sysroot proto used for these artifacts.
173 build_target: The build target used for these artifacts.
174 output_dir: The path to write artifacts to.
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600175
Alex Klein1699fab2022-09-08 08:46:06 -0600176 Returns:
177 A list of dictionary mappings of ArtifactType to list of paths.
178 """
179 base_path = chroot.full_path(sysroot_class.path)
180 board = build_target.name
181 factory_shim_location = Path(
182 image_lib.GetLatestImageLink(board, pointer=LOCATION_FACTORY)
183 )
Jack Neus5e56fef2021-06-18 16:57:28 +0000184
Alex Klein1699fab2022-09-08 08:46:06 -0600185 generated = []
186 dlc_func = functools.partial(image.copy_dlc_image, base_path)
187 license_func = functools.partial(
188 image.copy_license_credits, board, symlink=LOCATION_CORE
189 )
190 factory_image_func = functools.partial(
191 image.create_factory_image_zip,
192 chroot,
193 sysroot_class,
194 factory_shim_location,
195 packages_service.determine_full_version(),
196 )
197 stripped_packags_func = functools.partial(
198 image.create_stripped_packages_tar,
199 chroot,
200 build_target,
201 )
202 artifact_types = {
203 in_proto.ArtifactType.DLC_IMAGE: dlc_func,
204 in_proto.ArtifactType.LICENSE_CREDITS: license_func,
205 in_proto.ArtifactType.FACTORY_IMAGE: factory_image_func,
206 in_proto.ArtifactType.STRIPPED_PACKAGES: stripped_packags_func,
207 }
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600208
Alex Klein1699fab2022-09-08 08:46:06 -0600209 for output_artifact in in_proto.output_artifacts:
210 for artifact_type, func in artifact_types.items():
211 if artifact_type in output_artifact.artifact_types:
212 result = func(output_dir)
213 if result:
214 generated.append(
215 {
216 "paths": [result]
217 if isinstance(result, str)
218 else result,
219 "type": artifact_type,
220 }
221 )
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600222
Alex Klein1699fab2022-09-08 08:46:06 -0600223 return generated
Pi-Hsun Shih8d9c8e42021-06-30 03:27:28 +0000224
Alex Kleincaace392021-07-26 14:28:13 -0600225
Michael Mortensen10146cf2019-11-19 19:59:22 -0700226def _CreateResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600227 """Set output_proto success field on a successful Create response."""
228 output_proto.success = True
Michael Mortensen10146cf2019-11-19 19:59:22 -0700229
230
231@faux.success(_CreateResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700232@faux.empty_completed_unsuccessfully_error
Alex Klein1699fab2022-09-08 08:46:06 -0600233@validate.require("build_target.name")
Alex Klein231d2da2019-07-22 16:44:45 -0600234@validate.validation_complete
Alex Kleinaef41942022-04-19 14:13:17 -0600235@metrics_lib.collect_metrics
Alex Klein1699fab2022-09-08 08:46:06 -0600236def Create(
237 input_proto: "image_pb2.CreateImageRequest",
238 output_proto: "image_pb2.CreateImageResult",
239 _config: "api_config.ApiConfig",
240):
241 """Build images.
Alex Klein56355682019-02-07 10:36:54 -0700242
Alex Klein1699fab2022-09-08 08:46:06 -0600243 Args:
244 input_proto: The input message.
245 output_proto: The output message.
246 _config: The API call config.
247 """
248 board = input_proto.build_target.name
Alex Klein56355682019-02-07 10:36:54 -0700249
Alex Klein1699fab2022-09-08 08:46:06 -0600250 # Build the base image if no images provided.
251 to_build = input_proto.image_types or [_BASE_ID]
Alex Klein56355682019-02-07 10:36:54 -0700252
Alex Klein1699fab2022-09-08 08:46:06 -0600253 image_types = _ParseImagesToCreate(to_build)
254 build_config = _ParseCreateBuildConfig(input_proto)
255 factory_build_config = build_config._replace(
256 symlink=LOCATION_FACTORY, output_dir_suffix=LOCATION_FACTORY
257 )
Alex Klein56355682019-02-07 10:36:54 -0700258
Alex Klein1699fab2022-09-08 08:46:06 -0600259 # Try building the core and factory images.
260 # Sorted isn't really necessary here, but it's much easier to test.
261 core_result = image.Build(
262 board, sorted(image_types.core_images), config=build_config
263 )
264 logging.debug("Core Result Images: %s", core_result.images)
Alex Klein56355682019-02-07 10:36:54 -0700265
Alex Klein1699fab2022-09-08 08:46:06 -0600266 factory_result = image.Build(
267 board, image_types.factory, config=factory_build_config
268 )
269 logging.debug("Factory Result Images: %s", factory_result.images)
Will Bradley29a49c22019-10-21 11:50:08 -0600270
Alex Klein1699fab2022-09-08 08:46:06 -0600271 # A successful run will have no images missing, will have run at least one
272 # of the two image sets, and neither attempt errored. The no error condition
273 # should be redundant with no missing images, but is cheap insurance.
274 all_built = core_result.all_built and factory_result.all_built
275 one_ran = core_result.build_run or factory_result.build_run
276 no_errors = not core_result.run_error and not factory_result.run_error
277 output_proto.success = success = all_built and one_ran and no_errors
Will Bradley29a49c22019-10-21 11:50:08 -0600278
Alex Klein1699fab2022-09-08 08:46:06 -0600279 if success:
280 # Success! We need to record the images we built in the output.
281 all_images = {**core_result.images, **factory_result.images}
282 for img_name, img_path in all_images.items():
283 _add_image_to_proto(
284 output_proto, img_path, _IMAGE_MAPPING[img_name], board
285 )
Alex Klein27978a42021-07-27 14:18:10 -0600286
Alex Klein1699fab2022-09-08 08:46:06 -0600287 # Build and record VMs as necessary.
288 for vm_type in image_types.vms:
289 is_test = vm_type in [_TEST_VM_ID, _TEST_GUEST_VM_ID]
290 img_type = _IMAGE_MAPPING[_TEST_ID if is_test else _BASE_ID]
291 img_dir = core_result.images[img_type].parent.resolve()
292 try:
293 if vm_type in [_BASE_GUEST_VM_ID, _TEST_GUEST_VM_ID]:
294 vm_path = image.CreateGuestVm(
295 board, is_test=is_test, image_dir=img_dir
296 )
297 else:
298 vm_path = image.CreateVm(
299 board,
300 disk_layout=build_config.disk_layout,
301 is_test=is_test,
302 image_dir=img_dir,
303 )
304 except image.ImageToVmError as e:
305 cros_build_lib.Die(e)
Will Bradley29a49c22019-10-21 11:50:08 -0600306
Alex Klein1699fab2022-09-08 08:46:06 -0600307 _add_image_to_proto(output_proto, vm_path, vm_type, board)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700308
Alex Klein1699fab2022-09-08 08:46:06 -0600309 # Build and record any mod images.
310 for mod_type in image_types.mod_images:
311 if mod_type == _RECOVERY_ID:
312 base_image_path = core_result.images[constants.IMAGE_TYPE_BASE]
313 # For ChromeOS Flex special case.
314 if build_config.base_is_recovery:
315 result = image.CopyBaseToRecovery(
316 board=board, image_path=base_image_path
317 )
318 else:
319 result = image.BuildRecoveryImage(
320 board=board, image_path=base_image_path
321 )
322 if result.all_built:
323 _add_image_to_proto(
324 output_proto,
325 result.images[_IMAGE_MAPPING[mod_type]],
326 mod_type,
327 board,
328 )
329 else:
330 cros_build_lib.Die("Failed to create recovery image.")
331 else:
332 cros_build_lib.Die("_RECOVERY_ID is the only mod_image_type.")
Will Bradley29a49c22019-10-21 11:50:08 -0600333
Alex Klein1699fab2022-09-08 08:46:06 -0600334 # Read metric events log and pipe them into output_proto.events.
335 deserialize_metrics_log(output_proto.events, prefix=board)
336 return controller.RETURN_CODE_SUCCESS
Will Bradley29a49c22019-10-21 11:50:08 -0600337
Alex Klein1699fab2022-09-08 08:46:06 -0600338 else:
339 # Failure, include all of the failed packages in the output when available.
340 packages = core_result.failed_packages + factory_result.failed_packages
341 if not packages:
342 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
Alex Klein2557b4f2019-07-11 14:34:00 -0600343
Alex Klein1699fab2022-09-08 08:46:06 -0600344 for package in packages:
345 current = output_proto.failed_packages.add()
346 controller_util.serialize_package_info(package, current)
Alex Klein1bcd9882019-03-19 13:25:24 -0600347
Alex Klein1699fab2022-09-08 08:46:06 -0600348 return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
Alex Klein1bcd9882019-03-19 13:25:24 -0600349
Alex Kleincaace392021-07-26 14:28:13 -0600350
Alex Klein27978a42021-07-27 14:18:10 -0600351def _ParseImagesToCreate(to_build: List[int]) -> ImageTypes:
Alex Klein1699fab2022-09-08 08:46:06 -0600352 """Helper function to parse the image types to build.
Alex Klein21b95022019-05-09 14:14:46 -0600353
Alex Klein1699fab2022-09-08 08:46:06 -0600354 This function expresses the dependencies of each image type and adds
355 the requisite image types if they're not explicitly defined.
Alex Klein21b95022019-05-09 14:14:46 -0600356
Alex Klein1699fab2022-09-08 08:46:06 -0600357 Args:
358 to_build: The image type list.
Alex Klein21b95022019-05-09 14:14:46 -0600359
Alex Klein1699fab2022-09-08 08:46:06 -0600360 Returns:
361 ImageTypes: The parsed images to build.
362 """
363 image_types = set()
364 vm_types = set()
365 mod_image_types = set()
366 for current in to_build:
367 # Find out if it's a special case (vm, img mod), or just any old image.
368 if current in _VM_IMAGE_MAPPING:
369 vm_types.add(current)
370 # Make sure we build the image required to build the VM.
371 image_types.add(_VM_IMAGE_MAPPING[current])
372 elif current in _MOD_IMAGE_MAPPING:
373 mod_image_types.add(current)
374 image_types.add(_MOD_IMAGE_MAPPING[current])
375 elif current in _IMAGE_MAPPING:
376 image_types.add(_IMAGE_MAPPING[current])
377 else:
378 # Not expected, but at least it will be obvious if this comes up.
379 cros_build_lib.Die(
380 "The service's known image types do not match those in image.proto. "
381 "Unknown Enum ID: %s" % current
382 )
Alex Klein21b95022019-05-09 14:14:46 -0600383
Alex Klein1699fab2022-09-08 08:46:06 -0600384 # We can only build one type of these images at a time since image_to_vm.sh
385 # uses the default path if a name is not provided.
386 if vm_types.issuperset({_BASE_VM_ID, _TEST_VM_ID}):
387 cros_build_lib.Die("Cannot create more than one VM.")
Alex Klein21b95022019-05-09 14:14:46 -0600388
Alex Klein1699fab2022-09-08 08:46:06 -0600389 return ImageTypes(
390 images=image_types, vms=vm_types, mod_images=mod_image_types
391 )
Alex Klein21b95022019-05-09 14:14:46 -0600392
393
394def _ParseCreateBuildConfig(input_proto):
Alex Klein1699fab2022-09-08 08:46:06 -0600395 """Helper to parse the image build config for Create."""
396 enable_rootfs_verification = not input_proto.disable_rootfs_verification
397 version = input_proto.version or None
398 disk_layout = input_proto.disk_layout or None
399 builder_path = input_proto.builder_path or None
400 base_is_recovery = input_proto.base_is_recovery or False
401 return image.BuildConfig(
402 enable_rootfs_verification=enable_rootfs_verification,
403 replace=True,
404 version=version,
405 disk_layout=disk_layout,
406 builder_path=builder_path,
407 symlink=LOCATION_CORE,
408 base_is_recovery=base_is_recovery,
409 )
Alex Klein21b95022019-05-09 14:14:46 -0600410
Alex Klein1bcd9882019-03-19 13:25:24 -0600411
Michael Mortensen10146cf2019-11-19 19:59:22 -0700412def _SignerTestResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600413 """Set output_proto success field on a successful SignerTest response."""
414 output_proto.success = True
415 return controller.RETURN_CODE_SUCCESS
Michael Mortensen10146cf2019-11-19 19:59:22 -0700416
417
418@faux.success(_SignerTestResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700419@faux.empty_completed_unsuccessfully_error
Alex Klein1699fab2022-09-08 08:46:06 -0600420@validate.exists("image.path")
Alex Klein231d2da2019-07-22 16:44:45 -0600421@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600422def SignerTest(
423 input_proto: "image_pb2.ImageTestRequest",
424 output_proto: "image_pb2.ImageTestRequest",
425 _config: "api_config.ApiConfig",
426):
427 """Run image tests.
Michael Mortensenc83c9952019-08-05 12:15:12 -0600428
Alex Klein1699fab2022-09-08 08:46:06 -0600429 Args:
430 input_proto: The input message.
431 output_proto: The output message.
432 _config: The API call config.
433 """
434 image_path = input_proto.image.path
Michael Mortensenc83c9952019-08-05 12:15:12 -0600435
Alex Klein1699fab2022-09-08 08:46:06 -0600436 result = image_lib.SecurityTest(image=image_path)
437 output_proto.success = result
438 if result:
439 return controller.RETURN_CODE_SUCCESS
440 else:
441 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
Michael Mortensenc83c9952019-08-05 12:15:12 -0600442
Alex Klein076841b2019-08-29 15:19:39 -0600443
Michael Mortensen10146cf2019-11-19 19:59:22 -0700444def _TestResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600445 """Set output_proto success field on a successful Test response."""
446 output_proto.success = True
447 return controller.RETURN_CODE_SUCCESS
Michael Mortensen10146cf2019-11-19 19:59:22 -0700448
449
450@faux.success(_TestResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700451@faux.empty_completed_unsuccessfully_error
Alex Klein1699fab2022-09-08 08:46:06 -0600452@validate.require("build_target.name", "result.directory")
453@validate.exists("image.path")
454def Test(
455 input_proto: "image_pb2.ImageTestRequest",
456 output_proto: "image_pb2.ImageTestResult",
457 config: "api_config.ApiConfig",
458):
459 """Run image tests.
Alex Klein2966e302019-01-17 13:29:38 -0700460
Alex Klein1699fab2022-09-08 08:46:06 -0600461 Args:
462 input_proto: The input message.
463 output_proto: The output message.
464 config: The API call config.
465 """
466 image_path = input_proto.image.path
467 board = input_proto.build_target.name
468 result_directory = input_proto.result.directory
Alex Klein2966e302019-01-17 13:29:38 -0700469
Alex Klein1699fab2022-09-08 08:46:06 -0600470 if not os.path.isfile(image_path) or not image_path.endswith(".bin"):
471 cros_build_lib.Die(
472 "The image.path must be an existing image file with a .bin extension."
473 )
Alex Klein2966e302019-01-17 13:29:38 -0700474
Alex Klein1699fab2022-09-08 08:46:06 -0600475 if config.validate_only:
476 return controller.RETURN_CODE_VALID_INPUT
Alex Klein231d2da2019-07-22 16:44:45 -0600477
Alex Klein1699fab2022-09-08 08:46:06 -0600478 success = image.Test(board, result_directory, image_dir=image_path)
479 output_proto.success = success
Alex Klein8cb365a2019-05-15 16:24:53 -0600480
Alex Klein1699fab2022-09-08 08:46:06 -0600481 if success:
482 return controller.RETURN_CODE_SUCCESS
483 else:
484 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
Jack Neus761e1842020-12-01 18:20:11 +0000485
486
487@faux.empty_success
488@faux.empty_completed_unsuccessfully_error
Alex Klein1699fab2022-09-08 08:46:06 -0600489@validate.require("gs_image_dir", "sysroot.build_target.name")
490def PushImage(
491 input_proto: "image_pb2.PushImageRequest",
492 _output_proto: "image_pb2.PushImageResponse",
493 config: "api.config.ApiConfig",
494):
495 """Push artifacts from the archive bucket to the release bucket.
Jack Neus761e1842020-12-01 18:20:11 +0000496
Alex Klein1699fab2022-09-08 08:46:06 -0600497 Wraps chromite/scripts/pushimage.py.
Jack Neus761e1842020-12-01 18:20:11 +0000498
Alex Klein1699fab2022-09-08 08:46:06 -0600499 Args:
500 input_proto: Input proto.
501 _output_proto: Output proto.
502 config: The API call config.
Jack Neus761e1842020-12-01 18:20:11 +0000503
Alex Klein1699fab2022-09-08 08:46:06 -0600504 Returns:
505 A controller return code (e.g. controller.RETURN_CODE_SUCCESS).
506 """
507 sign_types = []
508 if input_proto.sign_types:
509 for sign_type in input_proto.sign_types:
510 if sign_type not in SUPPORTED_IMAGE_TYPES:
511 logging.error("unsupported sign type %g", sign_type)
512 return controller.RETURN_CODE_INVALID_INPUT
513 sign_types.append(SUPPORTED_IMAGE_TYPES[sign_type])
Jack Neus761e1842020-12-01 18:20:11 +0000514
Alex Klein1699fab2022-09-08 08:46:06 -0600515 # If configured for validation only we're done here.
516 if config.validate_only:
517 return controller.RETURN_CODE_VALID_INPUT
Jack Neus761e1842020-12-01 18:20:11 +0000518
Alex Klein1699fab2022-09-08 08:46:06 -0600519 kwargs = {}
520 if input_proto.profile.name:
521 kwargs["profile"] = input_proto.profile.name
522 if input_proto.dest_bucket:
523 kwargs["dest_bucket"] = input_proto.dest_bucket
524 if input_proto.channels:
525 kwargs["force_channels"] = [
526 common_pb2.Channel.Name(channel).lower()[len("channel_") :]
527 for channel in input_proto.channels
528 ]
529 try:
530 channel_to_uris = pushimage.PushImage(
531 input_proto.gs_image_dir,
532 input_proto.sysroot.build_target.name,
533 dry_run=input_proto.dryrun,
534 sign_types=sign_types,
535 **kwargs,
536 )
537 except Exception:
538 logging.error("PushImage failed: ", exc_info=True)
539 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
540 if channel_to_uris:
541 for uris in channel_to_uris.values():
542 for uri in uris:
543 _output_proto.instructions.add().instructions_file_path = uri
544 return controller.RETURN_CODE_SUCCESS