blob: 4ca6870019c4f279beac76ef00882d3b8b6fcaa8 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2019 The ChromiumOS Authors
George Engelbrechtfe63c8c2019-08-31 22:51:29 -06002# 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:
Alex Klein1699fab2022-09-08 08:46:06 -060019 from chromite.api import api_config
Kevin Shelton6fa94862022-04-08 20:46:23 -070020
Alex Klein1699fab2022-09-08 08:46:06 -060021_VALID_IMAGE_PAIRS = (
22 ("src_signed_image", "tgt_signed_image"),
23 ("src_unsigned_image", "tgt_unsigned_image"),
24 ("src_dlc_image", "tgt_dlc_image"),
25 ("full_update", "tgt_unsigned_image"),
26 ("full_update", "tgt_signed_image"),
27 ("full_update", "tgt_dlc_image"),
28)
29_VALID_MINIOS_PAIRS = (
30 ("src_signed_image", "tgt_signed_image"),
31 ("src_unsigned_image", "tgt_unsigned_image"),
32 ("full_update", "tgt_unsigned_image"),
33 ("full_update", "tgt_signed_image"),
34)
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060035
Alex Kleinc07a48b2022-08-26 15:58:44 -060036# TODO: Remove to use the standard cache directory if possible, otherwise
37# document why it cannot be used and preferably move outside of the repo.
Alex Klein1699fab2022-09-08 08:46:06 -060038_DEFAULT_PAYGEN_CACHE_DIR = ".paygen_cache"
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060039
40# We have more fields we might validate however, they're either
41# 'oneof' or allowed to be the empty value by design. If @validate
42# gets more complex in the future we can add more here.
Michael Mortensen85d38402019-12-12 09:50:29 -070043@faux.empty_success
44@faux.empty_completed_unsuccessfully_error
Alex Klein1699fab2022-09-08 08:46:06 -060045@validate.require("bucket")
46def GeneratePayload(
47 input_proto: payload_pb2.GenerationRequest,
48 output_proto: payload_pb2.GenerationResponse,
49 config: "api_config.ApiConfig",
50) -> int:
51 """Generate a update payload ('do paygen').
George Engelbrechtd2348bb2019-11-25 21:18:14 -070052
Alex Klein1699fab2022-09-08 08:46:06 -060053 Args:
54 input_proto: Input proto.
55 output_proto: Output proto.
56 config: The API call config.
George Engelbrechtd2348bb2019-11-25 21:18:14 -070057
Alex Klein1699fab2022-09-08 08:46:06 -060058 Returns:
59 A controller return code (e.g. controller.RETURN_CODE_SUCCESS).
60 """
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060061
Alex Klein1699fab2022-09-08 08:46:06 -060062 # Resolve the tgt image oneof.
63 tgt_name = input_proto.WhichOneof("tgt_image_oneof")
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060064 try:
Alex Klein1699fab2022-09-08 08:46:06 -060065 tgt_image = getattr(input_proto, tgt_name)
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060066 except AttributeError:
Alex Klein1699fab2022-09-08 08:46:06 -060067 cros_build_lib.Die("%s is not a known tgt image type" % (tgt_name,))
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060068
Alex Klein1699fab2022-09-08 08:46:06 -060069 # Resolve the src image oneof.
70 src_name = input_proto.WhichOneof("src_image_oneof")
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060071
Alex Klein1699fab2022-09-08 08:46:06 -060072 # If the source image is 'full_update' we lack a source entirely.
73 if src_name == "full_update":
74 src_image = None
75 # Otherwise we have an image.
76 else:
77 try:
78 src_image = getattr(input_proto, src_name)
79 except AttributeError:
80 cros_build_lib.Die("%s is not a known src image type" % (src_name,))
Greg Edelston629468c2022-02-11 14:54:56 -070081
Alex Klein1699fab2022-09-08 08:46:06 -060082 # Ensure they are compatible oneofs.
83 if (src_name, tgt_name) not in _VALID_IMAGE_PAIRS:
84 cros_build_lib.Die(
85 "%s and %s are not valid image pairs" % (src_image, tgt_image)
86 )
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060087
Alex Klein1699fab2022-09-08 08:46:06 -060088 # Ensure that miniOS payloads are only requested for compatible image types.
89 if input_proto.minios and (src_name, tgt_name) not in _VALID_MINIOS_PAIRS:
90 cros_build_lib.Die(
91 "%s and %s are not valid image pairs for miniOS"
92 % (src_image, tgt_image)
93 )
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060094
Alex Klein1699fab2022-09-08 08:46:06 -060095 # Find the value of bucket or default to 'chromeos-releases'.
96 destination_bucket = input_proto.bucket or "chromeos-releases"
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060097
Alex Klein1699fab2022-09-08 08:46:06 -060098 # There's a potential that some paygen_lib library might raise here, but since
99 # we're still involved in config we'll keep it before the validate_only.
100 payload_config = payload.PayloadConfig(
101 tgt_image,
102 src_image,
103 destination_bucket,
104 input_proto.minios,
105 input_proto.verify,
106 upload=not input_proto.dryrun,
107 cache_dir=_DEFAULT_PAYGEN_CACHE_DIR,
108 )
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600109
Alex Klein1699fab2022-09-08 08:46:06 -0600110 # If configured for validation only we're done here.
111 if config.validate_only:
112 return controller.RETURN_CODE_VALID_INPUT
113
114 # Do payload generation.
115 local_path, remote_uri = "", ""
116 try:
117 local_path, remote_uri = payload_config.GeneratePayload()
118 except paygen_payload_lib.PayloadGenerationSkippedException as e:
119 # If paygen was skipped, provide a reason if possible.
120 if isinstance(e, paygen_payload_lib.NoMiniOSPartitionException):
121 reason = payload_pb2.GenerationResponse.NOT_MINIOS_COMPATIBLE
122 output_proto.failure_reason = reason
123
124 _SetGeneratePayloadOutputProto(output_proto, local_path, remote_uri)
125 if remote_uri or input_proto.dryrun and local_path:
126 return controller.RETURN_CODE_SUCCESS
127 elif output_proto.failure_reason:
128 return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
129 else:
130 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600131
132
Alex Klein1699fab2022-09-08 08:46:06 -0600133def _SetGeneratePayloadOutputProto(
134 output_proto: payload_pb2.GenerationResponse,
135 local_path: str,
136 remote_uri: str,
137):
138 """Set the output proto with the results from the service class.
George Engelbrechtd2348bb2019-11-25 21:18:14 -0700139
Alex Klein1699fab2022-09-08 08:46:06 -0600140 Args:
141 output_proto: The output proto.
142 local_path: set output_proto with the local path, or ''.
143 remote_uri: set output_proto with the remote uri, or ''.
144 """
145 output_proto.success = True
146 output_proto.local_path = local_path or ""
147 output_proto.remote_uri = remote_uri or ""