blob: 9572b4a700a8e2ee235e919fc8b764022e75ff36 [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
Kevin Shelton5b21c8b2022-04-04 17:04:13 -070015from typing import List, NamedTuple, Set, TYPE_CHECKING, 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
Alex Kleinaef41942022-04-19 14:13:17 -060028from chromite.lib import metrics_lib
George Engelbrechtc9a8e812021-06-16 18:14:17 -060029from chromite.lib import sysroot_lib
Jack Neus761e1842020-12-01 18:20:11 +000030from chromite.scripts import pushimage
Alex Kleinb7cdbe62019-02-22 11:41:32 -070031from chromite.service import image
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040032from chromite.service import packages as packages_service
33
Alex Klein2966e302019-01-17 13:29:38 -070034
Kevin Shelton5b21c8b2022-04-04 17:04:13 -070035if TYPE_CHECKING:
36 from chromite.api import api_config
37 from chromite.api.gen.chromite.api import image_pb2
38
Alex Klein56355682019-02-07 10:36:54 -070039# The image.proto ImageType enum ids.
George Engelbrechtc55d6312021-05-05 12:11:13 -060040_BASE_ID = common_pb2.IMAGE_TYPE_BASE
41_DEV_ID = common_pb2.IMAGE_TYPE_DEV
42_TEST_ID = common_pb2.IMAGE_TYPE_TEST
43_BASE_VM_ID = common_pb2.IMAGE_TYPE_BASE_VM
44_TEST_VM_ID = common_pb2.IMAGE_TYPE_TEST_VM
45_RECOVERY_ID = common_pb2.IMAGE_TYPE_RECOVERY
46_FACTORY_ID = common_pb2.IMAGE_TYPE_FACTORY
47_FIRMWARE_ID = common_pb2.IMAGE_TYPE_FIRMWARE
48_BASE_GUEST_VM_ID = common_pb2.IMAGE_TYPE_BASE_GUEST_VM
49_TEST_GUEST_VM_ID = common_pb2.IMAGE_TYPE_TEST_GUEST_VM
Alex Klein56355682019-02-07 10:36:54 -070050
51# Dict to allow easily translating names to enum ids and vice versa.
52_IMAGE_MAPPING = {
53 _BASE_ID: constants.IMAGE_TYPE_BASE,
54 constants.IMAGE_TYPE_BASE: _BASE_ID,
55 _DEV_ID: constants.IMAGE_TYPE_DEV,
56 constants.IMAGE_TYPE_DEV: _DEV_ID,
57 _TEST_ID: constants.IMAGE_TYPE_TEST,
58 constants.IMAGE_TYPE_TEST: _TEST_ID,
Michael Mortenseneefe8952019-08-12 15:37:15 -060059 _RECOVERY_ID: constants.IMAGE_TYPE_RECOVERY,
60 constants.IMAGE_TYPE_RECOVERY: _RECOVERY_ID,
Alex Klein9039a952021-07-27 13:52:39 -060061 _FACTORY_ID: constants.IMAGE_TYPE_FACTORY_SHIM,
62 constants.IMAGE_TYPE_FACTORY_SHIM: _FACTORY_ID,
Michael Mortenseneefe8952019-08-12 15:37:15 -060063 _FIRMWARE_ID: constants.IMAGE_TYPE_FIRMWARE,
64 constants.IMAGE_TYPE_FIRMWARE: _FIRMWARE_ID,
Alex Klein56355682019-02-07 10:36:54 -070065}
66
George Engelbrecht9f4f8322021-03-08 12:04:17 -070067# Dict to describe the prerequisite built images for each VM image type.
Alex Klein21b95022019-05-09 14:14:46 -060068_VM_IMAGE_MAPPING = {
69 _BASE_VM_ID: _IMAGE_MAPPING[_BASE_ID],
70 _TEST_VM_ID: _IMAGE_MAPPING[_TEST_ID],
Trent Begin008cade2019-10-31 13:40:59 -060071 _BASE_GUEST_VM_ID: _IMAGE_MAPPING[_BASE_ID],
72 _TEST_GUEST_VM_ID: _IMAGE_MAPPING[_TEST_ID],
Alex Klein21b95022019-05-09 14:14:46 -060073}
74
George Engelbrecht9f4f8322021-03-08 12:04:17 -070075# Dict to describe the prerequisite built images for each mod image type.
76_MOD_IMAGE_MAPPING = {
77 _RECOVERY_ID: _IMAGE_MAPPING[_BASE_ID],
78}
79
Jack Neus761e1842020-12-01 18:20:11 +000080# Supported image types for PushImage.
81SUPPORTED_IMAGE_TYPES = {
82 common_pb2.IMAGE_TYPE_RECOVERY: constants.IMAGE_TYPE_RECOVERY,
83 common_pb2.IMAGE_TYPE_FACTORY: constants.IMAGE_TYPE_FACTORY,
84 common_pb2.IMAGE_TYPE_FIRMWARE: constants.IMAGE_TYPE_FIRMWARE,
85 common_pb2.IMAGE_TYPE_ACCESSORY_USBPD: constants.IMAGE_TYPE_ACCESSORY_USBPD,
86 common_pb2.IMAGE_TYPE_ACCESSORY_RWSIG: constants.IMAGE_TYPE_ACCESSORY_RWSIG,
Evan Benn4d061102022-02-14 12:50:45 +110087 common_pb2.IMAGE_TYPE_HPS_FIRMWARE: constants.IMAGE_TYPE_HPS_FIRMWARE,
Jack Neus761e1842020-12-01 18:20:11 +000088 common_pb2.IMAGE_TYPE_BASE: constants.IMAGE_TYPE_BASE,
George Engelbrecht9f4f8322021-03-08 12:04:17 -070089 common_pb2.IMAGE_TYPE_GSC_FIRMWARE: constants.IMAGE_TYPE_GSC_FIRMWARE,
Jack Neus761e1842020-12-01 18:20:11 +000090}
91
Alex Klein27978a42021-07-27 14:18:10 -060092# Built image directory symlink names. These names allow specifying a static
93# location for creation to simplify later archival stages. In practice, this
94# sets the symlink argument to build_packages.
95# Core are the build/dev/test images.
96# Use "latest" until we do a better job of passing through image directories,
97# e.g. for artifacts.
98LOCATION_CORE = 'latest'
99# The factory_install image.
100LOCATION_FACTORY = 'factory_shim'
101
102
103class ImageTypes(NamedTuple):
104 """Parsed image types."""
105 images: Set[str]
106 vms: Set[int]
107 mod_images: Set[int]
108
109 @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 []
113
114 @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 []
123
Alex Klein56355682019-02-07 10:36:54 -0700124
Alex Kleinf5dc2632021-08-31 16:35:06 -0600125def _add_image_to_proto(output_proto, path: Union['Path', str], image_type: int,
126 board: str):
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700127 """Quick helper function to add a new image to the output proto."""
128 new_image = output_proto.images.add()
Alex Kleinf5dc2632021-08-31 16:35:06 -0600129 new_image.path = str(path)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700130 new_image.type = image_type
131 new_image.build_target.name = board
132
133
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600134def ExampleGetResponse():
135 """Give an example response to assemble upstream in caller artifacts."""
136 uabs = common_pb2.UploadedArtifactsByService
137 cabs = common_pb2.ArtifactsByService
138 return uabs.Sysroot(artifacts=[
139 uabs.Image.ArtifactPaths(
140 artifact_type=cabs.Image.ArtifactType.DLC_IMAGE,
141 paths=[
142 common_pb2.Path(
143 path='/tmp/dlc/dlc.img', location=common_pb2.Path.OUTSIDE)
144 ])
145 ])
146
147
148def GetArtifacts(in_proto: common_pb2.ArtifactsByService.Image,
Alex Kleincaace392021-07-26 14:28:13 -0600149 chroot: chroot_lib.Chroot, sysroot_class: sysroot_lib.Sysroot,
150 build_target: build_target_lib.BuildTarget,
151 output_dir) -> list:
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600152 """Builds and copies images to specified output_dir.
153
154 Copies (after optionally bundling) all required images into the output_dir,
155 returning a mapping of image type to a list of (output_dir) paths to
156 the desired files. Note that currently it is only processing one image (DLC),
157 but the future direction is to process all required images. Required images
158 are located within output_artifact.artifact_type.
159
160 Args:
161 in_proto: Proto request defining reqs.
162 chroot: The chroot proto used for these artifacts.
163 sysroot_class: The sysroot proto used for these artifacts.
164 build_target: The build target used for these artifacts.
165 output_dir: The path to write artifacts to.
166
167 Returns:
168 A list of dictionary mappings of ArtifactType to list of paths.
169 """
Pi-Hsun Shih8d9c8e42021-06-30 03:27:28 +0000170 base_path = chroot.full_path(sysroot_class.path)
Jack Neus5e56fef2021-06-18 16:57:28 +0000171 board = build_target.name
Jack Neus94a35be2021-09-10 15:18:06 +0000172 factory_shim_location = Path(
Jack Neuse77614d2021-10-11 14:10:27 +0000173 image_lib.GetLatestImageLink(board, pointer=LOCATION_FACTORY)).resolve()
Jack Neus5e56fef2021-06-18 16:57:28 +0000174
175 generated = []
176 dlc_func = functools.partial(image.copy_dlc_image, base_path)
Alex Klein27978a42021-07-27 14:18:10 -0600177 license_func = functools.partial(
178 image.copy_license_credits, board, symlink=LOCATION_CORE)
Jack Neus94a35be2021-09-10 15:18:06 +0000179 factory_image_func = functools.partial(
180 image.create_factory_image_zip,
181 chroot,
182 sysroot_class,
183 factory_shim_location,
184 packages_service.determine_full_version(),
185 )
Jack Neus5e56fef2021-06-18 16:57:28 +0000186 artifact_types = {
Alex Kleincaace392021-07-26 14:28:13 -0600187 in_proto.ArtifactType.DLC_IMAGE: dlc_func,
188 in_proto.ArtifactType.LICENSE_CREDITS: license_func,
Jack Neus94a35be2021-09-10 15:18:06 +0000189 in_proto.ArtifactType.FACTORY_IMAGE: factory_image_func,
Jack Neus5e56fef2021-06-18 16:57:28 +0000190 }
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600191
192 for output_artifact in in_proto.output_artifacts:
Jack Neus5e56fef2021-06-18 16:57:28 +0000193 for artifact_type, func in artifact_types.items():
194 if artifact_type in output_artifact.artifact_types:
195 result = func(output_dir)
196 if result:
197 generated.append({
198 'paths': [result] if isinstance(result, str) else result,
199 'type': artifact_type,
200 })
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600201
Jack Neus5e56fef2021-06-18 16:57:28 +0000202 return generated
Pi-Hsun Shih8d9c8e42021-06-30 03:27:28 +0000203
Alex Kleincaace392021-07-26 14:28:13 -0600204
Michael Mortensen10146cf2019-11-19 19:59:22 -0700205def _CreateResponse(_input_proto, output_proto, _config):
206 """Set output_proto success field on a successful Create response."""
207 output_proto.success = True
208
209
210@faux.success(_CreateResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700211@faux.empty_completed_unsuccessfully_error
Alex Klein2b236722019-06-19 15:44:26 -0600212@validate.require('build_target.name')
Alex Klein231d2da2019-07-22 16:44:45 -0600213@validate.validation_complete
Alex Kleinaef41942022-04-19 14:13:17 -0600214@metrics_lib.collect_metrics
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700215def Create(input_proto: 'image_pb2.CreateImageRequest',
216 output_proto: 'image_pb2.CreateImageResult',
217 _config: 'api_config.ApiConfig'):
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700218 """Build images.
Alex Klein56355682019-02-07 10:36:54 -0700219
220 Args:
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700221 input_proto: The input message.
222 output_proto: The output message.
223 _config: The API call config.
Alex Klein56355682019-02-07 10:36:54 -0700224 """
225 board = input_proto.build_target.name
Alex Klein56355682019-02-07 10:36:54 -0700226
Alex Klein56355682019-02-07 10:36:54 -0700227 # Build the base image if no images provided.
228 to_build = input_proto.image_types or [_BASE_ID]
Alex Klein56355682019-02-07 10:36:54 -0700229
Alex Klein27978a42021-07-27 14:18:10 -0600230 image_types = _ParseImagesToCreate(to_build)
Alex Klein21b95022019-05-09 14:14:46 -0600231 build_config = _ParseCreateBuildConfig(input_proto)
Alex Klein27978a42021-07-27 14:18:10 -0600232 factory_build_config = copy.copy(build_config)
233 build_config.symlink = LOCATION_CORE
234 factory_build_config.symlink = LOCATION_FACTORY
Alex Klein3d3eb632021-09-08 13:55:21 -0600235 factory_build_config.output_dir_suffix = LOCATION_FACTORY
Alex Klein56355682019-02-07 10:36:54 -0700236
Alex Klein27978a42021-07-27 14:18:10 -0600237 # Try building the core and factory images.
Alex Klein56355682019-02-07 10:36:54 -0700238 # Sorted isn't really necessary here, but it's much easier to test.
Alex Klein27978a42021-07-27 14:18:10 -0600239 core_result = image.Build(
240 board, sorted(image_types.core_images), config=build_config)
241 logging.debug('Core Result Images: %s', core_result.images)
Alex Klein56355682019-02-07 10:36:54 -0700242
Alex Klein27978a42021-07-27 14:18:10 -0600243 factory_result = image.Build(
244 board, image_types.factory, config=factory_build_config)
245 logging.debug('Factory Result Images: %s', factory_result.images)
Will Bradley29a49c22019-10-21 11:50:08 -0600246
Alex Klein27978a42021-07-27 14:18:10 -0600247 # A successful run will have no images missing, will have run at least one
248 # of the two image sets, and neither attempt errored. The no error condition
249 # should be redundant with no missing images, but is cheap insurance.
250 all_built = core_result.all_built and factory_result.all_built
251 one_ran = core_result.build_run or factory_result.build_run
252 no_errors = not core_result.run_error and not factory_result.run_error
253 output_proto.success = success = all_built and one_ran and no_errors
Will Bradley29a49c22019-10-21 11:50:08 -0600254
Alex Klein27978a42021-07-27 14:18:10 -0600255 if success:
256 # Success! We need to record the images we built in the output.
257 all_images = {**core_result.images, **factory_result.images}
258 for img_name, img_path in all_images.items():
Alex Kleinf5dc2632021-08-31 16:35:06 -0600259 _add_image_to_proto(output_proto, img_path, _IMAGE_MAPPING[img_name],
Alex Klein27978a42021-07-27 14:18:10 -0600260 board)
261
262 # Build and record VMs as necessary.
263 for vm_type in image_types.vms:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700264 is_test = vm_type in [_TEST_VM_ID, _TEST_GUEST_VM_ID]
Alex Klein27978a42021-07-27 14:18:10 -0600265 img_type = _IMAGE_MAPPING[_TEST_ID if is_test else _BASE_ID]
266 img_dir = core_result.images[img_type].parent.resolve()
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700267 try:
268 if vm_type in [_BASE_GUEST_VM_ID, _TEST_GUEST_VM_ID]:
Alex Klein27978a42021-07-27 14:18:10 -0600269 vm_path = image.CreateGuestVm(
270 board, is_test=is_test, image_dir=img_dir)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700271 else:
272 vm_path = image.CreateVm(
Alex Klein27978a42021-07-27 14:18:10 -0600273 board,
274 disk_layout=build_config.disk_layout,
275 is_test=is_test,
276 image_dir=img_dir)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700277 except image.ImageToVmError as e:
278 cros_build_lib.Die(e)
Will Bradley29a49c22019-10-21 11:50:08 -0600279
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700280 _add_image_to_proto(output_proto, vm_path, vm_type, board)
281
Alex Klein27978a42021-07-27 14:18:10 -0600282 # Build and record any mod images.
283 for mod_type in image_types.mod_images:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700284 if mod_type == _RECOVERY_ID:
Alex Klein27978a42021-07-27 14:18:10 -0600285 base_image_path = core_result.images[constants.IMAGE_TYPE_BASE]
Alex Kleincaace392021-07-26 14:28:13 -0600286 result = image.BuildRecoveryImage(
287 board=board, image_path=base_image_path)
Alex Klein27978a42021-07-27 14:18:10 -0600288 if result.all_built:
289 _add_image_to_proto(output_proto,
290 result.images[_IMAGE_MAPPING[mod_type]], mod_type,
291 board)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700292 else:
293 cros_build_lib.Die('Failed to create recovery image.')
294 else:
295 cros_build_lib.Die('_RECOVERY_ID is the only mod_image_type.')
Will Bradley29a49c22019-10-21 11:50:08 -0600296
297 # Read metric events log and pipe them into output_proto.events.
298 deserialize_metrics_log(output_proto.events, prefix=board)
299 return controller.RETURN_CODE_SUCCESS
300
Alex Klein1bcd9882019-03-19 13:25:24 -0600301 else:
Alex Klein2557b4f2019-07-11 14:34:00 -0600302 # Failure, include all of the failed packages in the output when available.
Alex Klein27978a42021-07-27 14:18:10 -0600303 packages = core_result.failed_packages + factory_result.failed_packages
304 if not packages:
Alex Klein2557b4f2019-07-11 14:34:00 -0600305 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
306
Alex Klein27978a42021-07-27 14:18:10 -0600307 for package in packages:
Alex Klein1bcd9882019-03-19 13:25:24 -0600308 current = output_proto.failed_packages.add()
Alex Kleine9a7dbf2020-10-06 18:12:12 -0600309 controller_util.serialize_package_info(package, current)
Alex Klein1bcd9882019-03-19 13:25:24 -0600310
Alex Klein8cb365a2019-05-15 16:24:53 -0600311 return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
Alex Klein1bcd9882019-03-19 13:25:24 -0600312
Alex Kleincaace392021-07-26 14:28:13 -0600313
Alex Klein27978a42021-07-27 14:18:10 -0600314def _ParseImagesToCreate(to_build: List[int]) -> ImageTypes:
Alex Klein21b95022019-05-09 14:14:46 -0600315 """Helper function to parse the image types to build.
316
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700317 This function expresses the dependencies of each image type and adds
318 the requisite image types if they're not explicitly defined.
Alex Klein21b95022019-05-09 14:14:46 -0600319
320 Args:
Alex Klein27978a42021-07-27 14:18:10 -0600321 to_build: The image type list.
Alex Klein21b95022019-05-09 14:14:46 -0600322
323 Returns:
Alex Klein27978a42021-07-27 14:18:10 -0600324 ImageTypes: The parsed images to build.
Alex Klein21b95022019-05-09 14:14:46 -0600325 """
326 image_types = set()
327 vm_types = set()
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700328 mod_image_types = set()
Alex Klein21b95022019-05-09 14:14:46 -0600329 for current in to_build:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700330 # Find out if it's a special case (vm, img mod), or just any old image.
331 if current in _VM_IMAGE_MAPPING:
Alex Klein21b95022019-05-09 14:14:46 -0600332 vm_types.add(current)
333 # Make sure we build the image required to build the VM.
334 image_types.add(_VM_IMAGE_MAPPING[current])
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700335 elif current in _MOD_IMAGE_MAPPING:
336 mod_image_types.add(current)
337 image_types.add(_MOD_IMAGE_MAPPING[current])
338 elif current in _IMAGE_MAPPING:
339 image_types.add(_IMAGE_MAPPING[current])
Alex Klein21b95022019-05-09 14:14:46 -0600340 else:
341 # Not expected, but at least it will be obvious if this comes up.
342 cros_build_lib.Die(
343 "The service's known image types do not match those in image.proto. "
344 'Unknown Enum ID: %s' % current)
345
Trent Begin008cade2019-10-31 13:40:59 -0600346 # We can only build one type of these images at a time since image_to_vm.sh
347 # uses the default path if a name is not provided.
348 if vm_types.issuperset({_BASE_VM_ID, _TEST_VM_ID}):
Alex Klein21b95022019-05-09 14:14:46 -0600349 cros_build_lib.Die('Cannot create more than one VM.')
350
Alex Klein27978a42021-07-27 14:18:10 -0600351 return ImageTypes(
352 images=image_types, vms=vm_types, mod_images=mod_image_types)
Alex Klein21b95022019-05-09 14:14:46 -0600353
354
355def _ParseCreateBuildConfig(input_proto):
356 """Helper to parse the image build config for Create."""
357 enable_rootfs_verification = not input_proto.disable_rootfs_verification
358 version = input_proto.version or None
359 disk_layout = input_proto.disk_layout or None
360 builder_path = input_proto.builder_path or None
361 return image.BuildConfig(
Jack Neus761e1842020-12-01 18:20:11 +0000362 enable_rootfs_verification=enable_rootfs_verification,
363 replace=True,
364 version=version,
365 disk_layout=disk_layout,
366 builder_path=builder_path,
Alex Klein21b95022019-05-09 14:14:46 -0600367 )
368
Alex Klein1bcd9882019-03-19 13:25:24 -0600369
Michael Mortensen10146cf2019-11-19 19:59:22 -0700370def _SignerTestResponse(_input_proto, output_proto, _config):
371 """Set output_proto success field on a successful SignerTest response."""
372 output_proto.success = True
373 return controller.RETURN_CODE_SUCCESS
374
375
376@faux.success(_SignerTestResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700377@faux.empty_completed_unsuccessfully_error
Michael Mortensenc83c9952019-08-05 12:15:12 -0600378@validate.exists('image.path')
Alex Klein231d2da2019-07-22 16:44:45 -0600379@validate.validation_complete
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700380def SignerTest(input_proto: 'image_pb2.ImageTestRequest',
381 output_proto: 'image_pb2.ImageTestRequest',
382 _config: 'api_config.ApiConfig'):
Michael Mortensenc83c9952019-08-05 12:15:12 -0600383 """Run image tests.
384
385 Args:
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700386 input_proto: The input message.
387 output_proto: The output message.
388 _config: The API call config.
Michael Mortensenc83c9952019-08-05 12:15:12 -0600389 """
Michael Mortensenc83c9952019-08-05 12:15:12 -0600390 image_path = input_proto.image.path
391
Alex Klein231d2da2019-07-22 16:44:45 -0600392 result = image_lib.SecurityTest(image=image_path)
Michael Mortensenc83c9952019-08-05 12:15:12 -0600393 output_proto.success = result
394 if result:
395 return controller.RETURN_CODE_SUCCESS
396 else:
397 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
398
Alex Klein076841b2019-08-29 15:19:39 -0600399
Michael Mortensen10146cf2019-11-19 19:59:22 -0700400def _TestResponse(_input_proto, output_proto, _config):
401 """Set output_proto success field on a successful Test response."""
402 output_proto.success = True
403 return controller.RETURN_CODE_SUCCESS
404
405
406@faux.success(_TestResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700407@faux.empty_completed_unsuccessfully_error
Alex Klein2b236722019-06-19 15:44:26 -0600408@validate.require('build_target.name', 'result.directory')
409@validate.exists('image.path')
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700410def Test(input_proto: 'image_pb2.ImageTestRequest',
411 output_proto: 'image_pb2.ImageTestResult',
412 config: 'api_config.ApiConfig'):
Alex Klein2966e302019-01-17 13:29:38 -0700413 """Run image tests.
414
415 Args:
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700416 input_proto: The input message.
417 output_proto: The output message.
418 config: The API call config.
Alex Klein2966e302019-01-17 13:29:38 -0700419 """
420 image_path = input_proto.image.path
421 board = input_proto.build_target.name
422 result_directory = input_proto.result.directory
423
Alex Klein2966e302019-01-17 13:29:38 -0700424 if not os.path.isfile(image_path) or not image_path.endswith('.bin'):
Alex Klein4f0eb432019-05-02 13:56:04 -0600425 cros_build_lib.Die(
Alex Klein2966e302019-01-17 13:29:38 -0700426 'The image.path must be an existing image file with a .bin extension.')
427
Alex Klein231d2da2019-07-22 16:44:45 -0600428 if config.validate_only:
429 return controller.RETURN_CODE_VALID_INPUT
430
Alex Klein8cb365a2019-05-15 16:24:53 -0600431 success = image.Test(board, result_directory, image_dir=image_path)
432 output_proto.success = success
433
434 if success:
435 return controller.RETURN_CODE_SUCCESS
436 else:
437 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
Jack Neus761e1842020-12-01 18:20:11 +0000438
439
440@faux.empty_success
441@faux.empty_completed_unsuccessfully_error
442@validate.require('gs_image_dir', 'sysroot.build_target.name')
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700443def PushImage(input_proto: 'image_pb2.PushImageRequest',
444 _output_proto: 'image_pb2.PushImageResponse',
445 config: 'api.config.ApiConfig'):
Jack Neus761e1842020-12-01 18:20:11 +0000446 """Push artifacts from the archive bucket to the release bucket.
447
448 Wraps chromite/scripts/pushimage.py.
449
450 Args:
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700451 input_proto: Input proto.
452 _output_proto: Output proto.
453 config: The API call config.
Jack Neus761e1842020-12-01 18:20:11 +0000454
455 Returns:
456 A controller return code (e.g. controller.RETURN_CODE_SUCCESS).
457 """
458 sign_types = []
459 if input_proto.sign_types:
460 for sign_type in input_proto.sign_types:
461 if sign_type not in SUPPORTED_IMAGE_TYPES:
462 logging.error('unsupported sign type %g', sign_type)
463 return controller.RETURN_CODE_INVALID_INPUT
464 sign_types.append(SUPPORTED_IMAGE_TYPES[sign_type])
465
466 # If configured for validation only we're done here.
467 if config.validate_only:
468 return controller.RETURN_CODE_VALID_INPUT
469
Jack Neus485a9d22020-12-21 03:15:15 +0000470 kwargs = {}
471 if input_proto.profile.name:
472 kwargs['profile'] = input_proto.profile.name
473 if input_proto.dest_bucket:
474 kwargs['dest_bucket'] = input_proto.dest_bucket
Jack Neuse77614d2021-10-11 14:10:27 +0000475 if input_proto.channels:
476 kwargs['force_channels'] = [
477 common_pb2.Channel.Name(channel).lower()[len('channel_'):]
478 for channel in input_proto.channels
479 ]
Jack Neus761e1842020-12-01 18:20:11 +0000480 try:
Greg Edelston6902e3d2022-01-27 12:19:38 -0700481 channel_to_uris = pushimage.PushImage(
Jack Neus761e1842020-12-01 18:20:11 +0000482 input_proto.gs_image_dir,
483 input_proto.sysroot.build_target.name,
484 dry_run=input_proto.dryrun,
Jack Neus485a9d22020-12-21 03:15:15 +0000485 sign_types=sign_types,
486 **kwargs)
Jack Neus761e1842020-12-01 18:20:11 +0000487 except Exception:
Jack Neuse3150a42021-01-29 17:16:36 +0000488 logging.error('PushImage failed: ', exc_info=True)
Jack Neus761e1842020-12-01 18:20:11 +0000489 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
Benjamin Shaib91afa62022-05-24 15:45:20 +0000490 if channel_to_uris:
491 for uris in channel_to_uris.values():
492 for uri in uris:
493 _output_proto.instructions.add().instructions_file_path = uri
Greg Edelston6902e3d2022-01-27 12:19:38 -0700494 return controller.RETURN_CODE_SUCCESS