blob: e713a8498a4749a8687143dd476a230c3c1c5aea [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
Benjamin Shai3c1a2322023-02-10 17:29:46 +00007from typing import Dict, Tuple, TYPE_CHECKING
Kevin Shelton6fa94862022-04-08 20:46:23 -07008
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
Mike Frysinger16474792023-03-01 01:18:00 -050040
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060041# We have more fields we might validate however, they're either
42# 'oneof' or allowed to be the empty value by design. If @validate
43# gets more complex in the future we can add more here.
Michael Mortensen85d38402019-12-12 09:50:29 -070044@faux.empty_success
45@faux.empty_completed_unsuccessfully_error
Alex Klein1699fab2022-09-08 08:46:06 -060046@validate.require("bucket")
47def GeneratePayload(
48 input_proto: payload_pb2.GenerationRequest,
49 output_proto: payload_pb2.GenerationResponse,
50 config: "api_config.ApiConfig",
51) -> int:
52 """Generate a update payload ('do paygen').
George Engelbrechtd2348bb2019-11-25 21:18:14 -070053
Alex Klein1699fab2022-09-08 08:46:06 -060054 Args:
Alex Klein611dddd2022-10-11 17:02:01 -060055 input_proto: Input proto.
56 output_proto: Output proto.
57 config: The API call config.
George Engelbrechtd2348bb2019-11-25 21:18:14 -070058
Alex Klein1699fab2022-09-08 08:46:06 -060059 Returns:
Alex Klein611dddd2022-10-11 17:02:01 -060060 A controller return code (e.g. controller.RETURN_CODE_SUCCESS).
Alex Klein1699fab2022-09-08 08:46:06 -060061 """
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060062
Alex Klein1699fab2022-09-08 08:46:06 -060063 # Resolve the tgt image oneof.
64 tgt_name = input_proto.WhichOneof("tgt_image_oneof")
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060065 try:
Alex Klein1699fab2022-09-08 08:46:06 -060066 tgt_image = getattr(input_proto, tgt_name)
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060067 except AttributeError:
Alex Kleindf8ee502022-10-18 09:48:15 -060068 cros_build_lib.Die("%s is not a known tgt image type", tgt_name)
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060069
Alex Klein1699fab2022-09-08 08:46:06 -060070 # Resolve the src image oneof.
71 src_name = input_proto.WhichOneof("src_image_oneof")
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060072
Alex Klein1699fab2022-09-08 08:46:06 -060073 # If the source image is 'full_update' we lack a source entirely.
74 if src_name == "full_update":
75 src_image = None
76 # Otherwise we have an image.
77 else:
78 try:
79 src_image = getattr(input_proto, src_name)
80 except AttributeError:
Alex Kleindf8ee502022-10-18 09:48:15 -060081 cros_build_lib.Die("%s is not a known src image type", src_name)
Greg Edelston629468c2022-02-11 14:54:56 -070082
Alex Klein1699fab2022-09-08 08:46:06 -060083 # Ensure they are compatible oneofs.
84 if (src_name, tgt_name) not in _VALID_IMAGE_PAIRS:
85 cros_build_lib.Die(
Alex Kleindf8ee502022-10-18 09:48:15 -060086 "%s and %s are not valid image pairs", src_image, tgt_image
Alex Klein1699fab2022-09-08 08:46:06 -060087 )
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060088
Alex Klein1699fab2022-09-08 08:46:06 -060089 # Ensure that miniOS payloads are only requested for compatible image types.
90 if input_proto.minios and (src_name, tgt_name) not in _VALID_MINIOS_PAIRS:
91 cros_build_lib.Die(
Alex Kleindf8ee502022-10-18 09:48:15 -060092 "%s and %s are not valid image pairs for miniOS",
93 src_image,
94 tgt_image,
Alex Klein1699fab2022-09-08 08:46:06 -060095 )
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060096
Alex Klein1699fab2022-09-08 08:46:06 -060097 # Find the value of bucket or default to 'chromeos-releases'.
98 destination_bucket = input_proto.bucket or "chromeos-releases"
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060099
Alex Kleinab87ceb2023-01-24 12:00:51 -0700100 # There's a potential that some paygen_lib library might raise here, but
101 # since we're still involved in config we'll keep it before the
102 # validate_only.
Alex Klein1699fab2022-09-08 08:46:06 -0600103 payload_config = payload.PayloadConfig(
104 tgt_image,
105 src_image,
106 destination_bucket,
107 input_proto.minios,
108 input_proto.verify,
109 upload=not input_proto.dryrun,
110 cache_dir=_DEFAULT_PAYGEN_CACHE_DIR,
111 )
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600112
Alex Klein1699fab2022-09-08 08:46:06 -0600113 # If configured for validation only we're done here.
114 if config.validate_only:
115 return controller.RETURN_CODE_VALID_INPUT
116
117 # Do payload generation.
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000118 artifacts = {}
Alex Klein1699fab2022-09-08 08:46:06 -0600119 try:
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000120 artifacts = payload_config.GeneratePayload()
Alex Klein1699fab2022-09-08 08:46:06 -0600121 except paygen_payload_lib.PayloadGenerationSkippedException as e:
122 # If paygen was skipped, provide a reason if possible.
123 if isinstance(e, paygen_payload_lib.NoMiniOSPartitionException):
124 reason = payload_pb2.GenerationResponse.NOT_MINIOS_COMPATIBLE
125 output_proto.failure_reason = reason
126
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000127 _SetGeneratePayloadOutputProto(output_proto, artifacts)
128 if _SuccessfulPaygen(artifacts, input_proto.dryrun):
Alex Klein1699fab2022-09-08 08:46:06 -0600129 return controller.RETURN_CODE_SUCCESS
130 elif output_proto.failure_reason:
131 return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
132 else:
133 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600134
135
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000136def _SuccessfulPaygen(
137 artifacts: Dict[int, Tuple[str, str]], dryrun: bool
138) -> bool:
139 """Check to see if the payload generation was successful.
140
141 Args:
142 artifacts: a dict containing an artifact tuple keyed by its
143 version. Artifacts tuple is (local_path, remote_uri).
144 dryrun: whether or not this was a dry run job.
145 """
146 if not artifacts:
147 return False
148 for _, artifact in artifacts.items():
149 if not (artifact[1] or dryrun and artifact[0]):
150 return False
151 return True
152
153
Alex Klein1699fab2022-09-08 08:46:06 -0600154def _SetGeneratePayloadOutputProto(
155 output_proto: payload_pb2.GenerationResponse,
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000156 artifacts: Dict[int, Tuple[str, str]],
Alex Klein1699fab2022-09-08 08:46:06 -0600157):
158 """Set the output proto with the results from the service class.
George Engelbrechtd2348bb2019-11-25 21:18:14 -0700159
Alex Klein1699fab2022-09-08 08:46:06 -0600160 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600161 output_proto: The output proto.
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000162 artifacts: a dict containing an artifact tuple keyed by its
163 version. Artifacts tuple is (local_path, remote_uri).
Alex Klein1699fab2022-09-08 08:46:06 -0600164 """
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000165 for version, artifact in artifacts.items():
166 versioned_artifact = output_proto.versioned_artifacts.add()
167 versioned_artifact.version = version
168 versioned_artifact.local_path = artifact[0] or ""
169 versioned_artifact.remote_uri = artifact[1] or ""