blob: 5cb626028032349b650d26f6811d9e2d532e3967 [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
Alex Klein27978a42021-07-27 14:18:10 -060014from typing import List, NamedTuple, Set
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
George Engelbrechtc9a8e812021-06-16 18:14:17 -060027from chromite.lib import sysroot_lib
Jack Neus761e1842020-12-01 18:20:11 +000028from chromite.scripts import pushimage
Alex Kleinb7cdbe62019-02-22 11:41:32 -070029from chromite.service import image
Will Bradley9bc85452019-10-10 10:48:21 -060030from chromite.utils import metrics
Alex Klein2966e302019-01-17 13:29:38 -070031
Alex Klein56355682019-02-07 10:36:54 -070032# The image.proto ImageType enum ids.
George Engelbrechtc55d6312021-05-05 12:11:13 -060033_BASE_ID = common_pb2.IMAGE_TYPE_BASE
34_DEV_ID = common_pb2.IMAGE_TYPE_DEV
35_TEST_ID = common_pb2.IMAGE_TYPE_TEST
36_BASE_VM_ID = common_pb2.IMAGE_TYPE_BASE_VM
37_TEST_VM_ID = common_pb2.IMAGE_TYPE_TEST_VM
38_RECOVERY_ID = common_pb2.IMAGE_TYPE_RECOVERY
39_FACTORY_ID = common_pb2.IMAGE_TYPE_FACTORY
40_FIRMWARE_ID = common_pb2.IMAGE_TYPE_FIRMWARE
41_BASE_GUEST_VM_ID = common_pb2.IMAGE_TYPE_BASE_GUEST_VM
42_TEST_GUEST_VM_ID = common_pb2.IMAGE_TYPE_TEST_GUEST_VM
Alex Klein56355682019-02-07 10:36:54 -070043
44# Dict to allow easily translating names to enum ids and vice versa.
45_IMAGE_MAPPING = {
46 _BASE_ID: constants.IMAGE_TYPE_BASE,
47 constants.IMAGE_TYPE_BASE: _BASE_ID,
48 _DEV_ID: constants.IMAGE_TYPE_DEV,
49 constants.IMAGE_TYPE_DEV: _DEV_ID,
50 _TEST_ID: constants.IMAGE_TYPE_TEST,
51 constants.IMAGE_TYPE_TEST: _TEST_ID,
Michael Mortenseneefe8952019-08-12 15:37:15 -060052 _RECOVERY_ID: constants.IMAGE_TYPE_RECOVERY,
53 constants.IMAGE_TYPE_RECOVERY: _RECOVERY_ID,
Alex Klein9039a952021-07-27 13:52:39 -060054 _FACTORY_ID: constants.IMAGE_TYPE_FACTORY_SHIM,
55 constants.IMAGE_TYPE_FACTORY_SHIM: _FACTORY_ID,
Michael Mortenseneefe8952019-08-12 15:37:15 -060056 _FIRMWARE_ID: constants.IMAGE_TYPE_FIRMWARE,
57 constants.IMAGE_TYPE_FIRMWARE: _FIRMWARE_ID,
Alex Klein56355682019-02-07 10:36:54 -070058}
59
George Engelbrecht9f4f8322021-03-08 12:04:17 -070060# Dict to describe the prerequisite built images for each VM image type.
Alex Klein21b95022019-05-09 14:14:46 -060061_VM_IMAGE_MAPPING = {
62 _BASE_VM_ID: _IMAGE_MAPPING[_BASE_ID],
63 _TEST_VM_ID: _IMAGE_MAPPING[_TEST_ID],
Trent Begin008cade2019-10-31 13:40:59 -060064 _BASE_GUEST_VM_ID: _IMAGE_MAPPING[_BASE_ID],
65 _TEST_GUEST_VM_ID: _IMAGE_MAPPING[_TEST_ID],
Alex Klein21b95022019-05-09 14:14:46 -060066}
67
George Engelbrecht9f4f8322021-03-08 12:04:17 -070068# Dict to describe the prerequisite built images for each mod image type.
69_MOD_IMAGE_MAPPING = {
70 _RECOVERY_ID: _IMAGE_MAPPING[_BASE_ID],
71}
72
Jack Neus761e1842020-12-01 18:20:11 +000073# Supported image types for PushImage.
74SUPPORTED_IMAGE_TYPES = {
75 common_pb2.IMAGE_TYPE_RECOVERY: constants.IMAGE_TYPE_RECOVERY,
76 common_pb2.IMAGE_TYPE_FACTORY: constants.IMAGE_TYPE_FACTORY,
77 common_pb2.IMAGE_TYPE_FIRMWARE: constants.IMAGE_TYPE_FIRMWARE,
78 common_pb2.IMAGE_TYPE_ACCESSORY_USBPD: constants.IMAGE_TYPE_ACCESSORY_USBPD,
79 common_pb2.IMAGE_TYPE_ACCESSORY_RWSIG: constants.IMAGE_TYPE_ACCESSORY_RWSIG,
80 common_pb2.IMAGE_TYPE_BASE: constants.IMAGE_TYPE_BASE,
George Engelbrecht9f4f8322021-03-08 12:04:17 -070081 common_pb2.IMAGE_TYPE_GSC_FIRMWARE: constants.IMAGE_TYPE_GSC_FIRMWARE,
Jack Neus761e1842020-12-01 18:20:11 +000082}
83
Alex Klein27978a42021-07-27 14:18:10 -060084# Built image directory symlink names. These names allow specifying a static
85# location for creation to simplify later archival stages. In practice, this
86# sets the symlink argument to build_packages.
87# Core are the build/dev/test images.
88# Use "latest" until we do a better job of passing through image directories,
89# e.g. for artifacts.
90LOCATION_CORE = 'latest'
91# The factory_install image.
92LOCATION_FACTORY = 'factory_shim'
93
94
95class ImageTypes(NamedTuple):
96 """Parsed image types."""
97 images: Set[str]
98 vms: Set[int]
99 mod_images: Set[int]
100
101 @property
102 def core_images(self) -> List[str]:
103 """The core images (base/dev/test) as a list."""
104 return list(self.images - {_IMAGE_MAPPING[_FACTORY_ID]}) or []
105
106 @property
107 def has_factory(self) -> bool:
108 """Whether the factory image is present."""
109 return _IMAGE_MAPPING[_FACTORY_ID] in self.images
110
111 @property
112 def factory(self) -> List[str]:
113 """A list with the factory type if set."""
114 return [_IMAGE_MAPPING[_FACTORY_ID]] if self.has_factory else []
115
Alex Klein56355682019-02-07 10:36:54 -0700116
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700117def _add_image_to_proto(output_proto, path, image_type, board):
118 """Quick helper function to add a new image to the output proto."""
119 new_image = output_proto.images.add()
120 new_image.path = path
121 new_image.type = image_type
122 new_image.build_target.name = board
123
124
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600125def ExampleGetResponse():
126 """Give an example response to assemble upstream in caller artifacts."""
127 uabs = common_pb2.UploadedArtifactsByService
128 cabs = common_pb2.ArtifactsByService
129 return uabs.Sysroot(artifacts=[
130 uabs.Image.ArtifactPaths(
131 artifact_type=cabs.Image.ArtifactType.DLC_IMAGE,
132 paths=[
133 common_pb2.Path(
134 path='/tmp/dlc/dlc.img', location=common_pb2.Path.OUTSIDE)
135 ])
136 ])
137
138
139def GetArtifacts(in_proto: common_pb2.ArtifactsByService.Image,
Alex Kleincaace392021-07-26 14:28:13 -0600140 chroot: chroot_lib.Chroot, sysroot_class: sysroot_lib.Sysroot,
141 build_target: build_target_lib.BuildTarget,
142 output_dir) -> list:
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600143 """Builds and copies images to specified output_dir.
144
145 Copies (after optionally bundling) all required images into the output_dir,
146 returning a mapping of image type to a list of (output_dir) paths to
147 the desired files. Note that currently it is only processing one image (DLC),
148 but the future direction is to process all required images. Required images
149 are located within output_artifact.artifact_type.
150
151 Args:
152 in_proto: Proto request defining reqs.
153 chroot: The chroot proto used for these artifacts.
154 sysroot_class: The sysroot proto used for these artifacts.
155 build_target: The build target used for these artifacts.
156 output_dir: The path to write artifacts to.
157
158 Returns:
159 A list of dictionary mappings of ArtifactType to list of paths.
160 """
Pi-Hsun Shih8d9c8e42021-06-30 03:27:28 +0000161 base_path = chroot.full_path(sysroot_class.path)
Jack Neus5e56fef2021-06-18 16:57:28 +0000162 board = build_target.name
163
164 generated = []
165 dlc_func = functools.partial(image.copy_dlc_image, base_path)
Alex Klein27978a42021-07-27 14:18:10 -0600166 license_func = functools.partial(
167 image.copy_license_credits, board, symlink=LOCATION_CORE)
Jack Neus5e56fef2021-06-18 16:57:28 +0000168 artifact_types = {
Alex Kleincaace392021-07-26 14:28:13 -0600169 in_proto.ArtifactType.DLC_IMAGE: dlc_func,
170 in_proto.ArtifactType.LICENSE_CREDITS: license_func,
Jack Neus5e56fef2021-06-18 16:57:28 +0000171 }
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600172
173 for output_artifact in in_proto.output_artifacts:
Jack Neus5e56fef2021-06-18 16:57:28 +0000174 for artifact_type, func in artifact_types.items():
175 if artifact_type in output_artifact.artifact_types:
176 result = func(output_dir)
177 if result:
178 generated.append({
179 'paths': [result] if isinstance(result, str) else result,
180 'type': artifact_type,
181 })
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600182
Jack Neus5e56fef2021-06-18 16:57:28 +0000183 return generated
Pi-Hsun Shih8d9c8e42021-06-30 03:27:28 +0000184
Alex Kleincaace392021-07-26 14:28:13 -0600185
Michael Mortensen10146cf2019-11-19 19:59:22 -0700186def _CreateResponse(_input_proto, output_proto, _config):
187 """Set output_proto success field on a successful Create response."""
188 output_proto.success = True
189
190
191@faux.success(_CreateResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700192@faux.empty_completed_unsuccessfully_error
Alex Klein2b236722019-06-19 15:44:26 -0600193@validate.require('build_target.name')
Alex Klein231d2da2019-07-22 16:44:45 -0600194@validate.validation_complete
Will Bradley9bc85452019-10-10 10:48:21 -0600195@metrics.collect_metrics
Alex Klein231d2da2019-07-22 16:44:45 -0600196def Create(input_proto, output_proto, _config):
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700197 """Build images.
Alex Klein56355682019-02-07 10:36:54 -0700198
199 Args:
200 input_proto (image_pb2.CreateImageRequest): The input message.
201 output_proto (image_pb2.CreateImageResult): The output message.
Alex Klein231d2da2019-07-22 16:44:45 -0600202 _config (api_config.ApiConfig): The API call config.
Alex Klein56355682019-02-07 10:36:54 -0700203 """
204 board = input_proto.build_target.name
Alex Klein56355682019-02-07 10:36:54 -0700205
Alex Klein56355682019-02-07 10:36:54 -0700206 # Build the base image if no images provided.
207 to_build = input_proto.image_types or [_BASE_ID]
Alex Klein56355682019-02-07 10:36:54 -0700208
Alex Klein27978a42021-07-27 14:18:10 -0600209 image_types = _ParseImagesToCreate(to_build)
Alex Klein21b95022019-05-09 14:14:46 -0600210 build_config = _ParseCreateBuildConfig(input_proto)
Alex Klein27978a42021-07-27 14:18:10 -0600211 factory_build_config = copy.copy(build_config)
212 build_config.symlink = LOCATION_CORE
213 factory_build_config.symlink = LOCATION_FACTORY
Alex Klein56355682019-02-07 10:36:54 -0700214
Alex Klein27978a42021-07-27 14:18:10 -0600215 # Try building the core and factory images.
Alex Klein56355682019-02-07 10:36:54 -0700216 # Sorted isn't really necessary here, but it's much easier to test.
Alex Klein27978a42021-07-27 14:18:10 -0600217 core_result = image.Build(
218 board, sorted(image_types.core_images), config=build_config)
219 logging.debug('Core Result Images: %s', core_result.images)
Alex Klein56355682019-02-07 10:36:54 -0700220
Alex Klein27978a42021-07-27 14:18:10 -0600221 factory_result = image.Build(
222 board, image_types.factory, config=factory_build_config)
223 logging.debug('Factory Result Images: %s', factory_result.images)
Will Bradley29a49c22019-10-21 11:50:08 -0600224
Alex Klein27978a42021-07-27 14:18:10 -0600225 # A successful run will have no images missing, will have run at least one
226 # of the two image sets, and neither attempt errored. The no error condition
227 # should be redundant with no missing images, but is cheap insurance.
228 all_built = core_result.all_built and factory_result.all_built
229 one_ran = core_result.build_run or factory_result.build_run
230 no_errors = not core_result.run_error and not factory_result.run_error
231 output_proto.success = success = all_built and one_ran and no_errors
Will Bradley29a49c22019-10-21 11:50:08 -0600232
Alex Klein27978a42021-07-27 14:18:10 -0600233 if success:
234 # Success! We need to record the images we built in the output.
235 all_images = {**core_result.images, **factory_result.images}
236 for img_name, img_path in all_images.items():
237 _add_image_to_proto(output_proto, str(img_path), _IMAGE_MAPPING[img_name],
238 board)
239
240 # Build and record VMs as necessary.
241 for vm_type in image_types.vms:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700242 is_test = vm_type in [_TEST_VM_ID, _TEST_GUEST_VM_ID]
Alex Klein27978a42021-07-27 14:18:10 -0600243 img_type = _IMAGE_MAPPING[_TEST_ID if is_test else _BASE_ID]
244 img_dir = core_result.images[img_type].parent.resolve()
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700245 try:
246 if vm_type in [_BASE_GUEST_VM_ID, _TEST_GUEST_VM_ID]:
Alex Klein27978a42021-07-27 14:18:10 -0600247 vm_path = image.CreateGuestVm(
248 board, is_test=is_test, image_dir=img_dir)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700249 else:
250 vm_path = image.CreateVm(
Alex Klein27978a42021-07-27 14:18:10 -0600251 board,
252 disk_layout=build_config.disk_layout,
253 is_test=is_test,
254 image_dir=img_dir)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700255 except image.ImageToVmError as e:
256 cros_build_lib.Die(e)
Will Bradley29a49c22019-10-21 11:50:08 -0600257
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700258 _add_image_to_proto(output_proto, vm_path, vm_type, board)
259
Alex Klein27978a42021-07-27 14:18:10 -0600260 # Build and record any mod images.
261 for mod_type in image_types.mod_images:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700262 if mod_type == _RECOVERY_ID:
Alex Klein27978a42021-07-27 14:18:10 -0600263 base_image_path = core_result.images[constants.IMAGE_TYPE_BASE]
Alex Kleincaace392021-07-26 14:28:13 -0600264 result = image.BuildRecoveryImage(
265 board=board, image_path=base_image_path)
Alex Klein27978a42021-07-27 14:18:10 -0600266 if result.all_built:
267 _add_image_to_proto(output_proto,
268 result.images[_IMAGE_MAPPING[mod_type]], mod_type,
269 board)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700270 else:
271 cros_build_lib.Die('Failed to create recovery image.')
272 else:
273 cros_build_lib.Die('_RECOVERY_ID is the only mod_image_type.')
Will Bradley29a49c22019-10-21 11:50:08 -0600274
275 # Read metric events log and pipe them into output_proto.events.
276 deserialize_metrics_log(output_proto.events, prefix=board)
277 return controller.RETURN_CODE_SUCCESS
278
Alex Klein1bcd9882019-03-19 13:25:24 -0600279 else:
Alex Klein2557b4f2019-07-11 14:34:00 -0600280 # Failure, include all of the failed packages in the output when available.
Alex Klein27978a42021-07-27 14:18:10 -0600281 packages = core_result.failed_packages + factory_result.failed_packages
282 if not packages:
Alex Klein2557b4f2019-07-11 14:34:00 -0600283 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
284
Alex Klein27978a42021-07-27 14:18:10 -0600285 for package in packages:
Alex Klein1bcd9882019-03-19 13:25:24 -0600286 current = output_proto.failed_packages.add()
Alex Kleine9a7dbf2020-10-06 18:12:12 -0600287 controller_util.serialize_package_info(package, current)
Alex Klein1bcd9882019-03-19 13:25:24 -0600288
Alex Klein8cb365a2019-05-15 16:24:53 -0600289 return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
Alex Klein1bcd9882019-03-19 13:25:24 -0600290
Alex Kleincaace392021-07-26 14:28:13 -0600291
Alex Klein27978a42021-07-27 14:18:10 -0600292def _ParseImagesToCreate(to_build: List[int]) -> ImageTypes:
Alex Klein21b95022019-05-09 14:14:46 -0600293 """Helper function to parse the image types to build.
294
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700295 This function expresses the dependencies of each image type and adds
296 the requisite image types if they're not explicitly defined.
Alex Klein21b95022019-05-09 14:14:46 -0600297
298 Args:
Alex Klein27978a42021-07-27 14:18:10 -0600299 to_build: The image type list.
Alex Klein21b95022019-05-09 14:14:46 -0600300
301 Returns:
Alex Klein27978a42021-07-27 14:18:10 -0600302 ImageTypes: The parsed images to build.
Alex Klein21b95022019-05-09 14:14:46 -0600303 """
304 image_types = set()
305 vm_types = set()
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700306 mod_image_types = set()
Alex Klein21b95022019-05-09 14:14:46 -0600307 for current in to_build:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700308 # Find out if it's a special case (vm, img mod), or just any old image.
309 if current in _VM_IMAGE_MAPPING:
Alex Klein21b95022019-05-09 14:14:46 -0600310 vm_types.add(current)
311 # Make sure we build the image required to build the VM.
312 image_types.add(_VM_IMAGE_MAPPING[current])
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700313 elif current in _MOD_IMAGE_MAPPING:
314 mod_image_types.add(current)
315 image_types.add(_MOD_IMAGE_MAPPING[current])
316 elif current in _IMAGE_MAPPING:
317 image_types.add(_IMAGE_MAPPING[current])
Alex Klein21b95022019-05-09 14:14:46 -0600318 else:
319 # Not expected, but at least it will be obvious if this comes up.
320 cros_build_lib.Die(
321 "The service's known image types do not match those in image.proto. "
322 'Unknown Enum ID: %s' % current)
323
Trent Begin008cade2019-10-31 13:40:59 -0600324 # We can only build one type of these images at a time since image_to_vm.sh
325 # uses the default path if a name is not provided.
326 if vm_types.issuperset({_BASE_VM_ID, _TEST_VM_ID}):
Alex Klein21b95022019-05-09 14:14:46 -0600327 cros_build_lib.Die('Cannot create more than one VM.')
328
Alex Klein27978a42021-07-27 14:18:10 -0600329 return ImageTypes(
330 images=image_types, vms=vm_types, mod_images=mod_image_types)
Alex Klein21b95022019-05-09 14:14:46 -0600331
332
333def _ParseCreateBuildConfig(input_proto):
334 """Helper to parse the image build config for Create."""
335 enable_rootfs_verification = not input_proto.disable_rootfs_verification
336 version = input_proto.version or None
337 disk_layout = input_proto.disk_layout or None
338 builder_path = input_proto.builder_path or None
339 return image.BuildConfig(
Jack Neus761e1842020-12-01 18:20:11 +0000340 enable_rootfs_verification=enable_rootfs_verification,
341 replace=True,
342 version=version,
343 disk_layout=disk_layout,
344 builder_path=builder_path,
Alex Klein21b95022019-05-09 14:14:46 -0600345 )
346
Alex Klein1bcd9882019-03-19 13:25:24 -0600347
Michael Mortensen10146cf2019-11-19 19:59:22 -0700348def _SignerTestResponse(_input_proto, output_proto, _config):
349 """Set output_proto success field on a successful SignerTest response."""
350 output_proto.success = True
351 return controller.RETURN_CODE_SUCCESS
352
353
354@faux.success(_SignerTestResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700355@faux.empty_completed_unsuccessfully_error
Michael Mortensenc83c9952019-08-05 12:15:12 -0600356@validate.exists('image.path')
Alex Klein231d2da2019-07-22 16:44:45 -0600357@validate.validation_complete
358def SignerTest(input_proto, output_proto, _config):
Michael Mortensenc83c9952019-08-05 12:15:12 -0600359 """Run image tests.
360
361 Args:
362 input_proto (image_pb2.ImageTestRequest): The input message.
363 output_proto (image_pb2.ImageTestResult): The output message.
Alex Klein231d2da2019-07-22 16:44:45 -0600364 _config (api_config.ApiConfig): The API call config.
Michael Mortensenc83c9952019-08-05 12:15:12 -0600365 """
Michael Mortensenc83c9952019-08-05 12:15:12 -0600366 image_path = input_proto.image.path
367
Alex Klein231d2da2019-07-22 16:44:45 -0600368 result = image_lib.SecurityTest(image=image_path)
Michael Mortensenc83c9952019-08-05 12:15:12 -0600369 output_proto.success = result
370 if result:
371 return controller.RETURN_CODE_SUCCESS
372 else:
373 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
374
Alex Klein076841b2019-08-29 15:19:39 -0600375
Michael Mortensen10146cf2019-11-19 19:59:22 -0700376def _TestResponse(_input_proto, output_proto, _config):
377 """Set output_proto success field on a successful Test response."""
378 output_proto.success = True
379 return controller.RETURN_CODE_SUCCESS
380
381
382@faux.success(_TestResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700383@faux.empty_completed_unsuccessfully_error
Alex Klein2b236722019-06-19 15:44:26 -0600384@validate.require('build_target.name', 'result.directory')
385@validate.exists('image.path')
Alex Klein231d2da2019-07-22 16:44:45 -0600386def Test(input_proto, output_proto, config):
Alex Klein2966e302019-01-17 13:29:38 -0700387 """Run image tests.
388
389 Args:
390 input_proto (image_pb2.ImageTestRequest): The input message.
391 output_proto (image_pb2.ImageTestResult): The output message.
Alex Klein231d2da2019-07-22 16:44:45 -0600392 config (api_config.ApiConfig): The API call config.
Alex Klein2966e302019-01-17 13:29:38 -0700393 """
394 image_path = input_proto.image.path
395 board = input_proto.build_target.name
396 result_directory = input_proto.result.directory
397
Alex Klein2966e302019-01-17 13:29:38 -0700398 if not os.path.isfile(image_path) or not image_path.endswith('.bin'):
Alex Klein4f0eb432019-05-02 13:56:04 -0600399 cros_build_lib.Die(
Alex Klein2966e302019-01-17 13:29:38 -0700400 'The image.path must be an existing image file with a .bin extension.')
401
Alex Klein231d2da2019-07-22 16:44:45 -0600402 if config.validate_only:
403 return controller.RETURN_CODE_VALID_INPUT
404
Alex Klein8cb365a2019-05-15 16:24:53 -0600405 success = image.Test(board, result_directory, image_dir=image_path)
406 output_proto.success = success
407
408 if success:
409 return controller.RETURN_CODE_SUCCESS
410 else:
411 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
Jack Neus761e1842020-12-01 18:20:11 +0000412
413
414@faux.empty_success
415@faux.empty_completed_unsuccessfully_error
416@validate.require('gs_image_dir', 'sysroot.build_target.name')
417def PushImage(input_proto, _output_proto, config):
418 """Push artifacts from the archive bucket to the release bucket.
419
420 Wraps chromite/scripts/pushimage.py.
421
422 Args:
423 input_proto (PushImageRequest): Input proto.
424 _output_proto (PushImageResponse): Output proto.
425 config (api.config.ApiConfig): The API call config.
426
427 Returns:
428 A controller return code (e.g. controller.RETURN_CODE_SUCCESS).
429 """
430 sign_types = []
431 if input_proto.sign_types:
432 for sign_type in input_proto.sign_types:
433 if sign_type not in SUPPORTED_IMAGE_TYPES:
434 logging.error('unsupported sign type %g', sign_type)
435 return controller.RETURN_CODE_INVALID_INPUT
436 sign_types.append(SUPPORTED_IMAGE_TYPES[sign_type])
437
438 # If configured for validation only we're done here.
439 if config.validate_only:
440 return controller.RETURN_CODE_VALID_INPUT
441
Jack Neus485a9d22020-12-21 03:15:15 +0000442 kwargs = {}
443 if input_proto.profile.name:
444 kwargs['profile'] = input_proto.profile.name
445 if input_proto.dest_bucket:
446 kwargs['dest_bucket'] = input_proto.dest_bucket
Jack Neus761e1842020-12-01 18:20:11 +0000447 try:
448 pushimage.PushImage(
449 input_proto.gs_image_dir,
450 input_proto.sysroot.build_target.name,
451 dry_run=input_proto.dryrun,
Jack Neus485a9d22020-12-21 03:15:15 +0000452 sign_types=sign_types,
453 **kwargs)
Jack Neus761e1842020-12-01 18:20:11 +0000454 return controller.RETURN_CODE_SUCCESS
455 except Exception:
Jack Neuse3150a42021-01-29 17:16:36 +0000456 logging.error('PushImage failed: ', exc_info=True)
Jack Neus761e1842020-12-01 18:20:11 +0000457 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY