blob: 0d2ebefff51692b49ce95a79151e057d84bdc571 [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
Brian Norrisdd2e7e62023-06-16 14:07:32 -070012from chromite.api.controller import controller_util
Greg Edelston629468c2022-02-11 14:54:56 -070013from chromite.api.gen.chromite.api import payload_pb2
14from chromite.lib import cros_build_lib
15from chromite.lib.paygen import paygen_payload_lib
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060016from chromite.service import payload
17
18
Kevin Shelton6fa94862022-04-08 20:46:23 -070019if TYPE_CHECKING:
Alex Klein1699fab2022-09-08 08:46:06 -060020 from chromite.api import api_config
Kevin Shelton6fa94862022-04-08 20:46:23 -070021
Alex Klein1699fab2022-09-08 08:46:06 -060022_VALID_IMAGE_PAIRS = (
23 ("src_signed_image", "tgt_signed_image"),
24 ("src_unsigned_image", "tgt_unsigned_image"),
25 ("src_dlc_image", "tgt_dlc_image"),
26 ("full_update", "tgt_unsigned_image"),
27 ("full_update", "tgt_signed_image"),
28 ("full_update", "tgt_dlc_image"),
29)
30_VALID_MINIOS_PAIRS = (
31 ("src_signed_image", "tgt_signed_image"),
32 ("src_unsigned_image", "tgt_unsigned_image"),
33 ("full_update", "tgt_unsigned_image"),
34 ("full_update", "tgt_signed_image"),
35)
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060036
Alex Kleinc07a48b2022-08-26 15:58:44 -060037# TODO: Remove to use the standard cache directory if possible, otherwise
38# document why it cannot be used and preferably move outside of the repo.
Alex Klein1699fab2022-09-08 08:46:06 -060039_DEFAULT_PAYGEN_CACHE_DIR = ".paygen_cache"
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060040
Mike Frysinger16474792023-03-01 01:18:00 -050041
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060042# We have more fields we might validate however, they're either
43# 'oneof' or allowed to be the empty value by design. If @validate
44# gets more complex in the future we can add more here.
Michael Mortensen85d38402019-12-12 09:50:29 -070045@faux.empty_success
46@faux.empty_completed_unsuccessfully_error
Alex Klein1699fab2022-09-08 08:46:06 -060047@validate.require("bucket")
48def GeneratePayload(
49 input_proto: payload_pb2.GenerationRequest,
50 output_proto: payload_pb2.GenerationResponse,
51 config: "api_config.ApiConfig",
52) -> int:
53 """Generate a update payload ('do paygen').
George Engelbrechtd2348bb2019-11-25 21:18:14 -070054
Alex Klein1699fab2022-09-08 08:46:06 -060055 Args:
Alex Klein611dddd2022-10-11 17:02:01 -060056 input_proto: Input proto.
57 output_proto: Output proto.
58 config: The API call config.
George Engelbrechtd2348bb2019-11-25 21:18:14 -070059
Alex Klein1699fab2022-09-08 08:46:06 -060060 Returns:
Alex Klein611dddd2022-10-11 17:02:01 -060061 A controller return code (e.g. controller.RETURN_CODE_SUCCESS).
Alex Klein1699fab2022-09-08 08:46:06 -060062 """
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060063
Alex Klein1699fab2022-09-08 08:46:06 -060064 # Resolve the tgt image oneof.
65 tgt_name = input_proto.WhichOneof("tgt_image_oneof")
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060066 try:
Alex Klein1699fab2022-09-08 08:46:06 -060067 tgt_image = getattr(input_proto, tgt_name)
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060068 except AttributeError:
Alex Kleindf8ee502022-10-18 09:48:15 -060069 cros_build_lib.Die("%s is not a known tgt image type", tgt_name)
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060070
Alex Klein1699fab2022-09-08 08:46:06 -060071 # Resolve the src image oneof.
72 src_name = input_proto.WhichOneof("src_image_oneof")
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060073
Alex Klein1699fab2022-09-08 08:46:06 -060074 # If the source image is 'full_update' we lack a source entirely.
75 if src_name == "full_update":
76 src_image = None
77 # Otherwise we have an image.
78 else:
79 try:
80 src_image = getattr(input_proto, src_name)
81 except AttributeError:
Alex Kleindf8ee502022-10-18 09:48:15 -060082 cros_build_lib.Die("%s is not a known src image type", src_name)
Greg Edelston629468c2022-02-11 14:54:56 -070083
Alex Klein1699fab2022-09-08 08:46:06 -060084 # Ensure they are compatible oneofs.
85 if (src_name, tgt_name) not in _VALID_IMAGE_PAIRS:
86 cros_build_lib.Die(
Alex Kleindf8ee502022-10-18 09:48:15 -060087 "%s and %s are not valid image pairs", src_image, tgt_image
Alex Klein1699fab2022-09-08 08:46:06 -060088 )
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060089
Alex Klein1699fab2022-09-08 08:46:06 -060090 # Ensure that miniOS payloads are only requested for compatible image types.
91 if input_proto.minios and (src_name, tgt_name) not in _VALID_MINIOS_PAIRS:
92 cros_build_lib.Die(
Alex Kleindf8ee502022-10-18 09:48:15 -060093 "%s and %s are not valid image pairs for miniOS",
94 src_image,
95 tgt_image,
Alex Klein1699fab2022-09-08 08:46:06 -060096 )
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060097
Alex Klein1699fab2022-09-08 08:46:06 -060098 # Find the value of bucket or default to 'chromeos-releases'.
99 destination_bucket = input_proto.bucket or "chromeos-releases"
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600100
Brian Norrisdd2e7e62023-06-16 14:07:32 -0700101 chroot = controller_util.ParseChroot(input_proto.chroot)
102
Alex Kleinab87ceb2023-01-24 12:00:51 -0700103 # There's a potential that some paygen_lib library might raise here, but
104 # since we're still involved in config we'll keep it before the
105 # validate_only.
Alex Klein1699fab2022-09-08 08:46:06 -0600106 payload_config = payload.PayloadConfig(
Brian Norrisdd2e7e62023-06-16 14:07:32 -0700107 chroot,
Alex Klein1699fab2022-09-08 08:46:06 -0600108 tgt_image,
109 src_image,
110 destination_bucket,
111 input_proto.minios,
112 input_proto.verify,
113 upload=not input_proto.dryrun,
114 cache_dir=_DEFAULT_PAYGEN_CACHE_DIR,
115 )
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600116
Alex Klein1699fab2022-09-08 08:46:06 -0600117 # If configured for validation only we're done here.
118 if config.validate_only:
119 return controller.RETURN_CODE_VALID_INPUT
120
121 # Do payload generation.
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000122 artifacts = {}
Alex Klein1699fab2022-09-08 08:46:06 -0600123 try:
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000124 artifacts = payload_config.GeneratePayload()
Alex Klein1699fab2022-09-08 08:46:06 -0600125 except paygen_payload_lib.PayloadGenerationSkippedException as e:
126 # If paygen was skipped, provide a reason if possible.
Jack Neus2577e2d2023-04-06 16:14:01 +0000127 if isinstance(e, paygen_payload_lib.MiniOSException):
128 reason = e.return_code()
Alex Klein1699fab2022-09-08 08:46:06 -0600129 output_proto.failure_reason = reason
130
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000131 _SetGeneratePayloadOutputProto(output_proto, artifacts)
132 if _SuccessfulPaygen(artifacts, input_proto.dryrun):
Alex Klein1699fab2022-09-08 08:46:06 -0600133 return controller.RETURN_CODE_SUCCESS
134 elif output_proto.failure_reason:
135 return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
136 else:
137 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600138
139
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000140def _SuccessfulPaygen(
141 artifacts: Dict[int, Tuple[str, str]], dryrun: bool
142) -> bool:
143 """Check to see if the payload generation was successful.
144
145 Args:
146 artifacts: a dict containing an artifact tuple keyed by its
147 version. Artifacts tuple is (local_path, remote_uri).
148 dryrun: whether or not this was a dry run job.
149 """
150 if not artifacts:
151 return False
152 for _, artifact in artifacts.items():
153 if not (artifact[1] or dryrun and artifact[0]):
154 return False
155 return True
156
157
Alex Klein1699fab2022-09-08 08:46:06 -0600158def _SetGeneratePayloadOutputProto(
159 output_proto: payload_pb2.GenerationResponse,
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000160 artifacts: Dict[int, Tuple[str, str]],
Alex Klein1699fab2022-09-08 08:46:06 -0600161):
162 """Set the output proto with the results from the service class.
George Engelbrechtd2348bb2019-11-25 21:18:14 -0700163
Alex Klein1699fab2022-09-08 08:46:06 -0600164 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600165 output_proto: The output proto.
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000166 artifacts: a dict containing an artifact tuple keyed by its
167 version. Artifacts tuple is (local_path, remote_uri).
Alex Klein1699fab2022-09-08 08:46:06 -0600168 """
Benjamin Shai3c1a2322023-02-10 17:29:46 +0000169 for version, artifact in artifacts.items():
170 versioned_artifact = output_proto.versioned_artifacts.add()
171 versioned_artifact.version = version
172 versioned_artifact.local_path = artifact[0] or ""
173 versioned_artifact.remote_uri = artifact[1] or ""