blob: 652eee63215346e59d703b022fdeed413659a882 [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
Mike Frysingere852b072021-05-21 12:39:03 -04009import urllib.parse
Evan Hernandezd437b4e2019-03-25 13:48:30 -060010
Alex Klein231d2da2019-07-22 16:44:45 -060011from chromite.api import controller
Alex Klein076841b2019-08-29 15:19:39 -060012from chromite.api import faux
Alex Klein2b236722019-06-19 15:44:26 -060013from chromite.api import validate
Alex Kleinaf0e0452019-06-03 18:10:01 -060014from chromite.api.controller import controller_util
Evan Hernandezd437b4e2019-03-25 13:48:30 -060015from chromite.api.gen.chromite.api import binhost_pb2
LaMont Jonesc64ae212019-04-15 15:41:28 -060016from chromite.lib import constants
17from chromite.lib import cros_build_lib
Evan Hernandezd437b4e2019-03-25 13:48:30 -060018from chromite.lib import gs
Alex Kleinaf0e0452019-06-03 18:10:01 -060019from chromite.lib import sysroot_lib
Evan Hernandezd437b4e2019-03-25 13:48:30 -060020from chromite.service import binhost
21
Mike Frysingeref94e4c2020-02-10 23:59:54 -050022
Alex Kleinaf0e0452019-06-03 18:10:01 -060023_OVERLAY_TYPE_TO_NAME = {
24 binhost_pb2.OVERLAYTYPE_PUBLIC: constants.PUBLIC_OVERLAYS,
25 binhost_pb2.OVERLAYTYPE_PRIVATE: constants.PRIVATE_OVERLAYS,
26 binhost_pb2.OVERLAYTYPE_BOTH: constants.BOTH_OVERLAYS,
27 binhost_pb2.OVERLAYTYPE_NONE: None
28}
29
Evan Hernandezd437b4e2019-03-25 13:48:30 -060030
Michael Mortensena0af77b2019-11-13 11:15:15 -070031def _GetBinhostsResponse(_input_proto, output_proto, _config):
32 """Add fake binhosts to a successful response."""
33 new_binhost = output_proto.binhosts.add()
34 new_binhost.uri = ('gs://cr-prebuilt/board/amd64-generic/'
35 'paladin-R66-17.0.0-rc2/packages/')
36 new_binhost.package_index = 'Packages'
37
38
39@faux.success(_GetBinhostsResponse)
40@faux.empty_error
Alex Klein2b236722019-06-19 15:44:26 -060041@validate.require('build_target.name')
Alex Klein231d2da2019-07-22 16:44:45 -060042@validate.validation_complete
43def GetBinhosts(input_proto, output_proto, _config):
Alex Klein7e40d252019-06-10 09:01:32 -060044 """Get a list of binhosts."""
Alex Klein2960c752020-03-09 13:43:38 -060045 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
Alex Klein7e40d252019-06-10 09:01:32 -060046
47 binhosts = binhost.GetBinhosts(build_target)
48
49 for current in binhosts:
50 new_binhost = output_proto.binhosts.add()
51 new_binhost.uri = current
Alex Kleind3ac0bd2019-06-10 15:17:51 -060052 new_binhost.package_index = 'Packages'
Alex Klein7e40d252019-06-10 09:01:32 -060053
54
Michael Mortensen42251f92019-11-14 11:01:43 -070055def _GetPrivatePrebuiltAclArgsResponse(_input_proto, output_proto, _config):
56 """Add fake acls to a successful response."""
57 new_arg = output_proto.args.add()
58 new_arg.arg = '-g'
59 new_arg.value = 'group1:READ'
60
61
62@faux.success(_GetPrivatePrebuiltAclArgsResponse)
63@faux.empty_error
Alex Klein2b236722019-06-19 15:44:26 -060064@validate.require('build_target.name')
Alex Klein231d2da2019-07-22 16:44:45 -060065@validate.validation_complete
66def GetPrivatePrebuiltAclArgs(input_proto, output_proto, _config):
Alex Kleina471f682019-05-31 11:23:45 -060067 """Get the ACL args from the files in the private overlays."""
Alex Klein2960c752020-03-09 13:43:38 -060068 build_target = controller_util.ParseBuildTarget(input_proto.build_target)
Alex Kleina471f682019-05-31 11:23:45 -060069
70 try:
71 args = binhost.GetPrebuiltAclArgs(build_target)
72 except binhost.Error as e:
Mike Frysinger6b5c3cd2019-08-27 16:51:00 -040073 cros_build_lib.Die(e)
Alex Kleina471f682019-05-31 11:23:45 -060074
75 for arg, value in args:
76 new_arg = output_proto.args.add()
77 new_arg.arg = arg
78 new_arg.value = value
79
80
Michael Mortensen42251f92019-11-14 11:01:43 -070081def _PrepareBinhostUploadsResponse(_input_proto, output_proto, _config):
82 """Add fake binhost upload targets to a successful response."""
83 output_proto.uploads_dir = '/upload/directory'
84 output_proto.upload_targets.add().path = 'upload_target'
85
86
87@faux.success(_PrepareBinhostUploadsResponse)
88@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -060089@validate.require('uri')
90def PrepareBinhostUploads(input_proto, output_proto, config):
Michael Mortensen42251f92019-11-14 11:01:43 -070091 """Return a list of files to upload to the binhost.
Evan Hernandezd437b4e2019-03-25 13:48:30 -060092
93 See BinhostService documentation in api/proto/binhost.proto.
94
95 Args:
96 input_proto (PrepareBinhostUploadsRequest): The input proto.
97 output_proto (PrepareBinhostUploadsResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -060098 config (api_config.ApiConfig): The API call config.
Evan Hernandezd437b4e2019-03-25 13:48:30 -060099 """
Alex Klein2960c752020-03-09 13:43:38 -0600100 if input_proto.sysroot.build_target.name:
101 build_target_msg = input_proto.sysroot.build_target
102 else:
103 build_target_msg = input_proto.build_target
Alex Kleinaf0e0452019-06-03 18:10:01 -0600104 sysroot_path = input_proto.sysroot.path
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600105
Alex Klein2960c752020-03-09 13:43:38 -0600106 if not sysroot_path and not build_target_msg.name:
Alex Kleinaf0e0452019-06-03 18:10:01 -0600107 cros_build_lib.Die('Sysroot.path is required.')
108
Alex Klein2960c752020-03-09 13:43:38 -0600109 build_target = controller_util.ParseBuildTarget(build_target_msg)
Alex Kleinaf0e0452019-06-03 18:10:01 -0600110 chroot = controller_util.ParseChroot(input_proto.chroot)
111
112 if not sysroot_path:
Alex Kleinaf0e0452019-06-03 18:10:01 -0600113 sysroot_path = build_target.root
114 sysroot = sysroot_lib.Sysroot(sysroot_path)
115
116 uri = input_proto.uri
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600117 # For now, we enforce that all input URIs are Google Storage buckets.
118 if not gs.PathIsGs(uri):
119 raise ValueError('Upload URI %s must be Google Storage.' % uri)
120
Alex Klein231d2da2019-07-22 16:44:45 -0600121 if config.validate_only:
122 return controller.RETURN_CODE_VALID_INPUT
123
Mike Frysinger3dcacee2019-08-23 17:09:11 -0400124 parsed_uri = urllib.parse.urlparse(uri)
Alex Klein8dffea42019-06-14 14:01:36 -0600125 upload_uri = gs.GetGsURL(parsed_uri.netloc, for_gsutil=True).rstrip('/')
Alex Klein3e728442019-05-15 11:46:57 -0600126 upload_path = parsed_uri.path.lstrip('/')
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600127
128 # Read all packages and update the index. The index must be uploaded to the
129 # binhost for Portage to use it, so include it in upload_targets.
Alex Kleinaf0e0452019-06-03 18:10:01 -0600130 uploads_dir = binhost.GetPrebuiltsRoot(chroot, sysroot, build_target)
Alex Klein3e728442019-05-15 11:46:57 -0600131 index_path = binhost.UpdatePackageIndex(uploads_dir, upload_uri, upload_path,
132 sudo=True)
Alex Kleinb5d57a62019-06-20 12:04:53 -0600133 upload_targets = binhost.GetPrebuiltsFiles(uploads_dir)
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600134 assert index_path.startswith(uploads_dir), (
135 'expected index_path to start with uploads_dir')
136 upload_targets.append(index_path[len(uploads_dir):])
137
138 output_proto.uploads_dir = uploads_dir
139 for upload_target in upload_targets:
140 output_proto.upload_targets.add().path = upload_target.strip('/')
141
Alex Klein076841b2019-08-29 15:19:39 -0600142
Michael Mortensen42251f92019-11-14 11:01:43 -0700143def _PrepareDevInstallBinhostUploadsResponse(_input_proto, output_proto,
144 _config):
145 """Add fake binhost files to a successful response."""
146 output_proto.upload_targets.add().path = 'app-arch/zip-3.0-r3.tbz2'
147 output_proto.upload_targets.add().path = 'virtual/python-enum34-1.tbz2'
148 output_proto.upload_targets.add().path = 'Packages'
149
150
151@faux.success(_PrepareDevInstallBinhostUploadsResponse)
152@faux.empty_error
Michael Mortensenfc823882019-08-27 14:38:07 -0600153@validate.require('uri', 'sysroot.path')
154@validate.exists('uploads_dir')
155def PrepareDevInstallBinhostUploads(input_proto, output_proto, config):
156 """Return a list of files to upload to the binhost"
157
158 The files will also be copied to the uploads_dir.
159 See BinhostService documentation in api/proto/binhost.proto.
160
161 Args:
162 input_proto (PrepareDevInstallBinhostUploadsRequest): The input proto.
163 output_proto (PrepareDevInstallBinhostUploadsResponse): The output proto.
164 config (api_config.ApiConfig): The API call config.
165 """
166 sysroot_path = input_proto.sysroot.path
167
Michael Mortensenfc823882019-08-27 14:38:07 -0600168 chroot = controller_util.ParseChroot(input_proto.chroot)
169 sysroot = sysroot_lib.Sysroot(sysroot_path)
170
171 uri = input_proto.uri
172 # For now, we enforce that all input URIs are Google Storage buckets.
173 if not gs.PathIsGs(uri):
174 raise ValueError('Upload URI %s must be Google Storage.' % uri)
175
176 if config.validate_only:
177 return controller.RETURN_CODE_VALID_INPUT
178
Mike Frysinger3dcacee2019-08-23 17:09:11 -0400179 parsed_uri = urllib.parse.urlparse(uri)
Michael Mortensenfc823882019-08-27 14:38:07 -0600180 upload_uri = gs.GetGsURL(parsed_uri.netloc, for_gsutil=True).rstrip('/')
181 upload_path = parsed_uri.path.lstrip('/')
182
183 # Calculate the filename for the to-be-created Packages file, which will
184 # contain only devinstall packages.
185 devinstall_package_index_path = os.path.join(input_proto.uploads_dir,
186 'Packages')
187 upload_targets_list = binhost.ReadDevInstallFilesToCreatePackageIndex(
188 chroot, sysroot, devinstall_package_index_path, upload_uri, upload_path)
189
190 package_dir = chroot.full_path(sysroot.path, 'packages')
191 for upload_target in upload_targets_list:
192 # Copy each package to target/category/package
193 upload_target = upload_target.strip('/')
194 category = upload_target.split(os.sep)[0]
195 target_dir = os.path.join(input_proto.uploads_dir, category)
196 if not os.path.exists(target_dir):
197 os.makedirs(target_dir)
198 full_src_pkg_path = os.path.join(package_dir, upload_target)
199 full_target_src_path = os.path.join(input_proto.uploads_dir, upload_target)
200 shutil.copyfile(full_src_pkg_path, full_target_src_path)
201 output_proto.upload_targets.add().path = upload_target
202 output_proto.upload_targets.add().path = 'Packages'
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600203
Alex Klein076841b2019-08-29 15:19:39 -0600204
Michael Mortensen42251f92019-11-14 11:01:43 -0700205def _SetBinhostResponse(_input_proto, output_proto, _config):
206 """Add fake binhost file to a successful response."""
207 output_proto.output_file = '/path/to/BINHOST.conf'
208
209
210@faux.success(_SetBinhostResponse)
211@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600212@validate.require('build_target.name', 'key', 'uri')
213@validate.validation_complete
214def SetBinhost(input_proto, output_proto, _config):
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600215 """Set the URI for a given binhost key and build target.
216
217 See BinhostService documentation in api/proto/binhost.proto.
218
219 Args:
220 input_proto (SetBinhostRequest): The input proto.
221 output_proto (SetBinhostResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600222 _config (api_config.ApiConfig): The API call config.
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600223 """
224 target = input_proto.build_target.name
225 key = binhost_pb2.BinhostKey.Name(input_proto.key)
226 uri = input_proto.uri
227 private = input_proto.private
Alex Klein6fb0eb82019-05-20 16:16:14 -0600228
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600229 output_proto.output_file = binhost.SetBinhost(target, key, uri,
230 private=private)
LaMont Jonesc64ae212019-04-15 15:41:28 -0600231
LaMont Jonesc64ae212019-04-15 15:41:28 -0600232
Michael Mortensen42251f92019-11-14 11:01:43 -0700233def _RegenBuildCacheResponse(_input_proto, output_proto, _config):
234 """Add fake binhosts cache path to a successful response."""
235 output_proto.modified_overlays.add().path = '/path/to/BuildCache'
236
237
238@faux.success(_RegenBuildCacheResponse)
239@faux.empty_error
Alex Klein231d2da2019-07-22 16:44:45 -0600240@validate.require('overlay_type')
241@validate.is_in('overlay_type', _OVERLAY_TYPE_TO_NAME)
242@validate.validation_complete
Alex Klein82c85d42019-08-14 15:47:51 -0600243def RegenBuildCache(input_proto, output_proto, _config):
LaMont Jonesc64ae212019-04-15 15:41:28 -0600244 """Regenerate the Build Cache for a build target.
245
246 See BinhostService documentation in api/proto/binhost.proto.
247
248 Args:
249 input_proto (RegenBuildCacheRequest): The input proto.
Alex Klein82c85d42019-08-14 15:47:51 -0600250 output_proto (RegenBuildCacheResponse): The output proto.
Alex Klein231d2da2019-07-22 16:44:45 -0600251 _config (api_config.ApiConfig): The API call config.
LaMont Jonesc64ae212019-04-15 15:41:28 -0600252 """
Alex Klein82c85d42019-08-14 15:47:51 -0600253 chroot = controller_util.ParseChroot(input_proto.chroot)
LaMont Jonesc64ae212019-04-15 15:41:28 -0600254 overlay_type = input_proto.overlay_type
Alex Klein82c85d42019-08-14 15:47:51 -0600255 overlays = binhost.RegenBuildCache(chroot,
256 _OVERLAY_TYPE_TO_NAME[overlay_type])
257
258 for overlay in overlays:
259 output_proto.modified_overlays.add().path = overlay