blob: 005831e84ac6f36f07c6a9a4c29be91449b27614 [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 Klein1699fab2022-09-08 08:46:06 -0600134 if config.validate_only:
135 return controller.RETURN_CODE_VALID_INPUT
Alex Klein231d2da2019-07-22 16:44:45 -0600136
Alex Klein1699fab2022-09-08 08:46:06 -0600137 parsed_uri = urllib.parse.urlparse(uri)
138 upload_uri = gs.GetGsURL(parsed_uri.netloc, for_gsutil=True).rstrip("/")
139 upload_path = parsed_uri.path.lstrip("/")
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600140
Alex Klein1699fab2022-09-08 08:46:06 -0600141 # Read all packages and update the index. The index must be uploaded to the
142 # binhost for Portage to use it, so include it in upload_targets.
143 uploads_dir = binhost.GetPrebuiltsRoot(chroot, sysroot, build_target)
144 index_path = binhost.UpdatePackageIndex(
145 uploads_dir, upload_uri, upload_path, sudo=True
146 )
147 upload_targets = binhost.GetPrebuiltsFiles(uploads_dir)
148 assert index_path.startswith(
149 uploads_dir
150 ), "expected index_path to start with uploads_dir"
151 upload_targets.append(index_path[len(uploads_dir) :])
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600152
Alex Klein1699fab2022-09-08 08:46:06 -0600153 output_proto.uploads_dir = uploads_dir
154 for upload_target in upload_targets:
155 output_proto.upload_targets.add().path = upload_target.strip("/")
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600156
Alex Klein076841b2019-08-29 15:19:39 -0600157
Alex Klein1699fab2022-09-08 08:46:06 -0600158def _PrepareDevInstallBinhostUploadsResponse(
159 _input_proto, output_proto, _config
160):
161 """Add fake binhost files to a successful response."""
162 output_proto.upload_targets.add().path = "app-arch/zip-3.0-r3.tbz2"
163 output_proto.upload_targets.add().path = "virtual/python-enum34-1.tbz2"
164 output_proto.upload_targets.add().path = "Packages"
Michael Mortensen42251f92019-11-14 11:01:43 -0700165
166
167@faux.success(_PrepareDevInstallBinhostUploadsResponse)
168@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600169@validate.require("uri", "sysroot.path")
170@validate.exists("uploads_dir")
Kevin Shelton703b6882022-01-24 16:31:31 -0800171def PrepareDevInstallBinhostUploads(
172 input_proto: binhost_pb2.PrepareDevInstallBinhostUploadsRequest,
173 output_proto: binhost_pb2.PrepareDevInstallBinhostUploadsResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600174 config: "api_config.ApiConfig",
175):
176 """Return a list of files to upload to the binhost"
Michael Mortensenfc823882019-08-27 14:38:07 -0600177
Alex Klein1699fab2022-09-08 08:46:06 -0600178 The files will also be copied to the uploads_dir.
179 See BinhostService documentation in api/proto/binhost.proto.
Michael Mortensenfc823882019-08-27 14:38:07 -0600180
Alex Klein1699fab2022-09-08 08:46:06 -0600181 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600182 input_proto: The input proto.
183 output_proto: The output proto.
184 config: The API call config.
Alex Klein1699fab2022-09-08 08:46:06 -0600185 """
186 sysroot_path = input_proto.sysroot.path
Michael Mortensenfc823882019-08-27 14:38:07 -0600187
Alex Klein1699fab2022-09-08 08:46:06 -0600188 chroot = controller_util.ParseChroot(input_proto.chroot)
189 sysroot = sysroot_lib.Sysroot(sysroot_path)
Michael Mortensenfc823882019-08-27 14:38:07 -0600190
Alex Klein1699fab2022-09-08 08:46:06 -0600191 uri = input_proto.uri
192 # For now, we enforce that all input URIs are Google Storage buckets.
193 if not gs.PathIsGs(uri):
194 raise ValueError("Upload URI %s must be Google Storage." % uri)
Michael Mortensenfc823882019-08-27 14:38:07 -0600195
Alex Klein1699fab2022-09-08 08:46:06 -0600196 if config.validate_only:
197 return controller.RETURN_CODE_VALID_INPUT
Michael Mortensenfc823882019-08-27 14:38:07 -0600198
Alex Klein1699fab2022-09-08 08:46:06 -0600199 parsed_uri = urllib.parse.urlparse(uri)
200 upload_uri = gs.GetGsURL(parsed_uri.netloc, for_gsutil=True).rstrip("/")
201 upload_path = parsed_uri.path.lstrip("/")
Michael Mortensenfc823882019-08-27 14:38:07 -0600202
Alex Klein1699fab2022-09-08 08:46:06 -0600203 # Calculate the filename for the to-be-created Packages file, which will
204 # contain only devinstall packages.
205 devinstall_package_index_path = os.path.join(
206 input_proto.uploads_dir, "Packages"
207 )
208 upload_targets_list = binhost.ReadDevInstallFilesToCreatePackageIndex(
209 chroot, sysroot, devinstall_package_index_path, upload_uri, upload_path
210 )
Michael Mortensenfc823882019-08-27 14:38:07 -0600211
Alex Klein1699fab2022-09-08 08:46:06 -0600212 package_dir = chroot.full_path(sysroot.path, "packages")
213 for upload_target in upload_targets_list:
214 # Copy each package to target/category/package
215 upload_target = upload_target.strip("/")
216 category = upload_target.split(os.sep)[0]
217 target_dir = os.path.join(input_proto.uploads_dir, category)
218 if not os.path.exists(target_dir):
219 os.makedirs(target_dir)
220 full_src_pkg_path = os.path.join(package_dir, upload_target)
221 full_target_src_path = os.path.join(
222 input_proto.uploads_dir, upload_target
223 )
224 shutil.copyfile(full_src_pkg_path, full_target_src_path)
225 output_proto.upload_targets.add().path = upload_target
226 output_proto.upload_targets.add().path = "Packages"
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600227
Alex Klein076841b2019-08-29 15:19:39 -0600228
Michael Mortensen42251f92019-11-14 11:01:43 -0700229def _SetBinhostResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600230 """Add fake binhost file to a successful response."""
231 output_proto.output_file = "/path/to/BINHOST.conf"
Michael Mortensen42251f92019-11-14 11:01:43 -0700232
233
234@faux.success(_SetBinhostResponse)
235@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600236@validate.require("build_target.name", "key", "uri")
Alex Klein231d2da2019-07-22 16:44:45 -0600237@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600238def SetBinhost(
239 input_proto: binhost_pb2.SetBinhostRequest,
240 output_proto: binhost_pb2.SetBinhostResponse,
241 _config: "api_config.ApiConfig",
242):
243 """Set the URI for a given binhost key and build target.
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600244
Alex Klein1699fab2022-09-08 08:46:06 -0600245 See BinhostService documentation in api/proto/binhost.proto.
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600246
Alex Klein1699fab2022-09-08 08:46:06 -0600247 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600248 input_proto: The input proto.
249 output_proto: The output proto.
250 _config: The API call config.
Alex Klein1699fab2022-09-08 08:46:06 -0600251 """
252 target = input_proto.build_target.name
253 key = binhost_pb2.BinhostKey.Name(input_proto.key)
254 uri = input_proto.uri
255 private = input_proto.private
Arif Kasim6242cdd2022-10-19 17:51:00 +0000256 max_uris = input_proto.max_uris or _DEFAULT_BINHOST_MAX_URIS
Alex Klein6fb0eb82019-05-20 16:16:14 -0600257
Alex Klein1699fab2022-09-08 08:46:06 -0600258 output_proto.output_file = binhost.SetBinhost(
Arif Kasim6242cdd2022-10-19 17:51:00 +0000259 target, key, uri, private=private, max_uris=max_uris
Alex Klein1699fab2022-09-08 08:46:06 -0600260 )
LaMont Jonesc64ae212019-04-15 15:41:28 -0600261
LaMont Jonesc64ae212019-04-15 15:41:28 -0600262
Michael Mortensen42251f92019-11-14 11:01:43 -0700263def _RegenBuildCacheResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600264 """Add fake binhosts cache path to a successful response."""
265 output_proto.modified_overlays.add().path = "/path/to/BuildCache"
Michael Mortensen42251f92019-11-14 11:01:43 -0700266
267
268@faux.success(_RegenBuildCacheResponse)
269@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600270@validate.require("overlay_type")
271@validate.is_in("overlay_type", _OVERLAY_TYPE_TO_NAME)
Alex Klein231d2da2019-07-22 16:44:45 -0600272@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600273def RegenBuildCache(
274 input_proto: binhost_pb2.RegenBuildCacheRequest,
275 output_proto: binhost_pb2.RegenBuildCacheResponse,
276 _config: "api_config.ApiConfig",
277):
278 """Regenerate the Build Cache for a build target.
LaMont Jonesc64ae212019-04-15 15:41:28 -0600279
Alex Klein1699fab2022-09-08 08:46:06 -0600280 See BinhostService documentation in api/proto/binhost.proto.
LaMont Jonesc64ae212019-04-15 15:41:28 -0600281
Alex Klein1699fab2022-09-08 08:46:06 -0600282 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600283 input_proto: The input proto.
284 output_proto: The output proto.
285 _config: The API call config.
Alex Klein1699fab2022-09-08 08:46:06 -0600286 """
287 chroot = controller_util.ParseChroot(input_proto.chroot)
288 overlay_type = input_proto.overlay_type
289 overlays = binhost.RegenBuildCache(
290 chroot, _OVERLAY_TYPE_TO_NAME[overlay_type]
291 )
Alex Klein82c85d42019-08-14 15:47:51 -0600292
Alex Klein1699fab2022-09-08 08:46:06 -0600293 for overlay in overlays:
294 output_proto.modified_overlays.add().path = overlay