blob: 8702c47a2d2d601713b8d71491ca32c02f016774 [file] [log] [blame]
Evan Hernandezd437b4e2019-03-25 13:48:30 -06001# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# 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
Evan Hernandezd437b4e2019-03-25 13:48:30 -060034
Michael Mortensena0af77b2019-11-13 11:15:15 -070035def _GetBinhostsResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -060036 """Add fake binhosts to a successful response."""
37 new_binhost = output_proto.binhosts.add()
38 new_binhost.uri = (
39 "gs://cr-prebuilt/board/amd64-generic/"
40 "paladin-R66-17.0.0-rc2/packages/"
41 )
42 new_binhost.package_index = "Packages"
Michael Mortensena0af77b2019-11-13 11:15:15 -070043
44
45@faux.success(_GetBinhostsResponse)
46@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -060047@validate.require("build_target.name")
Alex Klein231d2da2019-07-22 16:44:45 -060048@validate.validation_complete
49def GetBinhosts(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -060050 """Get a list of binhosts."""
51 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
Alex Klein7e40d252019-06-10 09:01:32 -060052
Alex Klein1699fab2022-09-08 08:46:06 -060053 binhosts = binhost.GetBinhosts(build_target)
Alex Klein7e40d252019-06-10 09:01:32 -060054
Alex Klein1699fab2022-09-08 08:46:06 -060055 for current in binhosts:
56 new_binhost = output_proto.binhosts.add()
57 new_binhost.uri = current
58 new_binhost.package_index = "Packages"
Alex Klein7e40d252019-06-10 09:01:32 -060059
60
Michael Mortensen42251f92019-11-14 11:01:43 -070061def _GetPrivatePrebuiltAclArgsResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -060062 """Add fake acls to a successful response."""
63 new_arg = output_proto.args.add()
64 new_arg.arg = "-g"
65 new_arg.value = "group1:READ"
Michael Mortensen42251f92019-11-14 11:01:43 -070066
67
68@faux.success(_GetPrivatePrebuiltAclArgsResponse)
69@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -060070@validate.require("build_target.name")
Alex Klein231d2da2019-07-22 16:44:45 -060071@validate.validation_complete
72def GetPrivatePrebuiltAclArgs(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -060073 """Get the ACL args from the files in the private overlays."""
74 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
Alex Kleina471f682019-05-31 11:23:45 -060075
Alex Klein1699fab2022-09-08 08:46:06 -060076 try:
77 args = binhost.GetPrebuiltAclArgs(build_target)
78 except binhost.Error as e:
79 cros_build_lib.Die(e)
Alex Kleina471f682019-05-31 11:23:45 -060080
Alex Klein1699fab2022-09-08 08:46:06 -060081 for arg, value in args:
82 new_arg = output_proto.args.add()
83 new_arg.arg = arg
84 new_arg.value = value
Alex Kleina471f682019-05-31 11:23:45 -060085
86
Michael Mortensen42251f92019-11-14 11:01:43 -070087def _PrepareBinhostUploadsResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -060088 """Add fake binhost upload targets to a successful response."""
89 output_proto.uploads_dir = "/upload/directory"
90 output_proto.upload_targets.add().path = "upload_target"
Michael Mortensen42251f92019-11-14 11:01:43 -070091
92
93@faux.success(_PrepareBinhostUploadsResponse)
94@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -060095@validate.require("uri")
Kevin Shelton703b6882022-01-24 16:31:31 -080096def PrepareBinhostUploads(
97 input_proto: binhost_pb2.PrepareBinhostUploadsRequest,
98 output_proto: binhost_pb2.PrepareBinhostUploadsResponse,
Alex Klein1699fab2022-09-08 08:46:06 -060099 config: "api_config.ApiConfig",
100):
101 """Return a list of files to upload to the binhost.
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600102
Alex Klein1699fab2022-09-08 08:46:06 -0600103 See BinhostService documentation in api/proto/binhost.proto.
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600104
Alex Klein1699fab2022-09-08 08:46:06 -0600105 Args:
106 input_proto: The input proto.
107 output_proto: The output proto.
108 config: The API call config.
109 """
110 if input_proto.sysroot.build_target.name:
111 build_target_msg = input_proto.sysroot.build_target
112 else:
113 build_target_msg = input_proto.build_target
114 sysroot_path = input_proto.sysroot.path
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600115
Alex Klein1699fab2022-09-08 08:46:06 -0600116 if not sysroot_path and not build_target_msg.name:
117 cros_build_lib.Die("Sysroot.path is required.")
Alex Kleinaf0e0452019-06-03 18:10:01 -0600118
Alex Klein1699fab2022-09-08 08:46:06 -0600119 build_target = controller_util.ParseBuildTarget(build_target_msg)
120 chroot = controller_util.ParseChroot(input_proto.chroot)
Alex Kleinaf0e0452019-06-03 18:10:01 -0600121
Alex Klein1699fab2022-09-08 08:46:06 -0600122 if not sysroot_path:
123 sysroot_path = build_target.root
124 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Kleinaf0e0452019-06-03 18:10:01 -0600125
Alex Klein1699fab2022-09-08 08:46:06 -0600126 uri = input_proto.uri
127 # For now, we enforce that all input URIs are Google Storage buckets.
128 if not gs.PathIsGs(uri):
129 raise ValueError("Upload URI %s must be Google Storage." % uri)
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600130
Alex Klein1699fab2022-09-08 08:46:06 -0600131 if config.validate_only:
132 return controller.RETURN_CODE_VALID_INPUT
Alex Klein231d2da2019-07-22 16:44:45 -0600133
Alex Klein1699fab2022-09-08 08:46:06 -0600134 parsed_uri = urllib.parse.urlparse(uri)
135 upload_uri = gs.GetGsURL(parsed_uri.netloc, for_gsutil=True).rstrip("/")
136 upload_path = parsed_uri.path.lstrip("/")
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600137
Alex Klein1699fab2022-09-08 08:46:06 -0600138 # Read all packages and update the index. The index must be uploaded to the
139 # binhost for Portage to use it, so include it in upload_targets.
140 uploads_dir = binhost.GetPrebuiltsRoot(chroot, sysroot, build_target)
141 index_path = binhost.UpdatePackageIndex(
142 uploads_dir, upload_uri, upload_path, sudo=True
143 )
144 upload_targets = binhost.GetPrebuiltsFiles(uploads_dir)
145 assert index_path.startswith(
146 uploads_dir
147 ), "expected index_path to start with uploads_dir"
148 upload_targets.append(index_path[len(uploads_dir) :])
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600149
Alex Klein1699fab2022-09-08 08:46:06 -0600150 output_proto.uploads_dir = uploads_dir
151 for upload_target in upload_targets:
152 output_proto.upload_targets.add().path = upload_target.strip("/")
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600153
Alex Klein076841b2019-08-29 15:19:39 -0600154
Alex Klein1699fab2022-09-08 08:46:06 -0600155def _PrepareDevInstallBinhostUploadsResponse(
156 _input_proto, output_proto, _config
157):
158 """Add fake binhost files to a successful response."""
159 output_proto.upload_targets.add().path = "app-arch/zip-3.0-r3.tbz2"
160 output_proto.upload_targets.add().path = "virtual/python-enum34-1.tbz2"
161 output_proto.upload_targets.add().path = "Packages"
Michael Mortensen42251f92019-11-14 11:01:43 -0700162
163
164@faux.success(_PrepareDevInstallBinhostUploadsResponse)
165@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600166@validate.require("uri", "sysroot.path")
167@validate.exists("uploads_dir")
Kevin Shelton703b6882022-01-24 16:31:31 -0800168def PrepareDevInstallBinhostUploads(
169 input_proto: binhost_pb2.PrepareDevInstallBinhostUploadsRequest,
170 output_proto: binhost_pb2.PrepareDevInstallBinhostUploadsResponse,
Alex Klein1699fab2022-09-08 08:46:06 -0600171 config: "api_config.ApiConfig",
172):
173 """Return a list of files to upload to the binhost"
Michael Mortensenfc823882019-08-27 14:38:07 -0600174
Alex Klein1699fab2022-09-08 08:46:06 -0600175 The files will also be copied to the uploads_dir.
176 See BinhostService documentation in api/proto/binhost.proto.
Michael Mortensenfc823882019-08-27 14:38:07 -0600177
Alex Klein1699fab2022-09-08 08:46:06 -0600178 Args:
179 input_proto: The input proto.
180 output_proto: The output proto.
181 config: The API call config.
182 """
183 sysroot_path = input_proto.sysroot.path
Michael Mortensenfc823882019-08-27 14:38:07 -0600184
Alex Klein1699fab2022-09-08 08:46:06 -0600185 chroot = controller_util.ParseChroot(input_proto.chroot)
186 sysroot = sysroot_lib.Sysroot(sysroot_path)
Michael Mortensenfc823882019-08-27 14:38:07 -0600187
Alex Klein1699fab2022-09-08 08:46:06 -0600188 uri = input_proto.uri
189 # For now, we enforce that all input URIs are Google Storage buckets.
190 if not gs.PathIsGs(uri):
191 raise ValueError("Upload URI %s must be Google Storage." % uri)
Michael Mortensenfc823882019-08-27 14:38:07 -0600192
Alex Klein1699fab2022-09-08 08:46:06 -0600193 if config.validate_only:
194 return controller.RETURN_CODE_VALID_INPUT
Michael Mortensenfc823882019-08-27 14:38:07 -0600195
Alex Klein1699fab2022-09-08 08:46:06 -0600196 parsed_uri = urllib.parse.urlparse(uri)
197 upload_uri = gs.GetGsURL(parsed_uri.netloc, for_gsutil=True).rstrip("/")
198 upload_path = parsed_uri.path.lstrip("/")
Michael Mortensenfc823882019-08-27 14:38:07 -0600199
Alex Klein1699fab2022-09-08 08:46:06 -0600200 # Calculate the filename for the to-be-created Packages file, which will
201 # contain only devinstall packages.
202 devinstall_package_index_path = os.path.join(
203 input_proto.uploads_dir, "Packages"
204 )
205 upload_targets_list = binhost.ReadDevInstallFilesToCreatePackageIndex(
206 chroot, sysroot, devinstall_package_index_path, upload_uri, upload_path
207 )
Michael Mortensenfc823882019-08-27 14:38:07 -0600208
Alex Klein1699fab2022-09-08 08:46:06 -0600209 package_dir = chroot.full_path(sysroot.path, "packages")
210 for upload_target in upload_targets_list:
211 # Copy each package to target/category/package
212 upload_target = upload_target.strip("/")
213 category = upload_target.split(os.sep)[0]
214 target_dir = os.path.join(input_proto.uploads_dir, category)
215 if not os.path.exists(target_dir):
216 os.makedirs(target_dir)
217 full_src_pkg_path = os.path.join(package_dir, upload_target)
218 full_target_src_path = os.path.join(
219 input_proto.uploads_dir, upload_target
220 )
221 shutil.copyfile(full_src_pkg_path, full_target_src_path)
222 output_proto.upload_targets.add().path = upload_target
223 output_proto.upload_targets.add().path = "Packages"
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600224
Alex Klein076841b2019-08-29 15:19:39 -0600225
Michael Mortensen42251f92019-11-14 11:01:43 -0700226def _SetBinhostResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600227 """Add fake binhost file to a successful response."""
228 output_proto.output_file = "/path/to/BINHOST.conf"
Michael Mortensen42251f92019-11-14 11:01:43 -0700229
230
231@faux.success(_SetBinhostResponse)
232@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600233@validate.require("build_target.name", "key", "uri")
Alex Klein231d2da2019-07-22 16:44:45 -0600234@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600235def SetBinhost(
236 input_proto: binhost_pb2.SetBinhostRequest,
237 output_proto: binhost_pb2.SetBinhostResponse,
238 _config: "api_config.ApiConfig",
239):
240 """Set the URI for a given binhost key and build target.
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600241
Alex Klein1699fab2022-09-08 08:46:06 -0600242 See BinhostService documentation in api/proto/binhost.proto.
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600243
Alex Klein1699fab2022-09-08 08:46:06 -0600244 Args:
245 input_proto: The input proto.
246 output_proto: The output proto.
247 _config: The API call config.
248 """
249 target = input_proto.build_target.name
250 key = binhost_pb2.BinhostKey.Name(input_proto.key)
251 uri = input_proto.uri
252 private = input_proto.private
Alex Klein6fb0eb82019-05-20 16:16:14 -0600253
Alex Klein1699fab2022-09-08 08:46:06 -0600254 output_proto.output_file = binhost.SetBinhost(
255 target, key, uri, private=private
256 )
LaMont Jonesc64ae212019-04-15 15:41:28 -0600257
LaMont Jonesc64ae212019-04-15 15:41:28 -0600258
Michael Mortensen42251f92019-11-14 11:01:43 -0700259def _RegenBuildCacheResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600260 """Add fake binhosts cache path to a successful response."""
261 output_proto.modified_overlays.add().path = "/path/to/BuildCache"
Michael Mortensen42251f92019-11-14 11:01:43 -0700262
263
264@faux.success(_RegenBuildCacheResponse)
265@faux.empty_error
Alex Klein1699fab2022-09-08 08:46:06 -0600266@validate.require("overlay_type")
267@validate.is_in("overlay_type", _OVERLAY_TYPE_TO_NAME)
Alex Klein231d2da2019-07-22 16:44:45 -0600268@validate.validation_complete
Alex Klein1699fab2022-09-08 08:46:06 -0600269def RegenBuildCache(
270 input_proto: binhost_pb2.RegenBuildCacheRequest,
271 output_proto: binhost_pb2.RegenBuildCacheResponse,
272 _config: "api_config.ApiConfig",
273):
274 """Regenerate the Build Cache for a build target.
LaMont Jonesc64ae212019-04-15 15:41:28 -0600275
Alex Klein1699fab2022-09-08 08:46:06 -0600276 See BinhostService documentation in api/proto/binhost.proto.
LaMont Jonesc64ae212019-04-15 15:41:28 -0600277
Alex Klein1699fab2022-09-08 08:46:06 -0600278 Args:
279 input_proto: The input proto.
280 output_proto: The output proto.
281 _config: The API call config.
282 """
283 chroot = controller_util.ParseChroot(input_proto.chroot)
284 overlay_type = input_proto.overlay_type
285 overlays = binhost.RegenBuildCache(
286 chroot, _OVERLAY_TYPE_TO_NAME[overlay_type]
287 )
Alex Klein82c85d42019-08-14 15:47:51 -0600288
Alex Klein1699fab2022-09-08 08:46:06 -0600289 for overlay in overlays:
290 output_proto.modified_overlays.add().path = overlay