blob: 2de6e833f0d1cb2158a7a5cc77b418365cd59b82 [file] [log] [blame]
Alex Klein2966e302019-01-17 13:29:38 -07001# Copyright 2018 The Chromium OS Authors. All rights reserved.
2# 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
Alex Klein27978a42021-07-27 14:18:10 -060010import copy
Jack Neus5e56fef2021-06-18 16:57:28 +000011import functools
Chris McDonald1672ddb2021-07-21 11:48:23 -060012import logging
Alex Klein2966e302019-01-17 13:29:38 -070013import os
Jack Neus94a35be2021-09-10 15:18:06 +000014from pathlib import Path
15from typing import List, NamedTuple, Set, Union
Alex Klein2966e302019-01-17 13:29:38 -070016
Alex Klein8cb365a2019-05-15 16:24:53 -060017from chromite.api import controller
Alex Klein076841b2019-08-29 15:19:39 -060018from chromite.api import faux
Alex Klein2b236722019-06-19 15:44:26 -060019from chromite.api import validate
Alex Kleine9a7dbf2020-10-06 18:12:12 -060020from chromite.api.controller import controller_util
David Burgerb171d652019-05-13 16:07:00 -060021from chromite.api.gen.chromiumos import common_pb2
Will Bradley9bc85452019-10-10 10:48:21 -060022from chromite.api.metrics import deserialize_metrics_log
George Engelbrechtc9a8e812021-06-16 18:14:17 -060023from chromite.lib import build_target_lib
24from chromite.lib import chroot_lib
Alex Klein56355682019-02-07 10:36:54 -070025from chromite.lib import constants
Chris McDonald1672ddb2021-07-21 11:48:23 -060026from chromite.lib import cros_build_lib
Alex Klein56355682019-02-07 10:36:54 -070027from chromite.lib import image_lib
George Engelbrechtc9a8e812021-06-16 18:14:17 -060028from chromite.lib import sysroot_lib
Jack Neus94a35be2021-09-10 15:18:06 +000029from chromite.service import packages as packages_service
Jack Neus761e1842020-12-01 18:20:11 +000030from chromite.scripts import pushimage
Alex Kleinb7cdbe62019-02-22 11:41:32 -070031from chromite.service import image
Will Bradley9bc85452019-10-10 10:48:21 -060032from chromite.utils import metrics
Alex Klein2966e302019-01-17 13:29:38 -070033
Alex Klein56355682019-02-07 10:36:54 -070034# The image.proto ImageType enum ids.
George Engelbrechtc55d6312021-05-05 12:11:13 -060035_BASE_ID = common_pb2.IMAGE_TYPE_BASE
36_DEV_ID = common_pb2.IMAGE_TYPE_DEV
37_TEST_ID = common_pb2.IMAGE_TYPE_TEST
38_BASE_VM_ID = common_pb2.IMAGE_TYPE_BASE_VM
39_TEST_VM_ID = common_pb2.IMAGE_TYPE_TEST_VM
40_RECOVERY_ID = common_pb2.IMAGE_TYPE_RECOVERY
41_FACTORY_ID = common_pb2.IMAGE_TYPE_FACTORY
42_FIRMWARE_ID = common_pb2.IMAGE_TYPE_FIRMWARE
43_BASE_GUEST_VM_ID = common_pb2.IMAGE_TYPE_BASE_GUEST_VM
44_TEST_GUEST_VM_ID = common_pb2.IMAGE_TYPE_TEST_GUEST_VM
Alex Klein56355682019-02-07 10:36:54 -070045
46# Dict to allow easily translating names to enum ids and vice versa.
47_IMAGE_MAPPING = {
48 _BASE_ID: constants.IMAGE_TYPE_BASE,
49 constants.IMAGE_TYPE_BASE: _BASE_ID,
50 _DEV_ID: constants.IMAGE_TYPE_DEV,
51 constants.IMAGE_TYPE_DEV: _DEV_ID,
52 _TEST_ID: constants.IMAGE_TYPE_TEST,
53 constants.IMAGE_TYPE_TEST: _TEST_ID,
Michael Mortenseneefe8952019-08-12 15:37:15 -060054 _RECOVERY_ID: constants.IMAGE_TYPE_RECOVERY,
55 constants.IMAGE_TYPE_RECOVERY: _RECOVERY_ID,
Alex Klein9039a952021-07-27 13:52:39 -060056 _FACTORY_ID: constants.IMAGE_TYPE_FACTORY_SHIM,
57 constants.IMAGE_TYPE_FACTORY_SHIM: _FACTORY_ID,
Michael Mortenseneefe8952019-08-12 15:37:15 -060058 _FIRMWARE_ID: constants.IMAGE_TYPE_FIRMWARE,
59 constants.IMAGE_TYPE_FIRMWARE: _FIRMWARE_ID,
Alex Klein56355682019-02-07 10:36:54 -070060}
61
George Engelbrecht9f4f8322021-03-08 12:04:17 -070062# Dict to describe the prerequisite built images for each VM image type.
Alex Klein21b95022019-05-09 14:14:46 -060063_VM_IMAGE_MAPPING = {
64 _BASE_VM_ID: _IMAGE_MAPPING[_BASE_ID],
65 _TEST_VM_ID: _IMAGE_MAPPING[_TEST_ID],
Trent Begin008cade2019-10-31 13:40:59 -060066 _BASE_GUEST_VM_ID: _IMAGE_MAPPING[_BASE_ID],
67 _TEST_GUEST_VM_ID: _IMAGE_MAPPING[_TEST_ID],
Alex Klein21b95022019-05-09 14:14:46 -060068}
69
George Engelbrecht9f4f8322021-03-08 12:04:17 -070070# Dict to describe the prerequisite built images for each mod image type.
71_MOD_IMAGE_MAPPING = {
72 _RECOVERY_ID: _IMAGE_MAPPING[_BASE_ID],
73}
74
Jack Neus761e1842020-12-01 18:20:11 +000075# Supported image types for PushImage.
76SUPPORTED_IMAGE_TYPES = {
77 common_pb2.IMAGE_TYPE_RECOVERY: constants.IMAGE_TYPE_RECOVERY,
78 common_pb2.IMAGE_TYPE_FACTORY: constants.IMAGE_TYPE_FACTORY,
79 common_pb2.IMAGE_TYPE_FIRMWARE: constants.IMAGE_TYPE_FIRMWARE,
80 common_pb2.IMAGE_TYPE_ACCESSORY_USBPD: constants.IMAGE_TYPE_ACCESSORY_USBPD,
81 common_pb2.IMAGE_TYPE_ACCESSORY_RWSIG: constants.IMAGE_TYPE_ACCESSORY_RWSIG,
Evan Benn4d061102022-02-14 12:50:45 +110082 common_pb2.IMAGE_TYPE_HPS_FIRMWARE: constants.IMAGE_TYPE_HPS_FIRMWARE,
Jack Neus761e1842020-12-01 18:20:11 +000083 common_pb2.IMAGE_TYPE_BASE: constants.IMAGE_TYPE_BASE,
George Engelbrecht9f4f8322021-03-08 12:04:17 -070084 common_pb2.IMAGE_TYPE_GSC_FIRMWARE: constants.IMAGE_TYPE_GSC_FIRMWARE,
Jack Neus761e1842020-12-01 18:20:11 +000085}
86
Alex Klein27978a42021-07-27 14:18:10 -060087# Built image directory symlink names. These names allow specifying a static
88# location for creation to simplify later archival stages. In practice, this
89# sets the symlink argument to build_packages.
90# Core are the build/dev/test images.
91# Use "latest" until we do a better job of passing through image directories,
92# e.g. for artifacts.
93LOCATION_CORE = 'latest'
94# The factory_install image.
95LOCATION_FACTORY = 'factory_shim'
96
97
98class ImageTypes(NamedTuple):
99 """Parsed image types."""
100 images: Set[str]
101 vms: Set[int]
102 mod_images: Set[int]
103
104 @property
105 def core_images(self) -> List[str]:
106 """The core images (base/dev/test) as a list."""
107 return list(self.images - {_IMAGE_MAPPING[_FACTORY_ID]}) or []
108
109 @property
110 def has_factory(self) -> bool:
111 """Whether the factory image is present."""
112 return _IMAGE_MAPPING[_FACTORY_ID] in self.images
113
114 @property
115 def factory(self) -> List[str]:
116 """A list with the factory type if set."""
117 return [_IMAGE_MAPPING[_FACTORY_ID]] if self.has_factory else []
118
Alex Klein56355682019-02-07 10:36:54 -0700119
Alex Kleinf5dc2632021-08-31 16:35:06 -0600120def _add_image_to_proto(output_proto, path: Union['Path', str], image_type: int,
121 board: str):
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700122 """Quick helper function to add a new image to the output proto."""
123 new_image = output_proto.images.add()
Alex Kleinf5dc2632021-08-31 16:35:06 -0600124 new_image.path = str(path)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700125 new_image.type = image_type
126 new_image.build_target.name = board
127
128
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600129def ExampleGetResponse():
130 """Give an example response to assemble upstream in caller artifacts."""
131 uabs = common_pb2.UploadedArtifactsByService
132 cabs = common_pb2.ArtifactsByService
133 return uabs.Sysroot(artifacts=[
134 uabs.Image.ArtifactPaths(
135 artifact_type=cabs.Image.ArtifactType.DLC_IMAGE,
136 paths=[
137 common_pb2.Path(
138 path='/tmp/dlc/dlc.img', location=common_pb2.Path.OUTSIDE)
139 ])
140 ])
141
142
143def GetArtifacts(in_proto: common_pb2.ArtifactsByService.Image,
Alex Kleincaace392021-07-26 14:28:13 -0600144 chroot: chroot_lib.Chroot, sysroot_class: sysroot_lib.Sysroot,
145 build_target: build_target_lib.BuildTarget,
146 output_dir) -> list:
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600147 """Builds and copies images to specified output_dir.
148
149 Copies (after optionally bundling) all required images into the output_dir,
150 returning a mapping of image type to a list of (output_dir) paths to
151 the desired files. Note that currently it is only processing one image (DLC),
152 but the future direction is to process all required images. Required images
153 are located within output_artifact.artifact_type.
154
155 Args:
156 in_proto: Proto request defining reqs.
157 chroot: The chroot proto used for these artifacts.
158 sysroot_class: The sysroot proto used for these artifacts.
159 build_target: The build target used for these artifacts.
160 output_dir: The path to write artifacts to.
161
162 Returns:
163 A list of dictionary mappings of ArtifactType to list of paths.
164 """
Pi-Hsun Shih8d9c8e42021-06-30 03:27:28 +0000165 base_path = chroot.full_path(sysroot_class.path)
Jack Neus5e56fef2021-06-18 16:57:28 +0000166 board = build_target.name
Jack Neus94a35be2021-09-10 15:18:06 +0000167 factory_shim_location = Path(
Jack Neuse77614d2021-10-11 14:10:27 +0000168 image_lib.GetLatestImageLink(board, pointer=LOCATION_FACTORY)).resolve()
Jack Neus5e56fef2021-06-18 16:57:28 +0000169
170 generated = []
171 dlc_func = functools.partial(image.copy_dlc_image, base_path)
Alex Klein27978a42021-07-27 14:18:10 -0600172 license_func = functools.partial(
173 image.copy_license_credits, board, symlink=LOCATION_CORE)
Jack Neus94a35be2021-09-10 15:18:06 +0000174 factory_image_func = functools.partial(
175 image.create_factory_image_zip,
176 chroot,
177 sysroot_class,
178 factory_shim_location,
179 packages_service.determine_full_version(),
180 )
Jack Neus5e56fef2021-06-18 16:57:28 +0000181 artifact_types = {
Alex Kleincaace392021-07-26 14:28:13 -0600182 in_proto.ArtifactType.DLC_IMAGE: dlc_func,
183 in_proto.ArtifactType.LICENSE_CREDITS: license_func,
Jack Neus94a35be2021-09-10 15:18:06 +0000184 in_proto.ArtifactType.FACTORY_IMAGE: factory_image_func,
Jack Neus5e56fef2021-06-18 16:57:28 +0000185 }
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600186
187 for output_artifact in in_proto.output_artifacts:
Jack Neus5e56fef2021-06-18 16:57:28 +0000188 for artifact_type, func in artifact_types.items():
189 if artifact_type in output_artifact.artifact_types:
190 result = func(output_dir)
191 if result:
192 generated.append({
193 'paths': [result] if isinstance(result, str) else result,
194 'type': artifact_type,
195 })
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600196
Jack Neus5e56fef2021-06-18 16:57:28 +0000197 return generated
Pi-Hsun Shih8d9c8e42021-06-30 03:27:28 +0000198
Alex Kleincaace392021-07-26 14:28:13 -0600199
Michael Mortensen10146cf2019-11-19 19:59:22 -0700200def _CreateResponse(_input_proto, output_proto, _config):
201 """Set output_proto success field on a successful Create response."""
202 output_proto.success = True
203
204
205@faux.success(_CreateResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700206@faux.empty_completed_unsuccessfully_error
Alex Klein2b236722019-06-19 15:44:26 -0600207@validate.require('build_target.name')
Alex Klein231d2da2019-07-22 16:44:45 -0600208@validate.validation_complete
Will Bradley9bc85452019-10-10 10:48:21 -0600209@metrics.collect_metrics
Alex Klein231d2da2019-07-22 16:44:45 -0600210def Create(input_proto, output_proto, _config):
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700211 """Build images.
Alex Klein56355682019-02-07 10:36:54 -0700212
213 Args:
214 input_proto (image_pb2.CreateImageRequest): The input message.
215 output_proto (image_pb2.CreateImageResult): The output message.
Alex Klein231d2da2019-07-22 16:44:45 -0600216 _config (api_config.ApiConfig): The API call config.
Alex Klein56355682019-02-07 10:36:54 -0700217 """
218 board = input_proto.build_target.name
Alex Klein56355682019-02-07 10:36:54 -0700219
Alex Klein56355682019-02-07 10:36:54 -0700220 # Build the base image if no images provided.
221 to_build = input_proto.image_types or [_BASE_ID]
Alex Klein56355682019-02-07 10:36:54 -0700222
Alex Klein27978a42021-07-27 14:18:10 -0600223 image_types = _ParseImagesToCreate(to_build)
Alex Klein21b95022019-05-09 14:14:46 -0600224 build_config = _ParseCreateBuildConfig(input_proto)
Alex Klein27978a42021-07-27 14:18:10 -0600225 factory_build_config = copy.copy(build_config)
226 build_config.symlink = LOCATION_CORE
227 factory_build_config.symlink = LOCATION_FACTORY
Alex Klein3d3eb632021-09-08 13:55:21 -0600228 factory_build_config.output_dir_suffix = LOCATION_FACTORY
Alex Klein56355682019-02-07 10:36:54 -0700229
Alex Klein27978a42021-07-27 14:18:10 -0600230 # Try building the core and factory images.
Alex Klein56355682019-02-07 10:36:54 -0700231 # Sorted isn't really necessary here, but it's much easier to test.
Alex Klein27978a42021-07-27 14:18:10 -0600232 core_result = image.Build(
233 board, sorted(image_types.core_images), config=build_config)
234 logging.debug('Core Result Images: %s', core_result.images)
Alex Klein56355682019-02-07 10:36:54 -0700235
Alex Klein27978a42021-07-27 14:18:10 -0600236 factory_result = image.Build(
237 board, image_types.factory, config=factory_build_config)
238 logging.debug('Factory Result Images: %s', factory_result.images)
Will Bradley29a49c22019-10-21 11:50:08 -0600239
Alex Klein27978a42021-07-27 14:18:10 -0600240 # A successful run will have no images missing, will have run at least one
241 # of the two image sets, and neither attempt errored. The no error condition
242 # should be redundant with no missing images, but is cheap insurance.
243 all_built = core_result.all_built and factory_result.all_built
244 one_ran = core_result.build_run or factory_result.build_run
245 no_errors = not core_result.run_error and not factory_result.run_error
246 output_proto.success = success = all_built and one_ran and no_errors
Will Bradley29a49c22019-10-21 11:50:08 -0600247
Alex Klein27978a42021-07-27 14:18:10 -0600248 if success:
249 # Success! We need to record the images we built in the output.
250 all_images = {**core_result.images, **factory_result.images}
251 for img_name, img_path in all_images.items():
Alex Kleinf5dc2632021-08-31 16:35:06 -0600252 _add_image_to_proto(output_proto, img_path, _IMAGE_MAPPING[img_name],
Alex Klein27978a42021-07-27 14:18:10 -0600253 board)
254
255 # Build and record VMs as necessary.
256 for vm_type in image_types.vms:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700257 is_test = vm_type in [_TEST_VM_ID, _TEST_GUEST_VM_ID]
Alex Klein27978a42021-07-27 14:18:10 -0600258 img_type = _IMAGE_MAPPING[_TEST_ID if is_test else _BASE_ID]
259 img_dir = core_result.images[img_type].parent.resolve()
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700260 try:
261 if vm_type in [_BASE_GUEST_VM_ID, _TEST_GUEST_VM_ID]:
Alex Klein27978a42021-07-27 14:18:10 -0600262 vm_path = image.CreateGuestVm(
263 board, is_test=is_test, image_dir=img_dir)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700264 else:
265 vm_path = image.CreateVm(
Alex Klein27978a42021-07-27 14:18:10 -0600266 board,
267 disk_layout=build_config.disk_layout,
268 is_test=is_test,
269 image_dir=img_dir)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700270 except image.ImageToVmError as e:
271 cros_build_lib.Die(e)
Will Bradley29a49c22019-10-21 11:50:08 -0600272
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700273 _add_image_to_proto(output_proto, vm_path, vm_type, board)
274
Alex Klein27978a42021-07-27 14:18:10 -0600275 # Build and record any mod images.
276 for mod_type in image_types.mod_images:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700277 if mod_type == _RECOVERY_ID:
Alex Klein27978a42021-07-27 14:18:10 -0600278 base_image_path = core_result.images[constants.IMAGE_TYPE_BASE]
Alex Kleincaace392021-07-26 14:28:13 -0600279 result = image.BuildRecoveryImage(
280 board=board, image_path=base_image_path)
Alex Klein27978a42021-07-27 14:18:10 -0600281 if result.all_built:
282 _add_image_to_proto(output_proto,
283 result.images[_IMAGE_MAPPING[mod_type]], mod_type,
284 board)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700285 else:
286 cros_build_lib.Die('Failed to create recovery image.')
287 else:
288 cros_build_lib.Die('_RECOVERY_ID is the only mod_image_type.')
Will Bradley29a49c22019-10-21 11:50:08 -0600289
290 # Read metric events log and pipe them into output_proto.events.
291 deserialize_metrics_log(output_proto.events, prefix=board)
292 return controller.RETURN_CODE_SUCCESS
293
Alex Klein1bcd9882019-03-19 13:25:24 -0600294 else:
Alex Klein2557b4f2019-07-11 14:34:00 -0600295 # Failure, include all of the failed packages in the output when available.
Alex Klein27978a42021-07-27 14:18:10 -0600296 packages = core_result.failed_packages + factory_result.failed_packages
297 if not packages:
Alex Klein2557b4f2019-07-11 14:34:00 -0600298 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
299
Alex Klein27978a42021-07-27 14:18:10 -0600300 for package in packages:
Alex Klein1bcd9882019-03-19 13:25:24 -0600301 current = output_proto.failed_packages.add()
Alex Kleine9a7dbf2020-10-06 18:12:12 -0600302 controller_util.serialize_package_info(package, current)
Alex Klein1bcd9882019-03-19 13:25:24 -0600303
Alex Klein8cb365a2019-05-15 16:24:53 -0600304 return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
Alex Klein1bcd9882019-03-19 13:25:24 -0600305
Alex Kleincaace392021-07-26 14:28:13 -0600306
Alex Klein27978a42021-07-27 14:18:10 -0600307def _ParseImagesToCreate(to_build: List[int]) -> ImageTypes:
Alex Klein21b95022019-05-09 14:14:46 -0600308 """Helper function to parse the image types to build.
309
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700310 This function expresses the dependencies of each image type and adds
311 the requisite image types if they're not explicitly defined.
Alex Klein21b95022019-05-09 14:14:46 -0600312
313 Args:
Alex Klein27978a42021-07-27 14:18:10 -0600314 to_build: The image type list.
Alex Klein21b95022019-05-09 14:14:46 -0600315
316 Returns:
Alex Klein27978a42021-07-27 14:18:10 -0600317 ImageTypes: The parsed images to build.
Alex Klein21b95022019-05-09 14:14:46 -0600318 """
319 image_types = set()
320 vm_types = set()
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700321 mod_image_types = set()
Alex Klein21b95022019-05-09 14:14:46 -0600322 for current in to_build:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700323 # Find out if it's a special case (vm, img mod), or just any old image.
324 if current in _VM_IMAGE_MAPPING:
Alex Klein21b95022019-05-09 14:14:46 -0600325 vm_types.add(current)
326 # Make sure we build the image required to build the VM.
327 image_types.add(_VM_IMAGE_MAPPING[current])
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700328 elif current in _MOD_IMAGE_MAPPING:
329 mod_image_types.add(current)
330 image_types.add(_MOD_IMAGE_MAPPING[current])
331 elif current in _IMAGE_MAPPING:
332 image_types.add(_IMAGE_MAPPING[current])
Alex Klein21b95022019-05-09 14:14:46 -0600333 else:
334 # Not expected, but at least it will be obvious if this comes up.
335 cros_build_lib.Die(
336 "The service's known image types do not match those in image.proto. "
337 'Unknown Enum ID: %s' % current)
338
Trent Begin008cade2019-10-31 13:40:59 -0600339 # We can only build one type of these images at a time since image_to_vm.sh
340 # uses the default path if a name is not provided.
341 if vm_types.issuperset({_BASE_VM_ID, _TEST_VM_ID}):
Alex Klein21b95022019-05-09 14:14:46 -0600342 cros_build_lib.Die('Cannot create more than one VM.')
343
Alex Klein27978a42021-07-27 14:18:10 -0600344 return ImageTypes(
345 images=image_types, vms=vm_types, mod_images=mod_image_types)
Alex Klein21b95022019-05-09 14:14:46 -0600346
347
348def _ParseCreateBuildConfig(input_proto):
349 """Helper to parse the image build config for Create."""
350 enable_rootfs_verification = not input_proto.disable_rootfs_verification
351 version = input_proto.version or None
352 disk_layout = input_proto.disk_layout or None
353 builder_path = input_proto.builder_path or None
354 return image.BuildConfig(
Jack Neus761e1842020-12-01 18:20:11 +0000355 enable_rootfs_verification=enable_rootfs_verification,
356 replace=True,
357 version=version,
358 disk_layout=disk_layout,
359 builder_path=builder_path,
Alex Klein21b95022019-05-09 14:14:46 -0600360 )
361
Alex Klein1bcd9882019-03-19 13:25:24 -0600362
Michael Mortensen10146cf2019-11-19 19:59:22 -0700363def _SignerTestResponse(_input_proto, output_proto, _config):
364 """Set output_proto success field on a successful SignerTest response."""
365 output_proto.success = True
366 return controller.RETURN_CODE_SUCCESS
367
368
369@faux.success(_SignerTestResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700370@faux.empty_completed_unsuccessfully_error
Michael Mortensenc83c9952019-08-05 12:15:12 -0600371@validate.exists('image.path')
Alex Klein231d2da2019-07-22 16:44:45 -0600372@validate.validation_complete
373def SignerTest(input_proto, output_proto, _config):
Michael Mortensenc83c9952019-08-05 12:15:12 -0600374 """Run image tests.
375
376 Args:
377 input_proto (image_pb2.ImageTestRequest): The input message.
378 output_proto (image_pb2.ImageTestResult): The output message.
Alex Klein231d2da2019-07-22 16:44:45 -0600379 _config (api_config.ApiConfig): The API call config.
Michael Mortensenc83c9952019-08-05 12:15:12 -0600380 """
Michael Mortensenc83c9952019-08-05 12:15:12 -0600381 image_path = input_proto.image.path
382
Alex Klein231d2da2019-07-22 16:44:45 -0600383 result = image_lib.SecurityTest(image=image_path)
Michael Mortensenc83c9952019-08-05 12:15:12 -0600384 output_proto.success = result
385 if result:
386 return controller.RETURN_CODE_SUCCESS
387 else:
388 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
389
Alex Klein076841b2019-08-29 15:19:39 -0600390
Michael Mortensen10146cf2019-11-19 19:59:22 -0700391def _TestResponse(_input_proto, output_proto, _config):
392 """Set output_proto success field on a successful Test response."""
393 output_proto.success = True
394 return controller.RETURN_CODE_SUCCESS
395
396
397@faux.success(_TestResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700398@faux.empty_completed_unsuccessfully_error
Alex Klein2b236722019-06-19 15:44:26 -0600399@validate.require('build_target.name', 'result.directory')
400@validate.exists('image.path')
Alex Klein231d2da2019-07-22 16:44:45 -0600401def Test(input_proto, output_proto, config):
Alex Klein2966e302019-01-17 13:29:38 -0700402 """Run image tests.
403
404 Args:
405 input_proto (image_pb2.ImageTestRequest): The input message.
406 output_proto (image_pb2.ImageTestResult): The output message.
Alex Klein231d2da2019-07-22 16:44:45 -0600407 config (api_config.ApiConfig): The API call config.
Alex Klein2966e302019-01-17 13:29:38 -0700408 """
409 image_path = input_proto.image.path
410 board = input_proto.build_target.name
411 result_directory = input_proto.result.directory
412
Alex Klein2966e302019-01-17 13:29:38 -0700413 if not os.path.isfile(image_path) or not image_path.endswith('.bin'):
Alex Klein4f0eb432019-05-02 13:56:04 -0600414 cros_build_lib.Die(
Alex Klein2966e302019-01-17 13:29:38 -0700415 'The image.path must be an existing image file with a .bin extension.')
416
Alex Klein231d2da2019-07-22 16:44:45 -0600417 if config.validate_only:
418 return controller.RETURN_CODE_VALID_INPUT
419
Alex Klein8cb365a2019-05-15 16:24:53 -0600420 success = image.Test(board, result_directory, image_dir=image_path)
421 output_proto.success = success
422
423 if success:
424 return controller.RETURN_CODE_SUCCESS
425 else:
426 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
Jack Neus761e1842020-12-01 18:20:11 +0000427
428
429@faux.empty_success
430@faux.empty_completed_unsuccessfully_error
431@validate.require('gs_image_dir', 'sysroot.build_target.name')
432def PushImage(input_proto, _output_proto, config):
433 """Push artifacts from the archive bucket to the release bucket.
434
435 Wraps chromite/scripts/pushimage.py.
436
437 Args:
438 input_proto (PushImageRequest): Input proto.
439 _output_proto (PushImageResponse): Output proto.
440 config (api.config.ApiConfig): The API call config.
441
442 Returns:
443 A controller return code (e.g. controller.RETURN_CODE_SUCCESS).
444 """
445 sign_types = []
446 if input_proto.sign_types:
447 for sign_type in input_proto.sign_types:
448 if sign_type not in SUPPORTED_IMAGE_TYPES:
449 logging.error('unsupported sign type %g', sign_type)
450 return controller.RETURN_CODE_INVALID_INPUT
451 sign_types.append(SUPPORTED_IMAGE_TYPES[sign_type])
452
453 # If configured for validation only we're done here.
454 if config.validate_only:
455 return controller.RETURN_CODE_VALID_INPUT
456
Jack Neus485a9d22020-12-21 03:15:15 +0000457 kwargs = {}
458 if input_proto.profile.name:
459 kwargs['profile'] = input_proto.profile.name
460 if input_proto.dest_bucket:
461 kwargs['dest_bucket'] = input_proto.dest_bucket
Jack Neuse77614d2021-10-11 14:10:27 +0000462 if input_proto.channels:
463 kwargs['force_channels'] = [
464 common_pb2.Channel.Name(channel).lower()[len('channel_'):]
465 for channel in input_proto.channels
466 ]
Jack Neus761e1842020-12-01 18:20:11 +0000467 try:
Greg Edelston6902e3d2022-01-27 12:19:38 -0700468 channel_to_uris = pushimage.PushImage(
Jack Neus761e1842020-12-01 18:20:11 +0000469 input_proto.gs_image_dir,
470 input_proto.sysroot.build_target.name,
471 dry_run=input_proto.dryrun,
Jack Neus485a9d22020-12-21 03:15:15 +0000472 sign_types=sign_types,
473 **kwargs)
Jack Neus761e1842020-12-01 18:20:11 +0000474 except Exception:
Jack Neuse3150a42021-01-29 17:16:36 +0000475 logging.error('PushImage failed: ', exc_info=True)
Jack Neus761e1842020-12-01 18:20:11 +0000476 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
Greg Edelston6902e3d2022-01-27 12:19:38 -0700477 for uris in channel_to_uris.values():
478 for uri in uris:
479 _output_proto.instructions.add().instructions_file_path = uri
480 return controller.RETURN_CODE_SUCCESS