blob: 7a42a56548f72ec7faef06babe936f3c7453d18b [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,
82 common_pb2.IMAGE_TYPE_BASE: constants.IMAGE_TYPE_BASE,
George Engelbrecht9f4f8322021-03-08 12:04:17 -070083 common_pb2.IMAGE_TYPE_GSC_FIRMWARE: constants.IMAGE_TYPE_GSC_FIRMWARE,
Jack Neus761e1842020-12-01 18:20:11 +000084}
85
Alex Klein27978a42021-07-27 14:18:10 -060086# Built image directory symlink names. These names allow specifying a static
87# location for creation to simplify later archival stages. In practice, this
88# sets the symlink argument to build_packages.
89# Core are the build/dev/test images.
90# Use "latest" until we do a better job of passing through image directories,
91# e.g. for artifacts.
92LOCATION_CORE = 'latest'
93# The factory_install image.
94LOCATION_FACTORY = 'factory_shim'
95
96
97class ImageTypes(NamedTuple):
98 """Parsed image types."""
99 images: Set[str]
100 vms: Set[int]
101 mod_images: Set[int]
102
103 @property
104 def core_images(self) -> List[str]:
105 """The core images (base/dev/test) as a list."""
106 return list(self.images - {_IMAGE_MAPPING[_FACTORY_ID]}) or []
107
108 @property
109 def has_factory(self) -> bool:
110 """Whether the factory image is present."""
111 return _IMAGE_MAPPING[_FACTORY_ID] in self.images
112
113 @property
114 def factory(self) -> List[str]:
115 """A list with the factory type if set."""
116 return [_IMAGE_MAPPING[_FACTORY_ID]] if self.has_factory else []
117
Alex Klein56355682019-02-07 10:36:54 -0700118
Alex Kleinf5dc2632021-08-31 16:35:06 -0600119def _add_image_to_proto(output_proto, path: Union['Path', str], image_type: int,
120 board: str):
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700121 """Quick helper function to add a new image to the output proto."""
122 new_image = output_proto.images.add()
Alex Kleinf5dc2632021-08-31 16:35:06 -0600123 new_image.path = str(path)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700124 new_image.type = image_type
125 new_image.build_target.name = board
126
127
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600128def ExampleGetResponse():
129 """Give an example response to assemble upstream in caller artifacts."""
130 uabs = common_pb2.UploadedArtifactsByService
131 cabs = common_pb2.ArtifactsByService
132 return uabs.Sysroot(artifacts=[
133 uabs.Image.ArtifactPaths(
134 artifact_type=cabs.Image.ArtifactType.DLC_IMAGE,
135 paths=[
136 common_pb2.Path(
137 path='/tmp/dlc/dlc.img', location=common_pb2.Path.OUTSIDE)
138 ])
139 ])
140
141
142def GetArtifacts(in_proto: common_pb2.ArtifactsByService.Image,
Alex Kleincaace392021-07-26 14:28:13 -0600143 chroot: chroot_lib.Chroot, sysroot_class: sysroot_lib.Sysroot,
144 build_target: build_target_lib.BuildTarget,
145 output_dir) -> list:
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600146 """Builds and copies images to specified output_dir.
147
148 Copies (after optionally bundling) all required images into the output_dir,
149 returning a mapping of image type to a list of (output_dir) paths to
150 the desired files. Note that currently it is only processing one image (DLC),
151 but the future direction is to process all required images. Required images
152 are located within output_artifact.artifact_type.
153
154 Args:
155 in_proto: Proto request defining reqs.
156 chroot: The chroot proto used for these artifacts.
157 sysroot_class: The sysroot proto used for these artifacts.
158 build_target: The build target used for these artifacts.
159 output_dir: The path to write artifacts to.
160
161 Returns:
162 A list of dictionary mappings of ArtifactType to list of paths.
163 """
Pi-Hsun Shih8d9c8e42021-06-30 03:27:28 +0000164 base_path = chroot.full_path(sysroot_class.path)
Jack Neus5e56fef2021-06-18 16:57:28 +0000165 board = build_target.name
Jack Neus94a35be2021-09-10 15:18:06 +0000166 factory_shim_location = Path(
167 image_lib.GetLatestImageLink(board, pointer=LOCATION_FACTORY)).resolve()
Jack Neus5e56fef2021-06-18 16:57:28 +0000168
169 generated = []
170 dlc_func = functools.partial(image.copy_dlc_image, base_path)
Alex Klein27978a42021-07-27 14:18:10 -0600171 license_func = functools.partial(
172 image.copy_license_credits, board, symlink=LOCATION_CORE)
Jack Neus94a35be2021-09-10 15:18:06 +0000173 factory_image_func = functools.partial(
174 image.create_factory_image_zip,
175 chroot,
176 sysroot_class,
177 factory_shim_location,
178 packages_service.determine_full_version(),
179 )
Jack Neus5e56fef2021-06-18 16:57:28 +0000180 artifact_types = {
Alex Kleincaace392021-07-26 14:28:13 -0600181 in_proto.ArtifactType.DLC_IMAGE: dlc_func,
182 in_proto.ArtifactType.LICENSE_CREDITS: license_func,
Jack Neus94a35be2021-09-10 15:18:06 +0000183 in_proto.ArtifactType.FACTORY_IMAGE: factory_image_func,
Jack Neus5e56fef2021-06-18 16:57:28 +0000184 }
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600185
186 for output_artifact in in_proto.output_artifacts:
Jack Neus5e56fef2021-06-18 16:57:28 +0000187 for artifact_type, func in artifact_types.items():
188 if artifact_type in output_artifact.artifact_types:
189 result = func(output_dir)
190 if result:
191 generated.append({
192 'paths': [result] if isinstance(result, str) else result,
193 'type': artifact_type,
194 })
George Engelbrechtc9a8e812021-06-16 18:14:17 -0600195
Jack Neus5e56fef2021-06-18 16:57:28 +0000196 return generated
Pi-Hsun Shih8d9c8e42021-06-30 03:27:28 +0000197
Alex Kleincaace392021-07-26 14:28:13 -0600198
Michael Mortensen10146cf2019-11-19 19:59:22 -0700199def _CreateResponse(_input_proto, output_proto, _config):
200 """Set output_proto success field on a successful Create response."""
201 output_proto.success = True
202
203
204@faux.success(_CreateResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700205@faux.empty_completed_unsuccessfully_error
Alex Klein2b236722019-06-19 15:44:26 -0600206@validate.require('build_target.name')
Alex Klein231d2da2019-07-22 16:44:45 -0600207@validate.validation_complete
Will Bradley9bc85452019-10-10 10:48:21 -0600208@metrics.collect_metrics
Alex Klein231d2da2019-07-22 16:44:45 -0600209def Create(input_proto, output_proto, _config):
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700210 """Build images.
Alex Klein56355682019-02-07 10:36:54 -0700211
212 Args:
213 input_proto (image_pb2.CreateImageRequest): The input message.
214 output_proto (image_pb2.CreateImageResult): The output message.
Alex Klein231d2da2019-07-22 16:44:45 -0600215 _config (api_config.ApiConfig): The API call config.
Alex Klein56355682019-02-07 10:36:54 -0700216 """
217 board = input_proto.build_target.name
Alex Klein56355682019-02-07 10:36:54 -0700218
Alex Klein56355682019-02-07 10:36:54 -0700219 # Build the base image if no images provided.
220 to_build = input_proto.image_types or [_BASE_ID]
Alex Klein56355682019-02-07 10:36:54 -0700221
Alex Klein27978a42021-07-27 14:18:10 -0600222 image_types = _ParseImagesToCreate(to_build)
Alex Klein21b95022019-05-09 14:14:46 -0600223 build_config = _ParseCreateBuildConfig(input_proto)
Alex Klein27978a42021-07-27 14:18:10 -0600224 factory_build_config = copy.copy(build_config)
225 build_config.symlink = LOCATION_CORE
226 factory_build_config.symlink = LOCATION_FACTORY
Alex Klein3d3eb632021-09-08 13:55:21 -0600227 factory_build_config.output_dir_suffix = LOCATION_FACTORY
Alex Klein56355682019-02-07 10:36:54 -0700228
Alex Klein27978a42021-07-27 14:18:10 -0600229 # Try building the core and factory images.
Alex Klein56355682019-02-07 10:36:54 -0700230 # Sorted isn't really necessary here, but it's much easier to test.
Alex Klein27978a42021-07-27 14:18:10 -0600231 core_result = image.Build(
232 board, sorted(image_types.core_images), config=build_config)
233 logging.debug('Core Result Images: %s', core_result.images)
Alex Klein56355682019-02-07 10:36:54 -0700234
Alex Klein27978a42021-07-27 14:18:10 -0600235 factory_result = image.Build(
236 board, image_types.factory, config=factory_build_config)
237 logging.debug('Factory Result Images: %s', factory_result.images)
Will Bradley29a49c22019-10-21 11:50:08 -0600238
Alex Klein27978a42021-07-27 14:18:10 -0600239 # A successful run will have no images missing, will have run at least one
240 # of the two image sets, and neither attempt errored. The no error condition
241 # should be redundant with no missing images, but is cheap insurance.
242 all_built = core_result.all_built and factory_result.all_built
243 one_ran = core_result.build_run or factory_result.build_run
244 no_errors = not core_result.run_error and not factory_result.run_error
245 output_proto.success = success = all_built and one_ran and no_errors
Will Bradley29a49c22019-10-21 11:50:08 -0600246
Alex Klein27978a42021-07-27 14:18:10 -0600247 if success:
248 # Success! We need to record the images we built in the output.
249 all_images = {**core_result.images, **factory_result.images}
250 for img_name, img_path in all_images.items():
Alex Kleinf5dc2632021-08-31 16:35:06 -0600251 _add_image_to_proto(output_proto, img_path, _IMAGE_MAPPING[img_name],
Alex Klein27978a42021-07-27 14:18:10 -0600252 board)
253
254 # Build and record VMs as necessary.
255 for vm_type in image_types.vms:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700256 is_test = vm_type in [_TEST_VM_ID, _TEST_GUEST_VM_ID]
Alex Klein27978a42021-07-27 14:18:10 -0600257 img_type = _IMAGE_MAPPING[_TEST_ID if is_test else _BASE_ID]
258 img_dir = core_result.images[img_type].parent.resolve()
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700259 try:
260 if vm_type in [_BASE_GUEST_VM_ID, _TEST_GUEST_VM_ID]:
Alex Klein27978a42021-07-27 14:18:10 -0600261 vm_path = image.CreateGuestVm(
262 board, is_test=is_test, image_dir=img_dir)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700263 else:
264 vm_path = image.CreateVm(
Alex Klein27978a42021-07-27 14:18:10 -0600265 board,
266 disk_layout=build_config.disk_layout,
267 is_test=is_test,
268 image_dir=img_dir)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700269 except image.ImageToVmError as e:
270 cros_build_lib.Die(e)
Will Bradley29a49c22019-10-21 11:50:08 -0600271
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700272 _add_image_to_proto(output_proto, vm_path, vm_type, board)
273
Alex Klein27978a42021-07-27 14:18:10 -0600274 # Build and record any mod images.
275 for mod_type in image_types.mod_images:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700276 if mod_type == _RECOVERY_ID:
Alex Klein27978a42021-07-27 14:18:10 -0600277 base_image_path = core_result.images[constants.IMAGE_TYPE_BASE]
Alex Kleincaace392021-07-26 14:28:13 -0600278 result = image.BuildRecoveryImage(
279 board=board, image_path=base_image_path)
Alex Klein27978a42021-07-27 14:18:10 -0600280 if result.all_built:
281 _add_image_to_proto(output_proto,
282 result.images[_IMAGE_MAPPING[mod_type]], mod_type,
283 board)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700284 else:
285 cros_build_lib.Die('Failed to create recovery image.')
286 else:
287 cros_build_lib.Die('_RECOVERY_ID is the only mod_image_type.')
Will Bradley29a49c22019-10-21 11:50:08 -0600288
289 # Read metric events log and pipe them into output_proto.events.
290 deserialize_metrics_log(output_proto.events, prefix=board)
291 return controller.RETURN_CODE_SUCCESS
292
Alex Klein1bcd9882019-03-19 13:25:24 -0600293 else:
Alex Klein2557b4f2019-07-11 14:34:00 -0600294 # Failure, include all of the failed packages in the output when available.
Alex Klein27978a42021-07-27 14:18:10 -0600295 packages = core_result.failed_packages + factory_result.failed_packages
296 if not packages:
Alex Klein2557b4f2019-07-11 14:34:00 -0600297 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
298
Alex Klein27978a42021-07-27 14:18:10 -0600299 for package in packages:
Alex Klein1bcd9882019-03-19 13:25:24 -0600300 current = output_proto.failed_packages.add()
Alex Kleine9a7dbf2020-10-06 18:12:12 -0600301 controller_util.serialize_package_info(package, current)
Alex Klein1bcd9882019-03-19 13:25:24 -0600302
Alex Klein8cb365a2019-05-15 16:24:53 -0600303 return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
Alex Klein1bcd9882019-03-19 13:25:24 -0600304
Alex Kleincaace392021-07-26 14:28:13 -0600305
Alex Klein27978a42021-07-27 14:18:10 -0600306def _ParseImagesToCreate(to_build: List[int]) -> ImageTypes:
Alex Klein21b95022019-05-09 14:14:46 -0600307 """Helper function to parse the image types to build.
308
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700309 This function expresses the dependencies of each image type and adds
310 the requisite image types if they're not explicitly defined.
Alex Klein21b95022019-05-09 14:14:46 -0600311
312 Args:
Alex Klein27978a42021-07-27 14:18:10 -0600313 to_build: The image type list.
Alex Klein21b95022019-05-09 14:14:46 -0600314
315 Returns:
Alex Klein27978a42021-07-27 14:18:10 -0600316 ImageTypes: The parsed images to build.
Alex Klein21b95022019-05-09 14:14:46 -0600317 """
318 image_types = set()
319 vm_types = set()
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700320 mod_image_types = set()
Alex Klein21b95022019-05-09 14:14:46 -0600321 for current in to_build:
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700322 # Find out if it's a special case (vm, img mod), or just any old image.
323 if current in _VM_IMAGE_MAPPING:
Alex Klein21b95022019-05-09 14:14:46 -0600324 vm_types.add(current)
325 # Make sure we build the image required to build the VM.
326 image_types.add(_VM_IMAGE_MAPPING[current])
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700327 elif current in _MOD_IMAGE_MAPPING:
328 mod_image_types.add(current)
329 image_types.add(_MOD_IMAGE_MAPPING[current])
330 elif current in _IMAGE_MAPPING:
331 image_types.add(_IMAGE_MAPPING[current])
Alex Klein21b95022019-05-09 14:14:46 -0600332 else:
333 # Not expected, but at least it will be obvious if this comes up.
334 cros_build_lib.Die(
335 "The service's known image types do not match those in image.proto. "
336 'Unknown Enum ID: %s' % current)
337
Trent Begin008cade2019-10-31 13:40:59 -0600338 # We can only build one type of these images at a time since image_to_vm.sh
339 # uses the default path if a name is not provided.
340 if vm_types.issuperset({_BASE_VM_ID, _TEST_VM_ID}):
Alex Klein21b95022019-05-09 14:14:46 -0600341 cros_build_lib.Die('Cannot create more than one VM.')
342
Alex Klein27978a42021-07-27 14:18:10 -0600343 return ImageTypes(
344 images=image_types, vms=vm_types, mod_images=mod_image_types)
Alex Klein21b95022019-05-09 14:14:46 -0600345
346
347def _ParseCreateBuildConfig(input_proto):
348 """Helper to parse the image build config for Create."""
349 enable_rootfs_verification = not input_proto.disable_rootfs_verification
350 version = input_proto.version or None
351 disk_layout = input_proto.disk_layout or None
352 builder_path = input_proto.builder_path or None
353 return image.BuildConfig(
Jack Neus761e1842020-12-01 18:20:11 +0000354 enable_rootfs_verification=enable_rootfs_verification,
355 replace=True,
356 version=version,
357 disk_layout=disk_layout,
358 builder_path=builder_path,
Alex Klein21b95022019-05-09 14:14:46 -0600359 )
360
Alex Klein1bcd9882019-03-19 13:25:24 -0600361
Michael Mortensen10146cf2019-11-19 19:59:22 -0700362def _SignerTestResponse(_input_proto, output_proto, _config):
363 """Set output_proto success field on a successful SignerTest response."""
364 output_proto.success = True
365 return controller.RETURN_CODE_SUCCESS
366
367
368@faux.success(_SignerTestResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700369@faux.empty_completed_unsuccessfully_error
Michael Mortensenc83c9952019-08-05 12:15:12 -0600370@validate.exists('image.path')
Alex Klein231d2da2019-07-22 16:44:45 -0600371@validate.validation_complete
372def SignerTest(input_proto, output_proto, _config):
Michael Mortensenc83c9952019-08-05 12:15:12 -0600373 """Run image tests.
374
375 Args:
376 input_proto (image_pb2.ImageTestRequest): The input message.
377 output_proto (image_pb2.ImageTestResult): The output message.
Alex Klein231d2da2019-07-22 16:44:45 -0600378 _config (api_config.ApiConfig): The API call config.
Michael Mortensenc83c9952019-08-05 12:15:12 -0600379 """
Michael Mortensenc83c9952019-08-05 12:15:12 -0600380 image_path = input_proto.image.path
381
Alex Klein231d2da2019-07-22 16:44:45 -0600382 result = image_lib.SecurityTest(image=image_path)
Michael Mortensenc83c9952019-08-05 12:15:12 -0600383 output_proto.success = result
384 if result:
385 return controller.RETURN_CODE_SUCCESS
386 else:
387 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
388
Alex Klein076841b2019-08-29 15:19:39 -0600389
Michael Mortensen10146cf2019-11-19 19:59:22 -0700390def _TestResponse(_input_proto, output_proto, _config):
391 """Set output_proto success field on a successful Test response."""
392 output_proto.success = True
393 return controller.RETURN_CODE_SUCCESS
394
395
396@faux.success(_TestResponse)
Michael Mortensen85d38402019-12-12 09:50:29 -0700397@faux.empty_completed_unsuccessfully_error
Alex Klein2b236722019-06-19 15:44:26 -0600398@validate.require('build_target.name', 'result.directory')
399@validate.exists('image.path')
Alex Klein231d2da2019-07-22 16:44:45 -0600400def Test(input_proto, output_proto, config):
Alex Klein2966e302019-01-17 13:29:38 -0700401 """Run image tests.
402
403 Args:
404 input_proto (image_pb2.ImageTestRequest): The input message.
405 output_proto (image_pb2.ImageTestResult): The output message.
Alex Klein231d2da2019-07-22 16:44:45 -0600406 config (api_config.ApiConfig): The API call config.
Alex Klein2966e302019-01-17 13:29:38 -0700407 """
408 image_path = input_proto.image.path
409 board = input_proto.build_target.name
410 result_directory = input_proto.result.directory
411
Alex Klein2966e302019-01-17 13:29:38 -0700412 if not os.path.isfile(image_path) or not image_path.endswith('.bin'):
Alex Klein4f0eb432019-05-02 13:56:04 -0600413 cros_build_lib.Die(
Alex Klein2966e302019-01-17 13:29:38 -0700414 'The image.path must be an existing image file with a .bin extension.')
415
Alex Klein231d2da2019-07-22 16:44:45 -0600416 if config.validate_only:
417 return controller.RETURN_CODE_VALID_INPUT
418
Alex Klein8cb365a2019-05-15 16:24:53 -0600419 success = image.Test(board, result_directory, image_dir=image_path)
420 output_proto.success = success
421
422 if success:
423 return controller.RETURN_CODE_SUCCESS
424 else:
425 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
Jack Neus761e1842020-12-01 18:20:11 +0000426
427
428@faux.empty_success
429@faux.empty_completed_unsuccessfully_error
430@validate.require('gs_image_dir', 'sysroot.build_target.name')
431def PushImage(input_proto, _output_proto, config):
432 """Push artifacts from the archive bucket to the release bucket.
433
434 Wraps chromite/scripts/pushimage.py.
435
436 Args:
437 input_proto (PushImageRequest): Input proto.
438 _output_proto (PushImageResponse): Output proto.
439 config (api.config.ApiConfig): The API call config.
440
441 Returns:
442 A controller return code (e.g. controller.RETURN_CODE_SUCCESS).
443 """
444 sign_types = []
445 if input_proto.sign_types:
446 for sign_type in input_proto.sign_types:
447 if sign_type not in SUPPORTED_IMAGE_TYPES:
448 logging.error('unsupported sign type %g', sign_type)
449 return controller.RETURN_CODE_INVALID_INPUT
450 sign_types.append(SUPPORTED_IMAGE_TYPES[sign_type])
451
452 # If configured for validation only we're done here.
453 if config.validate_only:
454 return controller.RETURN_CODE_VALID_INPUT
455
Jack Neus485a9d22020-12-21 03:15:15 +0000456 kwargs = {}
457 if input_proto.profile.name:
458 kwargs['profile'] = input_proto.profile.name
459 if input_proto.dest_bucket:
460 kwargs['dest_bucket'] = input_proto.dest_bucket
Jack Neus761e1842020-12-01 18:20:11 +0000461 try:
462 pushimage.PushImage(
463 input_proto.gs_image_dir,
464 input_proto.sysroot.build_target.name,
465 dry_run=input_proto.dryrun,
Jack Neus485a9d22020-12-21 03:15:15 +0000466 sign_types=sign_types,
467 **kwargs)
Jack Neus761e1842020-12-01 18:20:11 +0000468 return controller.RETURN_CODE_SUCCESS
469 except Exception:
Jack Neuse3150a42021-01-29 17:16:36 +0000470 logging.error('PushImage failed: ', exc_info=True)
Jack Neus761e1842020-12-01 18:20:11 +0000471 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY