blob: 10a8edf6cc350cfaeaa3febf81900d2a389721c4 [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
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:
35 from chromite.api import api_config
36 from chromite.api.gen.chromite.api import image_pb2
37
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.
97LOCATION_CORE = 'latest'
98# The factory_install image.
99LOCATION_FACTORY = 'factory_shim'
100
101
102class ImageTypes(NamedTuple):
103 """Parsed image types."""
104 images: Set[str]
105 vms: Set[int]
106 mod_images: Set[int]
107
108 @property
109 def core_images(self) -> List[str]:
110 """The core images (base/dev/test) as a list."""
111 return list(self.images - {_IMAGE_MAPPING[_FACTORY_ID]}) or []
112
113 @property
114 def has_factory(self) -> bool:
115 """Whether the factory image is present."""
116 return _IMAGE_MAPPING[_FACTORY_ID] in self.images
117
118 @property
119 def factory(self) -> List[str]:
120 """A list with the factory type if set."""
121 return [_IMAGE_MAPPING[_FACTORY_ID]] if self.has_factory else []
122
Alex Klein56355682019-02-07 10:36:54 -0700123
Alex Kleinf5dc2632021-08-31 16:35:06 -0600124def _add_image_to_proto(output_proto, path: Union['Path', str], image_type: int,
125 board: str):
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700126 """Quick helper function to add a new image to the output proto."""
127 new_image = output_proto.images.add()
Alex Kleinf5dc2632021-08-31 16:35:06 -0600128 new_image.path = str(path)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700129 new_image.type = image_type
130 new_image.build_target.name = board
131
132
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600133def ExampleGetResponse():
134 """Give an example response to assemble upstream in caller artifacts."""
135 uabs = common_pb2.UploadedArtifactsByService
136 cabs = common_pb2.ArtifactsByService
137 return uabs.Sysroot(artifacts=[
138 uabs.Image.ArtifactPaths(
139 artifact_type=cabs.Image.ArtifactType.DLC_IMAGE,
140 paths=[
141 common_pb2.Path(
142 path='/tmp/dlc/dlc.img', location=common_pb2.Path.OUTSIDE)
143 ])
144 ])
145
146
147def GetArtifacts(in_proto: common_pb2.ArtifactsByService.Image,
Alex Kleincaace392021-07-26 14:28:13 -0600148 chroot: chroot_lib.Chroot, sysroot_class: sysroot_lib.Sysroot,
149 build_target: build_target_lib.BuildTarget,
150 output_dir) -> list:
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600151 """Builds and copies images to specified output_dir.
152
153 Copies (after optionally bundling) all required images into the output_dir,
154 returning a mapping of image type to a list of (output_dir) paths to
155 the desired files. Note that currently it is only processing one image (DLC),
156 but the future direction is to process all required images. Required images
157 are located within output_artifact.artifact_type.
158
159 Args:
160 in_proto: Proto request defining reqs.
161 chroot: The chroot proto used for these artifacts.
162 sysroot_class: The sysroot proto used for these artifacts.
163 build_target: The build target used for these artifacts.
164 output_dir: The path to write artifacts to.
165
166 Returns:
167 A list of dictionary mappings of ArtifactType to list of paths.
168 """
Pi-Hsun Shih8d9c8e42021-06-30 03:27:28 +0000169 base_path = chroot.full_path(sysroot_class.path)
Jack Neus5e56fef2021-06-18 16:57:28 +0000170 board = build_target.name
Jack Neus94a35be2021-09-10 15:18:06 +0000171 factory_shim_location = Path(
Cheng Yuehd5a31802022-07-25 15:00:55 +0800172 image_lib.GetLatestImageLink(board, pointer=LOCATION_FACTORY))
Jack Neus5e56fef2021-06-18 16:57:28 +0000173
174 generated = []
175 dlc_func = functools.partial(image.copy_dlc_image, base_path)
Alex Klein27978a42021-07-27 14:18:10 -0600176 license_func = functools.partial(
177 image.copy_license_credits, board, symlink=LOCATION_CORE)
Jack Neus94a35be2021-09-10 15:18:06 +0000178 factory_image_func = functools.partial(
179 image.create_factory_image_zip,
180 chroot,
181 sysroot_class,
182 factory_shim_location,
183 packages_service.determine_full_version(),
184 )
Jack Neusaf47ed62022-08-16 16:19:48 +0000185 stripped_packags_func = functools.partial(
186 image.create_stripped_packages_tar,
187 chroot,
188 build_target,
189 )
Jack Neus5e56fef2021-06-18 16:57:28 +0000190 artifact_types = {
Alex Kleincaace392021-07-26 14:28:13 -0600191 in_proto.ArtifactType.DLC_IMAGE: dlc_func,
192 in_proto.ArtifactType.LICENSE_CREDITS: license_func,
Jack Neus94a35be2021-09-10 15:18:06 +0000193 in_proto.ArtifactType.FACTORY_IMAGE: factory_image_func,
Jack Neusaf47ed62022-08-16 16:19:48 +0000194 in_proto.ArtifactType.STRIPPED_PACKAGES: stripped_packags_func,
Jack Neus5e56fef2021-06-18 16:57:28 +0000195 }
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600196
197 for output_artifact in in_proto.output_artifacts:
Jack Neus5e56fef2021-06-18 16:57:28 +0000198 for artifact_type, func in artifact_types.items():
199 if artifact_type in output_artifact.artifact_types:
200 result = func(output_dir)
201 if result:
202 generated.append({
203 'paths': [result] if isinstance(result, str) else result,
204 'type': artifact_type,
205 })
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600206
Jack Neus5e56fef2021-06-18 16:57:28 +0000207 return generated
Pi-Hsun Shih8d9c8e42021-06-30 03:27:28 +0000208
Alex Kleincaace392021-07-26 14:28:13 -0600209
Michael Mortensen10146cf2019-11-19 19:59:22 -0700210def _CreateResponse(_input_proto, output_proto, _config):
211 """Set output_proto success field on a successful Create response."""
212 output_proto.success = True
213
214
215@faux.success(_CreateResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700216@faux.empty_completed_unsuccessfully_error
Alex Klein2b236722019-06-19 15:44:26 -0600217@validate.require('build_target.name')
Alex Klein231d2da2019-07-22 16:44:45 -0600218@validate.validation_complete
Alex Kleinaef41942022-04-19 14:13:17 -0600219@metrics_lib.collect_metrics
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700220def Create(input_proto: 'image_pb2.CreateImageRequest',
221 output_proto: 'image_pb2.CreateImageResult',
222 _config: 'api_config.ApiConfig'):
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700223 """Build images.
Alex Klein56355682019-02-07 10:36:54 -0700224
225 Args:
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700226 input_proto: The input message.
227 output_proto: The output message.
228 _config: The API call config.
Alex Klein56355682019-02-07 10:36:54 -0700229 """
230 board = input_proto.build_target.name
Alex Klein56355682019-02-07 10:36:54 -0700231
Alex Klein56355682019-02-07 10:36:54 -0700232 # Build the base image if no images provided.
233 to_build = input_proto.image_types or [_BASE_ID]
Alex Klein56355682019-02-07 10:36:54 -0700234
Alex Klein27978a42021-07-27 14:18:10 -0600235 image_types = _ParseImagesToCreate(to_build)
Alex Klein21b95022019-05-09 14:14:46 -0600236 build_config = _ParseCreateBuildConfig(input_proto)
Ram Chandrasekar53c49582022-05-12 21:15:29 +0000237 factory_build_config = build_config._replace(
238 symlink=LOCATION_FACTORY, output_dir_suffix=LOCATION_FACTORY)
Alex Klein56355682019-02-07 10:36:54 -0700239
Alex Klein27978a42021-07-27 14:18:10 -0600240 # Try building the core and factory images.
Alex Klein56355682019-02-07 10:36:54 -0700241 # Sorted isn't really necessary here, but it's much easier to test.
Alex Klein27978a42021-07-27 14:18:10 -0600242 core_result = image.Build(
243 board, sorted(image_types.core_images), config=build_config)
244 logging.debug('Core Result Images: %s', core_result.images)
Alex Klein56355682019-02-07 10:36:54 -0700245
Alex Klein27978a42021-07-27 14:18:10 -0600246 factory_result = image.Build(
247 board, image_types.factory, config=factory_build_config)
248 logging.debug('Factory Result Images: %s', factory_result.images)
Will Bradley29a49c22019-10-21 11:50:08 -0600249
Alex Klein27978a42021-07-27 14:18:10 -0600250 # A successful run will have no images missing, will have run at least one
251 # of the two image sets, and neither attempt errored. The no error condition
252 # should be redundant with no missing images, but is cheap insurance.
253 all_built = core_result.all_built and factory_result.all_built
254 one_ran = core_result.build_run or factory_result.build_run
255 no_errors = not core_result.run_error and not factory_result.run_error
256 output_proto.success = success = all_built and one_ran and no_errors
Will Bradley29a49c22019-10-21 11:50:08 -0600257
Alex Klein27978a42021-07-27 14:18:10 -0600258 if success:
259 # Success! We need to record the images we built in the output.
260 all_images = {**core_result.images, **factory_result.images}
261 for img_name, img_path in all_images.items():
Alex Kleinf5dc2632021-08-31 16:35:06 -0600262 _add_image_to_proto(output_proto, img_path, _IMAGE_MAPPING[img_name],
Alex Klein27978a42021-07-27 14:18:10 -0600263 board)
264
265 # Build and record VMs as necessary.
266 for vm_type in image_types.vms:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700267 is_test = vm_type in [_TEST_VM_ID, _TEST_GUEST_VM_ID]
Alex Klein27978a42021-07-27 14:18:10 -0600268 img_type = _IMAGE_MAPPING[_TEST_ID if is_test else _BASE_ID]
269 img_dir = core_result.images[img_type].parent.resolve()
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700270 try:
271 if vm_type in [_BASE_GUEST_VM_ID, _TEST_GUEST_VM_ID]:
Alex Klein27978a42021-07-27 14:18:10 -0600272 vm_path = image.CreateGuestVm(
273 board, is_test=is_test, image_dir=img_dir)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700274 else:
275 vm_path = image.CreateVm(
Alex Klein27978a42021-07-27 14:18:10 -0600276 board,
277 disk_layout=build_config.disk_layout,
278 is_test=is_test,
279 image_dir=img_dir)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700280 except image.ImageToVmError as e:
281 cros_build_lib.Die(e)
Will Bradley29a49c22019-10-21 11:50:08 -0600282
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700283 _add_image_to_proto(output_proto, vm_path, vm_type, board)
284
Alex Klein27978a42021-07-27 14:18:10 -0600285 # Build and record any mod images.
286 for mod_type in image_types.mod_images:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700287 if mod_type == _RECOVERY_ID:
Alex Klein27978a42021-07-27 14:18:10 -0600288 base_image_path = core_result.images[constants.IMAGE_TYPE_BASE]
Joseph Sussman34c01be2022-06-03 14:04:41 +0000289 # For ChromeOS Flex special case.
290 if build_config.base_is_recovery:
291 result = image.CopyBaseToRecovery(
292 board=board, image_path=base_image_path)
293 else:
294 result = image.BuildRecoveryImage(
295 board=board, image_path=base_image_path)
Alex Klein27978a42021-07-27 14:18:10 -0600296 if result.all_built:
297 _add_image_to_proto(output_proto,
298 result.images[_IMAGE_MAPPING[mod_type]], mod_type,
299 board)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700300 else:
301 cros_build_lib.Die('Failed to create recovery image.')
302 else:
303 cros_build_lib.Die('_RECOVERY_ID is the only mod_image_type.')
Will Bradley29a49c22019-10-21 11:50:08 -0600304
305 # Read metric events log and pipe them into output_proto.events.
306 deserialize_metrics_log(output_proto.events, prefix=board)
307 return controller.RETURN_CODE_SUCCESS
308
Alex Klein1bcd9882019-03-19 13:25:24 -0600309 else:
Alex Klein2557b4f2019-07-11 14:34:00 -0600310 # Failure, include all of the failed packages in the output when available.
Alex Klein27978a42021-07-27 14:18:10 -0600311 packages = core_result.failed_packages + factory_result.failed_packages
312 if not packages:
Alex Klein2557b4f2019-07-11 14:34:00 -0600313 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
314
Alex Klein27978a42021-07-27 14:18:10 -0600315 for package in packages:
Alex Klein1bcd9882019-03-19 13:25:24 -0600316 current = output_proto.failed_packages.add()
Alex Kleine9a7dbf2020-10-06 18:12:12 -0600317 controller_util.serialize_package_info(package, current)
Alex Klein1bcd9882019-03-19 13:25:24 -0600318
Alex Klein8cb365a2019-05-15 16:24:53 -0600319 return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
Alex Klein1bcd9882019-03-19 13:25:24 -0600320
Alex Kleincaace392021-07-26 14:28:13 -0600321
Alex Klein27978a42021-07-27 14:18:10 -0600322def _ParseImagesToCreate(to_build: List[int]) -> ImageTypes:
Alex Klein21b95022019-05-09 14:14:46 -0600323 """Helper function to parse the image types to build.
324
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700325 This function expresses the dependencies of each image type and adds
326 the requisite image types if they're not explicitly defined.
Alex Klein21b95022019-05-09 14:14:46 -0600327
328 Args:
Alex Klein27978a42021-07-27 14:18:10 -0600329 to_build: The image type list.
Alex Klein21b95022019-05-09 14:14:46 -0600330
331 Returns:
Alex Klein27978a42021-07-27 14:18:10 -0600332 ImageTypes: The parsed images to build.
Alex Klein21b95022019-05-09 14:14:46 -0600333 """
334 image_types = set()
335 vm_types = set()
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700336 mod_image_types = set()
Alex Klein21b95022019-05-09 14:14:46 -0600337 for current in to_build:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700338 # Find out if it's a special case (vm, img mod), or just any old image.
339 if current in _VM_IMAGE_MAPPING:
Alex Klein21b95022019-05-09 14:14:46 -0600340 vm_types.add(current)
341 # Make sure we build the image required to build the VM.
342 image_types.add(_VM_IMAGE_MAPPING[current])
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700343 elif current in _MOD_IMAGE_MAPPING:
344 mod_image_types.add(current)
345 image_types.add(_MOD_IMAGE_MAPPING[current])
346 elif current in _IMAGE_MAPPING:
347 image_types.add(_IMAGE_MAPPING[current])
Alex Klein21b95022019-05-09 14:14:46 -0600348 else:
349 # Not expected, but at least it will be obvious if this comes up.
350 cros_build_lib.Die(
351 "The service's known image types do not match those in image.proto. "
352 'Unknown Enum ID: %s' % current)
353
Trent Begin008cade2019-10-31 13:40:59 -0600354 # We can only build one type of these images at a time since image_to_vm.sh
355 # uses the default path if a name is not provided.
356 if vm_types.issuperset({_BASE_VM_ID, _TEST_VM_ID}):
Alex Klein21b95022019-05-09 14:14:46 -0600357 cros_build_lib.Die('Cannot create more than one VM.')
358
Alex Klein27978a42021-07-27 14:18:10 -0600359 return ImageTypes(
360 images=image_types, vms=vm_types, mod_images=mod_image_types)
Alex Klein21b95022019-05-09 14:14:46 -0600361
362
363def _ParseCreateBuildConfig(input_proto):
364 """Helper to parse the image build config for Create."""
365 enable_rootfs_verification = not input_proto.disable_rootfs_verification
366 version = input_proto.version or None
367 disk_layout = input_proto.disk_layout or None
368 builder_path = input_proto.builder_path or None
Joseph Sussman34c01be2022-06-03 14:04:41 +0000369 base_is_recovery = input_proto.base_is_recovery or False
Alex Klein21b95022019-05-09 14:14:46 -0600370 return image.BuildConfig(
Jack Neus761e1842020-12-01 18:20:11 +0000371 enable_rootfs_verification=enable_rootfs_verification,
372 replace=True,
373 version=version,
374 disk_layout=disk_layout,
375 builder_path=builder_path,
Ram Chandrasekar53c49582022-05-12 21:15:29 +0000376 symlink=LOCATION_CORE,
Joseph Sussman34c01be2022-06-03 14:04:41 +0000377 base_is_recovery=base_is_recovery,
Alex Klein21b95022019-05-09 14:14:46 -0600378 )
379
Alex Klein1bcd9882019-03-19 13:25:24 -0600380
Michael Mortensen10146cf2019-11-19 19:59:22 -0700381def _SignerTestResponse(_input_proto, output_proto, _config):
382 """Set output_proto success field on a successful SignerTest response."""
383 output_proto.success = True
384 return controller.RETURN_CODE_SUCCESS
385
386
387@faux.success(_SignerTestResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700388@faux.empty_completed_unsuccessfully_error
Michael Mortensenc83c9952019-08-05 12:15:12 -0600389@validate.exists('image.path')
Alex Klein231d2da2019-07-22 16:44:45 -0600390@validate.validation_complete
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700391def SignerTest(input_proto: 'image_pb2.ImageTestRequest',
392 output_proto: 'image_pb2.ImageTestRequest',
393 _config: 'api_config.ApiConfig'):
Michael Mortensenc83c9952019-08-05 12:15:12 -0600394 """Run image tests.
395
396 Args:
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700397 input_proto: The input message.
398 output_proto: The output message.
399 _config: The API call config.
Michael Mortensenc83c9952019-08-05 12:15:12 -0600400 """
Michael Mortensenc83c9952019-08-05 12:15:12 -0600401 image_path = input_proto.image.path
402
Alex Klein231d2da2019-07-22 16:44:45 -0600403 result = image_lib.SecurityTest(image=image_path)
Michael Mortensenc83c9952019-08-05 12:15:12 -0600404 output_proto.success = result
405 if result:
406 return controller.RETURN_CODE_SUCCESS
407 else:
408 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
409
Alex Klein076841b2019-08-29 15:19:39 -0600410
Michael Mortensen10146cf2019-11-19 19:59:22 -0700411def _TestResponse(_input_proto, output_proto, _config):
412 """Set output_proto success field on a successful Test response."""
413 output_proto.success = True
414 return controller.RETURN_CODE_SUCCESS
415
416
417@faux.success(_TestResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700418@faux.empty_completed_unsuccessfully_error
Alex Klein2b236722019-06-19 15:44:26 -0600419@validate.require('build_target.name', 'result.directory')
420@validate.exists('image.path')
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700421def Test(input_proto: 'image_pb2.ImageTestRequest',
422 output_proto: 'image_pb2.ImageTestResult',
423 config: 'api_config.ApiConfig'):
Alex Klein2966e302019-01-17 13:29:38 -0700424 """Run image tests.
425
426 Args:
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700427 input_proto: The input message.
428 output_proto: The output message.
429 config: The API call config.
Alex Klein2966e302019-01-17 13:29:38 -0700430 """
431 image_path = input_proto.image.path
432 board = input_proto.build_target.name
433 result_directory = input_proto.result.directory
434
Alex Klein2966e302019-01-17 13:29:38 -0700435 if not os.path.isfile(image_path) or not image_path.endswith('.bin'):
Alex Klein4f0eb432019-05-02 13:56:04 -0600436 cros_build_lib.Die(
Alex Klein2966e302019-01-17 13:29:38 -0700437 'The image.path must be an existing image file with a .bin extension.')
438
Alex Klein231d2da2019-07-22 16:44:45 -0600439 if config.validate_only:
440 return controller.RETURN_CODE_VALID_INPUT
441
Alex Klein8cb365a2019-05-15 16:24:53 -0600442 success = image.Test(board, result_directory, image_dir=image_path)
443 output_proto.success = success
444
445 if success:
446 return controller.RETURN_CODE_SUCCESS
447 else:
448 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
Jack Neus761e1842020-12-01 18:20:11 +0000449
450
451@faux.empty_success
452@faux.empty_completed_unsuccessfully_error
453@validate.require('gs_image_dir', 'sysroot.build_target.name')
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700454def PushImage(input_proto: 'image_pb2.PushImageRequest',
455 _output_proto: 'image_pb2.PushImageResponse',
456 config: 'api.config.ApiConfig'):
Jack Neus761e1842020-12-01 18:20:11 +0000457 """Push artifacts from the archive bucket to the release bucket.
458
459 Wraps chromite/scripts/pushimage.py.
460
461 Args:
Kevin Shelton5b21c8b2022-04-04 17:04:13 -0700462 input_proto: Input proto.
463 _output_proto: Output proto.
464 config: The API call config.
Jack Neus761e1842020-12-01 18:20:11 +0000465
466 Returns:
467 A controller return code (e.g. controller.RETURN_CODE_SUCCESS).
468 """
469 sign_types = []
470 if input_proto.sign_types:
471 for sign_type in input_proto.sign_types:
472 if sign_type not in SUPPORTED_IMAGE_TYPES:
473 logging.error('unsupported sign type %g', sign_type)
474 return controller.RETURN_CODE_INVALID_INPUT
475 sign_types.append(SUPPORTED_IMAGE_TYPES[sign_type])
476
477 # If configured for validation only we're done here.
478 if config.validate_only:
479 return controller.RETURN_CODE_VALID_INPUT
480
Jack Neus485a9d22020-12-21 03:15:15 +0000481 kwargs = {}
482 if input_proto.profile.name:
483 kwargs['profile'] = input_proto.profile.name
484 if input_proto.dest_bucket:
485 kwargs['dest_bucket'] = input_proto.dest_bucket
Jack Neuse77614d2021-10-11 14:10:27 +0000486 if input_proto.channels:
487 kwargs['force_channels'] = [
488 common_pb2.Channel.Name(channel).lower()[len('channel_'):]
489 for channel in input_proto.channels
490 ]
Jack Neus761e1842020-12-01 18:20:11 +0000491 try:
Greg Edelston6902e3d2022-01-27 12:19:38 -0700492 channel_to_uris = pushimage.PushImage(
Jack Neus761e1842020-12-01 18:20:11 +0000493 input_proto.gs_image_dir,
494 input_proto.sysroot.build_target.name,
495 dry_run=input_proto.dryrun,
Jack Neus485a9d22020-12-21 03:15:15 +0000496 sign_types=sign_types,
497 **kwargs)
Jack Neus761e1842020-12-01 18:20:11 +0000498 except Exception:
Jack Neuse3150a42021-01-29 17:16:36 +0000499 logging.error('PushImage failed: ', exc_info=True)
Jack Neus761e1842020-12-01 18:20:11 +0000500 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
Benjamin Shaib91afa62022-05-24 15:45:20 +0000501 if channel_to_uris:
502 for uris in channel_to_uris.values():
503 for uri in uris:
504 _output_proto.instructions.add().instructions_file_path = uri
Greg Edelston6902e3d2022-01-27 12:19:38 -0700505 return controller.RETURN_CODE_SUCCESS