blob: 567dfd06e34b1737cec10251df694a781278707f [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2019 The ChromiumOS Authors
Evan Hernandezd437b4e2019-03-25 13:48:30 -06002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Portage Binhost operations."""
6
Michael Mortensenfc823882019-08-27 14:38:07 -06007import os
8import shutil
Kevin Shelton703b6882022-01-24 16:31:31 -08009from typing import TYPE_CHECKING
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040010import urllib.parse
Evan Hernandezd437b4e2019-03-25 13:48:30 -060011
Alex Klein231d2da2019-07-22 16:44:45 -060012from chromite.api import controller
Alex Klein076841b2019-08-29 15:19:39 -060013from chromite.api import faux
Alex Klein2b236722019-06-19 15:44:26 -060014from chromite.api import validate
Alex Kleinaf0e0452019-06-03 18:10:01 -060015from chromite.api.controller import controller_util
Evan Hernandezd437b4e2019-03-25 13:48:30 -060016from chromite.api.gen.chromite.api import binhost_pb2
LaMont Jonesc64ae212019-04-15 15:41:28 -060017from chromite.lib import constants
18from chromite.lib import cros_build_lib
Evan Hernandezd437b4e2019-03-25 13:48:30 -060019from chromite.lib import gs
Alex Kleinaf0e0452019-06-03 18:10:01 -060020from chromite.lib import sysroot_lib
Evan Hernandezd437b4e2019-03-25 13:48:30 -060021from chromite.service import binhost
22
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040023
Kevin Shelton703b6882022-01-24 16:31:31 -080024if TYPE_CHECKING:
Alex Klein1699fab2022-09-08 08:46:06 -060025 from chromite.api import api_config
Mike Frysingeref94e4c2020-02-10 23:59:54 -050026
Alex Kleinaf0e0452019-06-03 18:10:01 -060027_OVERLAY_TYPE_TO_NAME = {
28 binhost_pb2.OVERLAYTYPE_PUBLIC: constants.PUBLIC_OVERLAYS,
29 binhost_pb2.OVERLAYTYPE_PRIVATE: constants.PRIVATE_OVERLAYS,
30 binhost_pb2.OVERLAYTYPE_BOTH: constants.BOTH_OVERLAYS,
Alex Klein1699fab2022-09-08 08:46:06 -060031 binhost_pb2.OVERLAYTYPE_NONE: None,
Alex Kleinaf0e0452019-06-03 18:10:01 -060032}
33
Arif Kasim6242cdd2022-10-19 17:51:00 +000034# Default maximum number of URIs to be stored in Binhost conf file.
35_DEFAULT_BINHOST_MAX_URIS = 1
36
Evan Hernandezd437b4e2019-03-25 13:48:30 -060037
Michael Mortensena0af77b2019-11-13 11:15:15 -070038def _GetBinhostsResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -060039 """Add fake binhosts to a successful response."""
40 new_binhost = output_proto.binhosts.add()
41 new_binhost.uri = (
42 "gs://cr-prebuilt/board/amd64-generic/"
43 "paladin-R66-17.0.0-rc2/packages/"
44 )
45 new_binhost.package_index = "Packages"
Michael Mortensena0af77b2019-11-13 11:15:15 -070046
47
48@faux.success(_GetBinhostsResponse)
49@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -060050@validate.require("build_target.name")
Alex Klein231d2da2019-07-22 16:44:45 -060051@validate.validation_complete
52def GetBinhosts(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -060053 """Get a list of binhosts."""
54 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
Alex Klein7e40d252019-06-10 09:01:32 -060055
Alex Klein1699fab2022-09-08 08:46:06 -060056 binhosts = binhost.GetBinhosts(build_target)
Alex Klein7e40d252019-06-10 09:01:32 -060057
Alex Klein1699fab2022-09-08 08:46:06 -060058 for current in binhosts:
59 new_binhost = output_proto.binhosts.add()
60 new_binhost.uri = current
61 new_binhost.package_index = "Packages"
Alex Klein7e40d252019-06-10 09:01:32 -060062
63
Michael Mortensen42251f92019-11-14 11:01:43 -070064def _GetPrivatePrebuiltAclArgsResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -060065 """Add fake acls to a successful response."""
66 new_arg = output_proto.args.add()
67 new_arg.arg = "-g"
68 new_arg.value = "group1:READ"
Michael Mortensen42251f92019-11-14 11:01:43 -070069
70
71@faux.success(_GetPrivatePrebuiltAclArgsResponse)
72@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -060073@validate.require("build_target.name")
Alex Klein231d2da2019-07-22 16:44:45 -060074@validate.validation_complete
75def GetPrivatePrebuiltAclArgs(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -060076 """Get the ACL args from the files in the private overlays."""
77 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
Alex Kleina471f682019-05-31 11:23:45 -060078
Alex Klein1699fab2022-09-08 08:46:06 -060079 try:
80 args = binhost.GetPrebuiltAclArgs(build_target)
81 except binhost.Error as e:
82 cros_build_lib.Die(e)
Alex Kleina471f682019-05-31 11:23:45 -060083
Alex Klein1699fab2022-09-08 08:46:06 -060084 for arg, value in args:
85 new_arg = output_proto.args.add()
86 new_arg.arg = arg
87 new_arg.value = value
Alex Kleina471f682019-05-31 11:23:45 -060088
89
Michael Mortensen42251f92019-11-14 11:01:43 -070090def _PrepareBinhostUploadsResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -060091 """Add fake binhost upload targets to a successful response."""
92 output_proto.uploads_dir = "/upload/directory"
93 output_proto.upload_targets.add().path = "upload_target"
Michael Mortensen42251f92019-11-14 11:01:43 -070094
95
96@faux.success(_PrepareBinhostUploadsResponse)
97@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -060098@validate.require("uri")
Kevin Shelton703b6882022-01-24 16:31:31 -080099def PrepareBinhostUploads(
100 input_proto: binhost_pb2.PrepareBinhostUploadsRequest,
101 output_proto: binhost_pb2.PrepareBinhostUploadsResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600102 config: "api_config.ApiConfig",
103):
104 """Return a list of files to upload to the binhost.
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600105
Alex Klein1699fab2022-09-08 08:46:06 -0600106 See BinhostService documentation in api/proto/binhost.proto.
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600107
Alex Klein1699fab2022-09-08 08:46:06 -0600108 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600109 input_proto: The input proto.
110 output_proto: The output proto.
111 config: The API call config.
Alex Klein1699fab2022-09-08 08:46:06 -0600112 """
113 if input_proto.sysroot.build_target.name:
114 build_target_msg = input_proto.sysroot.build_target
115 else:
116 build_target_msg = input_proto.build_target
117 sysroot_path = input_proto.sysroot.path
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600118
Alex Klein1699fab2022-09-08 08:46:06 -0600119 if not sysroot_path and not build_target_msg.name:
120 cros_build_lib.Die("Sysroot.path is required.")
Alex Kleinaf0e0452019-06-03 18:10:01 -0600121
Alex Klein1699fab2022-09-08 08:46:06 -0600122 build_target = controller_util.ParseBuildTarget(build_target_msg)
123 chroot = controller_util.ParseChroot(input_proto.chroot)
Alex Kleinaf0e0452019-06-03 18:10:01 -0600124
Alex Klein1699fab2022-09-08 08:46:06 -0600125 if not sysroot_path:
126 sysroot_path = build_target.root
127 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Kleinaf0e0452019-06-03 18:10:01 -0600128
Alex Klein1699fab2022-09-08 08:46:06 -0600129 uri = input_proto.uri
130 # For now, we enforce that all input URIs are Google Storage buckets.
131 if not gs.PathIsGs(uri):
132 raise ValueError("Upload URI %s must be Google Storage." % uri)
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600133
Alex Kleina0472ed2022-11-02 12:07:04 -0600134 package_index_paths = [f.path.path for f in input_proto.package_index_files]
135
Alex Klein1699fab2022-09-08 08:46:06 -0600136 if config.validate_only:
137 return controller.RETURN_CODE_VALID_INPUT
Alex Klein231d2da2019-07-22 16:44:45 -0600138
Alex Klein1699fab2022-09-08 08:46:06 -0600139 parsed_uri = urllib.parse.urlparse(uri)
140 upload_uri = gs.GetGsURL(parsed_uri.netloc, for_gsutil=True).rstrip("/")
141 upload_path = parsed_uri.path.lstrip("/")
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600142
Alex Klein1699fab2022-09-08 08:46:06 -0600143 # Read all packages and update the index. The index must be uploaded to the
144 # binhost for Portage to use it, so include it in upload_targets.
145 uploads_dir = binhost.GetPrebuiltsRoot(chroot, sysroot, build_target)
146 index_path = binhost.UpdatePackageIndex(
147 uploads_dir, upload_uri, upload_path, sudo=True
148 )
Alex Kleina0472ed2022-11-02 12:07:04 -0600149 upload_targets = binhost.GetPrebuiltsFiles(
150 uploads_dir, package_index_paths=package_index_paths, sudo=True
151 )
Alex Klein1699fab2022-09-08 08:46:06 -0600152 assert index_path.startswith(
153 uploads_dir
154 ), "expected index_path to start with uploads_dir"
155 upload_targets.append(index_path[len(uploads_dir) :])
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600156
Alex Klein1699fab2022-09-08 08:46:06 -0600157 output_proto.uploads_dir = uploads_dir
158 for upload_target in upload_targets:
159 output_proto.upload_targets.add().path = upload_target.strip("/")
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600160
Alex Klein076841b2019-08-29 15:19:39 -0600161
Alex Klein1699fab2022-09-08 08:46:06 -0600162def _PrepareDevInstallBinhostUploadsResponse(
163 _input_proto, output_proto, _config
164):
165 """Add fake binhost files to a successful response."""
166 output_proto.upload_targets.add().path = "app-arch/zip-3.0-r3.tbz2"
167 output_proto.upload_targets.add().path = "virtual/python-enum34-1.tbz2"
168 output_proto.upload_targets.add().path = "Packages"
Michael Mortensen42251f92019-11-14 11:01:43 -0700169
170
171@faux.success(_PrepareDevInstallBinhostUploadsResponse)
172@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600173@validate.require("uri", "sysroot.path")
174@validate.exists("uploads_dir")
Kevin Shelton703b6882022-01-24 16:31:31 -0800175def PrepareDevInstallBinhostUploads(
176 input_proto: binhost_pb2.PrepareDevInstallBinhostUploadsRequest,
177 output_proto: binhost_pb2.PrepareDevInstallBinhostUploadsResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600178 config: "api_config.ApiConfig",
179):
180 """Return a list of files to upload to the binhost"
Michael Mortensenfc823882019-08-27 14:38:07 -0600181
Alex Klein1699fab2022-09-08 08:46:06 -0600182 The files will also be copied to the uploads_dir.
183 See BinhostService documentation in api/proto/binhost.proto.
Michael Mortensenfc823882019-08-27 14:38:07 -0600184
Alex Klein1699fab2022-09-08 08:46:06 -0600185 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600186 input_proto: The input proto.
187 output_proto: The output proto.
188 config: The API call config.
Alex Klein1699fab2022-09-08 08:46:06 -0600189 """
190 sysroot_path = input_proto.sysroot.path
Michael Mortensenfc823882019-08-27 14:38:07 -0600191
Alex Klein1699fab2022-09-08 08:46:06 -0600192 chroot = controller_util.ParseChroot(input_proto.chroot)
193 sysroot = sysroot_lib.Sysroot(sysroot_path)
Michael Mortensenfc823882019-08-27 14:38:07 -0600194
Alex Klein1699fab2022-09-08 08:46:06 -0600195 uri = input_proto.uri
196 # For now, we enforce that all input URIs are Google Storage buckets.
197 if not gs.PathIsGs(uri):
198 raise ValueError("Upload URI %s must be Google Storage." % uri)
Michael Mortensenfc823882019-08-27 14:38:07 -0600199
Alex Klein1699fab2022-09-08 08:46:06 -0600200 if config.validate_only:
201 return controller.RETURN_CODE_VALID_INPUT
Michael Mortensenfc823882019-08-27 14:38:07 -0600202
Alex Klein1699fab2022-09-08 08:46:06 -0600203 parsed_uri = urllib.parse.urlparse(uri)
204 upload_uri = gs.GetGsURL(parsed_uri.netloc, for_gsutil=True).rstrip("/")
205 upload_path = parsed_uri.path.lstrip("/")
Michael Mortensenfc823882019-08-27 14:38:07 -0600206
Alex Klein1699fab2022-09-08 08:46:06 -0600207 # Calculate the filename for the to-be-created Packages file, which will
208 # contain only devinstall packages.
209 devinstall_package_index_path = os.path.join(
210 input_proto.uploads_dir, "Packages"
211 )
212 upload_targets_list = binhost.ReadDevInstallFilesToCreatePackageIndex(
213 chroot, sysroot, devinstall_package_index_path, upload_uri, upload_path
214 )
Michael Mortensenfc823882019-08-27 14:38:07 -0600215
Alex Klein1699fab2022-09-08 08:46:06 -0600216 package_dir = chroot.full_path(sysroot.path, "packages")
217 for upload_target in upload_targets_list:
218 # Copy each package to target/category/package
219 upload_target = upload_target.strip("/")
220 category = upload_target.split(os.sep)[0]
221 target_dir = os.path.join(input_proto.uploads_dir, category)
222 if not os.path.exists(target_dir):
223 os.makedirs(target_dir)
224 full_src_pkg_path = os.path.join(package_dir, upload_target)
225 full_target_src_path = os.path.join(
226 input_proto.uploads_dir, upload_target
227 )
228 shutil.copyfile(full_src_pkg_path, full_target_src_path)
229 output_proto.upload_targets.add().path = upload_target
230 output_proto.upload_targets.add().path = "Packages"
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600231
Alex Klein076841b2019-08-29 15:19:39 -0600232
Michael Mortensen42251f92019-11-14 11:01:43 -0700233def _SetBinhostResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600234 """Add fake binhost file to a successful response."""
235 output_proto.output_file = "/path/to/BINHOST.conf"
Michael Mortensen42251f92019-11-14 11:01:43 -0700236
237
238@faux.success(_SetBinhostResponse)
239@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600240@validate.require("build_target.name", "key", "uri")
Alex Klein231d2da2019-07-22 16:44:45 -0600241@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600242def SetBinhost(
243 input_proto: binhost_pb2.SetBinhostRequest,
244 output_proto: binhost_pb2.SetBinhostResponse,
245 _config: "api_config.ApiConfig",
246):
247 """Set the URI for a given binhost key and build target.
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600248
Alex Klein1699fab2022-09-08 08:46:06 -0600249 See BinhostService documentation in api/proto/binhost.proto.
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600250
Alex Klein1699fab2022-09-08 08:46:06 -0600251 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600252 input_proto: The input proto.
253 output_proto: The output proto.
254 _config: The API call config.
Alex Klein1699fab2022-09-08 08:46:06 -0600255 """
256 target = input_proto.build_target.name
257 key = binhost_pb2.BinhostKey.Name(input_proto.key)
258 uri = input_proto.uri
259 private = input_proto.private
Arif Kasim6242cdd2022-10-19 17:51:00 +0000260 max_uris = input_proto.max_uris or _DEFAULT_BINHOST_MAX_URIS
Alex Klein6fb0eb82019-05-20 16:16:14 -0600261
Alex Klein1699fab2022-09-08 08:46:06 -0600262 output_proto.output_file = binhost.SetBinhost(
Arif Kasim6242cdd2022-10-19 17:51:00 +0000263 target, key, uri, private=private, max_uris=max_uris
Alex Klein1699fab2022-09-08 08:46:06 -0600264 )
LaMont Jonesc64ae212019-04-15 15:41:28 -0600265
LaMont Jonesc64ae212019-04-15 15:41:28 -0600266
Arif Kasima0467262022-11-11 17:08:14 +0000267def _GetBinhostConfPathResponse(_input_proto, output_proto, _config):
268 """Add fake binhost file to a successful response."""
269 output_proto.conf_path = "/path/to/BINHOST.conf"
270
271
272@faux.success(_GetBinhostConfPathResponse)
273@faux.empty_error
274@validate.require("build_target.name", "key")
275@validate.validation_complete
276def GetBinhostConfPath(
277 input_proto: binhost_pb2.GetBinhostConfPathRequest,
278 output_proto: binhost_pb2.GetBinhostConfPathResponse,
279 _config: "api_config.ApiConfig",
280):
281 target = input_proto.build_target.name
282 key = binhost_pb2.BinhostKey.Name(input_proto.key)
283 private = input_proto.private
284 output_proto.conf_path = str(
285 binhost.GetBinhostConfPath(target, key, private)
286 )
287
288
Michael Mortensen42251f92019-11-14 11:01:43 -0700289def _RegenBuildCacheResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600290 """Add fake binhosts cache path to a successful response."""
291 output_proto.modified_overlays.add().path = "/path/to/BuildCache"
Michael Mortensen42251f92019-11-14 11:01:43 -0700292
293
294@faux.success(_RegenBuildCacheResponse)
295@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600296@validate.require("overlay_type")
297@validate.is_in("overlay_type", _OVERLAY_TYPE_TO_NAME)
Alex Klein231d2da2019-07-22 16:44:45 -0600298@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600299def RegenBuildCache(
300 input_proto: binhost_pb2.RegenBuildCacheRequest,
301 output_proto: binhost_pb2.RegenBuildCacheResponse,
302 _config: "api_config.ApiConfig",
303):
304 """Regenerate the Build Cache for a build target.
LaMont Jonesc64ae212019-04-15 15:41:28 -0600305
Alex Klein1699fab2022-09-08 08:46:06 -0600306 See BinhostService documentation in api/proto/binhost.proto.
LaMont Jonesc64ae212019-04-15 15:41:28 -0600307
Alex Klein1699fab2022-09-08 08:46:06 -0600308 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600309 input_proto: The input proto.
310 output_proto: The output proto.
311 _config: The API call config.
Alex Klein1699fab2022-09-08 08:46:06 -0600312 """
313 chroot = controller_util.ParseChroot(input_proto.chroot)
314 overlay_type = input_proto.overlay_type
315 overlays = binhost.RegenBuildCache(
316 chroot, _OVERLAY_TYPE_TO_NAME[overlay_type]
317 )
Alex Klein82c85d42019-08-14 15:47:51 -0600318
Alex Klein1699fab2022-09-08 08:46:06 -0600319 for overlay in overlays:
320 output_proto.modified_overlays.add().path = overlay