blob: 343baa181b76c6a6c02d30662609845227ca7529 [file] [log] [blame]
George Engelbrechtfe63c8c2019-08-31 22:51:29 -06001# Copyright 2019 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"""Payload API Service."""
6
Kevin Shelton6fa94862022-04-08 20:46:23 -07007from typing import TYPE_CHECKING
8
George Engelbrechtfe63c8c2019-08-31 22:51:29 -06009from chromite.api import controller
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060010from chromite.api import faux
11from chromite.api import validate
Greg Edelston629468c2022-02-11 14:54:56 -070012from chromite.api.gen.chromite.api import payload_pb2
13from chromite.lib import cros_build_lib
14from chromite.lib.paygen import paygen_payload_lib
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060015from chromite.service import payload
16
17
Kevin Shelton6fa94862022-04-08 20:46:23 -070018if TYPE_CHECKING:
19 from chromite.api import api_config
20
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060021_VALID_IMAGE_PAIRS = (('src_signed_image', 'tgt_signed_image'),
22 ('src_unsigned_image', 'tgt_unsigned_image'),
George Engelbrecht7bea3742020-11-17 20:21:11 -070023 ('src_dlc_image', 'tgt_dlc_image'),
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060024 ('full_update', 'tgt_unsigned_image'),
George Engelbrecht7bea3742020-11-17 20:21:11 -070025 ('full_update', 'tgt_signed_image'),
26 ('full_update', 'tgt_dlc_image'))
Greg Edelston629468c2022-02-11 14:54:56 -070027_VALID_MINIOS_PAIRS = (('src_signed_image', 'tgt_signed_image'),
28 ('src_unsigned_image', 'tgt_unsigned_image'),
29 ('full_update', 'tgt_unsigned_image'),
30 ('full_update', 'tgt_signed_image'))
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060031
Alex Kleinc07a48b2022-08-26 15:58:44 -060032# TODO: Remove to use the standard cache directory if possible, otherwise
33# document why it cannot be used and preferably move outside of the repo.
George Engelbrechta42172f2020-11-04 12:42:04 -070034_DEFAULT_PAYGEN_CACHE_DIR = '.paygen_cache'
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060035
36# We have more fields we might validate however, they're either
37# 'oneof' or allowed to be the empty value by design. If @validate
38# gets more complex in the future we can add more here.
Michael Mortensen85d38402019-12-12 09:50:29 -070039@faux.empty_success
40@faux.empty_completed_unsuccessfully_error
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060041@validate.require('bucket')
Kevin Shelton6fa94862022-04-08 20:46:23 -070042def GeneratePayload(input_proto: payload_pb2.GenerationRequest,
43 output_proto: payload_pb2.GenerationResponse,
44 config: 'api_config.ApiConfig') -> int:
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060045 """Generate a update payload ('do paygen').
George Engelbrechtd2348bb2019-11-25 21:18:14 -070046
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060047 Args:
Kevin Shelton6fa94862022-04-08 20:46:23 -070048 input_proto: Input proto.
49 output_proto: Output proto.
50 config: The API call config.
George Engelbrechtd2348bb2019-11-25 21:18:14 -070051
52 Returns:
53 A controller return code (e.g. controller.RETURN_CODE_SUCCESS).
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060054 """
55
56 # Resolve the tgt image oneof.
57 tgt_name = input_proto.WhichOneof('tgt_image_oneof')
58 try:
59 tgt_image = getattr(input_proto, tgt_name)
60 except AttributeError:
61 cros_build_lib.Die('%s is not a known tgt image type' % (tgt_name,))
62
63 # Resolve the src image oneof.
64 src_name = input_proto.WhichOneof('src_image_oneof')
65
66 # If the source image is 'full_update' we lack a source entirely.
67 if src_name == 'full_update':
68 src_image = None
69 # Otherwise we have an image.
70 else:
71 try:
72 src_image = getattr(input_proto, src_name)
73 except AttributeError:
74 cros_build_lib.Die('%s is not a known src image type' % (src_name,))
75
76 # Ensure they are compatible oneofs.
77 if (src_name, tgt_name) not in _VALID_IMAGE_PAIRS:
78 cros_build_lib.Die('%s and %s are not valid image pairs' %
79 (src_image, tgt_image))
80
Greg Edelston629468c2022-02-11 14:54:56 -070081 # Ensure that miniOS payloads are only requested for compatible image types.
82 if input_proto.minios and (src_name, tgt_name) not in _VALID_MINIOS_PAIRS:
83 cros_build_lib.Die('%s and %s are not valid image pairs for miniOS' %
84 (src_image, tgt_image))
85
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060086 # Find the value of bucket or default to 'chromeos-releases'.
87 destination_bucket = input_proto.bucket or 'chromeos-releases'
88
89 # There's a potential that some paygen_lib library might raise here, but since
90 # we're still involved in config we'll keep it before the validate_only.
Navil Perezf5482be2020-04-09 23:18:14 -060091 payload_config = payload.PayloadConfig(tgt_image, src_image,
Greg Edelston629468c2022-02-11 14:54:56 -070092 destination_bucket, input_proto.minios,
93 input_proto.verify,
George Engelbrechte2aaad12021-11-19 14:52:38 -070094 upload=not input_proto.dryrun,
George Engelbrechta42172f2020-11-04 12:42:04 -070095 cache_dir=_DEFAULT_PAYGEN_CACHE_DIR)
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060096
97 # If configured for validation only we're done here.
98 if config.validate_only:
99 return controller.RETURN_CODE_VALID_INPUT
100
101 # Do payload generation.
Greg Edelston629468c2022-02-11 14:54:56 -0700102 local_path, remote_uri = '', ''
103 try:
104 local_path, remote_uri = payload_config.GeneratePayload()
Jae Hoon Kim81482cf2022-08-26 21:55:13 +0000105 except paygen_payload_lib.PayloadGenerationSkippedException as e:
Greg Edelston629468c2022-02-11 14:54:56 -0700106 # If paygen was skipped, provide a reason if possible.
Jae Hoon Kim81482cf2022-08-26 21:55:13 +0000107 if isinstance(e, paygen_payload_lib.NoMiniOSPartitionException):
108 reason = payload_pb2.GenerationResponse.NOT_MINIOS_COMPATIBLE
109 output_proto.failure_reason = reason
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600110
Greg Edelston629468c2022-02-11 14:54:56 -0700111 _SetGeneratePayloadOutputProto(output_proto, local_path, remote_uri)
George Engelbrechte2aaad12021-11-19 14:52:38 -0700112 if remote_uri or input_proto.dryrun and local_path:
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600113 return controller.RETURN_CODE_SUCCESS
Benjamin Shai6e97bc02022-03-07 21:34:39 +0000114 elif output_proto.failure_reason:
115 return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600116 else:
117 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
118
119
Kevin Shelton6fa94862022-04-08 20:46:23 -0700120def _SetGeneratePayloadOutputProto(output_proto: payload_pb2.GenerationResponse,
121 local_path: str,
122 remote_uri: str):
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600123 """Set the output proto with the results from the service class.
George Engelbrechtd2348bb2019-11-25 21:18:14 -0700124
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600125 Args:
Kevin Shelton6fa94862022-04-08 20:46:23 -0700126 output_proto: The output proto.
127 local_path: set output_proto with the local path, or ''.
128 remote_uri: set output_proto with the remote uri, or ''.
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600129 """
George Engelbrecht52d0dba2020-11-12 11:49:02 -0700130 output_proto.success = True
George Engelbrechtdbc96742020-11-13 15:59:48 -0700131 output_proto.local_path = local_path or ''
132 output_proto.remote_uri = remote_uri or ''