blob: 88444cce779b52464114e08f0ba1cea984f43e8f [file] [log] [blame]
Evan Hernandezf388cbf2019-04-01 11:15:23 -06001# -*- coding: utf-8 -*-
2# Copyright 2019 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Implements ArtifactService."""
7
8from __future__ import print_function
9
Alex Kleincb541e82019-06-26 15:06:11 -060010import functools
Evan Hernandezf388cbf2019-04-01 11:15:23 -060011import os
12
Alex Klein2b236722019-06-19 15:44:26 -060013from chromite.api import validate
Alex Klein238d8862019-05-07 11:32:46 -060014from chromite.api.controller import controller_util
Evan Hernandezf388cbf2019-04-01 11:15:23 -060015from chromite.cbuildbot import commands
Alex Klein6504eca2019-04-18 15:37:56 -060016from chromite.cbuildbot.stages import vm_test_stages
Alex Klein2275d692019-04-23 16:04:12 -060017from chromite.lib import build_target_util
18from chromite.lib import chroot_lib
Evan Hernandezf388cbf2019-04-01 11:15:23 -060019from chromite.lib import constants
20from chromite.lib import cros_build_lib
Evan Hernandezde445982019-04-22 13:42:34 -060021from chromite.lib import cros_logging as logging
Alex Klein2275d692019-04-23 16:04:12 -060022from chromite.lib import sysroot_lib
23from chromite.service import artifacts
Evan Hernandezf388cbf2019-04-01 11:15:23 -060024
25
Evan Hernandez9f125ac2019-04-08 17:18:47 -060026def _GetImageDir(build_root, target):
27 """Return path containing images for the given build target.
28
Alex Kleine2612a02019-04-18 13:51:06 -060029 TODO(saklein) Expand image_lib.GetLatestImageLink to support this use case.
30
Evan Hernandez9f125ac2019-04-08 17:18:47 -060031 Args:
32 build_root (str): Path to checkout where build occurs.
33 target (str): Name of the build target.
34
35 Returns:
36 Path to the directory containing target images.
37
38 Raises:
39 DieSystemExit: If the image dir does not exist.
40 """
41 image_dir = os.path.join(build_root, 'src/build/images', target, 'latest')
42 if not os.path.exists(image_dir):
43 cros_build_lib.Die('Expected to find image output for target %s at %s, '
44 'but path does not exist' % (target, image_dir))
45 return image_dir
46
47
48def BundleImageZip(input_proto, output_proto):
49 """Bundle image.zip.
50
51 Args:
52 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -060053 output_proto (BundleResponse): The output proto.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060054 """
55 target = input_proto.build_target.name
56 output_dir = input_proto.output_dir
57 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
58 archive = commands.BuildImageZip(output_dir, image_dir)
59 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
60
61
Evan Hernandezf388cbf2019-04-01 11:15:23 -060062def BundleTestUpdatePayloads(input_proto, output_proto):
63 """Generate minimal update payloads for the build target for testing.
64
65 Args:
66 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -060067 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -060068 """
69 target = input_proto.build_target.name
70 output_dir = input_proto.output_dir
71 build_root = constants.SOURCE_ROOT
72
73 # Use the first available image to create the update payload.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060074 img_dir = _GetImageDir(build_root, target)
Alex Kleincb541e82019-06-26 15:06:11 -060075 img_types = [constants.IMAGE_TYPE_TEST, constants.IMAGE_TYPE_DEV,
76 constants.IMAGE_TYPE_BASE]
77 img_names = [constants.IMAGE_TYPE_TO_NAME[t] for t in img_types]
78 img_paths = map(functools.partial(os.path.join, img_dir), img_names)
Mike Frysingera552be42018-08-17 14:39:32 -040079 valid_images = [x for x in img_paths if os.path.exists(x)]
Evan Hernandezf388cbf2019-04-01 11:15:23 -060080
Alex Kleincb541e82019-06-26 15:06:11 -060081 if not valid_images:
Evan Hernandezf388cbf2019-04-01 11:15:23 -060082 cros_build_lib.Die(
83 'Expected to find an image of type among %r for target "%s" '
Evan Hernandez9f125ac2019-04-08 17:18:47 -060084 'at path %s.', img_types, target, img_dir)
Alex Kleincb541e82019-06-26 15:06:11 -060085 image = valid_images[0]
Evan Hernandezf388cbf2019-04-01 11:15:23 -060086
Alex Kleincb541e82019-06-26 15:06:11 -060087 payloads = artifacts.BundleTestUpdatePayloads(image, output_dir)
88 for payload in payloads:
89 output_proto.artifacts.add().path = payload
Evan Hernandezf388cbf2019-04-01 11:15:23 -060090
91
92def BundleAutotestFiles(input_proto, output_proto):
93 """Tar the autotest files for a build target.
94
95 Args:
96 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -060097 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -060098 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -060099 output_dir = input_proto.output_dir
Alex Klein238d8862019-05-07 11:32:46 -0600100 if not output_dir:
101 cros_build_lib.Die('output_dir is required.')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600102
Alex Klein238d8862019-05-07 11:32:46 -0600103 target = input_proto.build_target.name
104 if target:
105 # Legacy call, build out sysroot path from default source root and the
106 # build target.
107 target = input_proto.build_target.name
108 build_root = constants.SOURCE_ROOT
109 sysroot_path = os.path.join(build_root, constants.DEFAULT_CHROOT_DIR,
110 'build', target)
111 sysroot = sysroot_lib.Sysroot(sysroot_path)
112 else:
113 # New style call, use chroot and sysroot.
114 chroot = controller_util.ParseChroot(input_proto.chroot)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600115
Alex Klein238d8862019-05-07 11:32:46 -0600116 sysroot_path = input_proto.sysroot.path
117 if not sysroot_path:
118 cros_build_lib.Die('sysroot.path is required.')
119
120 # Since we're staying outside the chroot, prepend the chroot path to the
121 # sysroot path so we have a valid full path to the sysroot.
122 sysroot = sysroot_lib.Sysroot(os.path.join(chroot.path,
123 sysroot_path.lstrip(os.sep)))
124
125 if not sysroot.Exists():
126 cros_build_lib.Die('Sysroot path must exist: %s', sysroot.path)
127
128 try:
129 # Note that this returns the full path to *multiple* tarballs.
130 archives = artifacts.BundleAutotestFiles(sysroot, output_dir)
131 except artifacts.Error as e:
132 cros_build_lib.Die(e.message)
133
134 for archive in archives.values():
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600135 output_proto.artifacts.add().path = archive
136
137
Alex Kleinb9d810b2019-07-01 12:38:02 -0600138@validate.require('output_dir')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600139def BundleTastFiles(input_proto, output_proto):
140 """Tar the tast files for a build target.
141
142 Args:
143 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600144 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600145 """
146 target = input_proto.build_target.name
147 output_dir = input_proto.output_dir
148 build_root = constants.SOURCE_ROOT
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600149
Alex Kleinb9d810b2019-07-01 12:38:02 -0600150 chroot = controller_util.ParseChroot(input_proto.chroot)
151 sysroot_path = input_proto.sysroot.path
152
153 # TODO(saklein) Cleanup legacy handling after it has been switched over.
154 if target:
155 # Legacy handling.
156 chroot.path = os.path.join(build_root, 'chroot')
157 sysroot_path = os.path.join('/build', target)
158
159 # New handling - chroot & sysroot based.
160 # TODO(saklein) Switch this to the require decorator when legacy is removed.
161 if not sysroot_path:
162 cros_build_lib.Die('sysroot.path is required.')
163
164 sysroot = sysroot_lib.Sysroot(sysroot_path)
165 if not sysroot.Exists(chroot):
166 cros_build_lib.Die('Sysroot must exist.')
167
168 archive = artifacts.BundleTastFiles(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600169
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600170 if archive is None:
171 cros_build_lib.Die(
172 'Could not bundle Tast files. '
173 'No Tast directories found for %s.', target)
174
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600175 output_proto.artifacts.add().path = archive
176
177
178def BundlePinnedGuestImages(input_proto, output_proto):
179 """Tar the pinned guest images for a build target.
180
181 Args:
182 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600183 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600184 """
185 target = input_proto.build_target.name
186 output_dir = input_proto.output_dir
187 build_root = constants.SOURCE_ROOT
188
Alex Kleine2612a02019-04-18 13:51:06 -0600189 # TODO(crbug.com/954299): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600190 archive = commands.BuildPinnedGuestImagesTarball(build_root, target,
191 output_dir)
192
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600193 if archive is None:
Evan Hernandezde445982019-04-22 13:42:34 -0600194 logging.warning('Found no pinned guest images for %s.', target)
195 return
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600196
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600197 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
198
199
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600200def FetchPinnedGuestImages(input_proto, output_proto):
201 """Get the pinned guest image information."""
202 sysroot_path = input_proto.sysroot.path
203 if not sysroot_path:
204 cros_build_lib.Die('sysroot.path is required.')
205
206 chroot = controller_util.ParseChroot(input_proto.chroot)
207 sysroot = sysroot_lib.Sysroot(sysroot_path)
208
209 if not chroot.exists():
210 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
211
212 if not sysroot.Exists(chroot=chroot):
213 cros_build_lib.Die('Sysroot does not exist: %s',
214 chroot.full_path(sysroot.path))
215
216 pins = artifacts.FetchPinnedGuestImages(chroot, sysroot)
217
218 for pin in pins:
219 pinned_image = output_proto.pinned_images.add()
220 pinned_image.filename = pin.filename
221 pinned_image.uri = pin.uri
222
223
Michael Mortensen38675192019-06-28 16:52:55 +0000224@validate.require('output_dir', 'sysroot.path')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600225def BundleFirmware(input_proto, output_proto):
226 """Tar the firmware images for a build target.
227
228 Args:
229 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600230 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600231 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600232 output_dir = input_proto.output_dir
Michael Mortensen38675192019-06-28 16:52:55 +0000233 chroot = controller_util.ParseChroot(input_proto.chroot)
234 sysroot_path = input_proto.sysroot.path
235 sysroot = sysroot_lib.Sysroot(sysroot_path)
236 archive = artifacts.BuildFirmwareArchive(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600237
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600238 if archive is None:
239 cros_build_lib.Die(
Michael Mortensen38675192019-06-28 16:52:55 +0000240 'Could not create firmware archive. No firmware found for %s.',
241 sysroot_path)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600242
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600243 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
244
245
246def BundleEbuildLogs(input_proto, output_proto):
247 """Tar the ebuild logs for a build target.
248
249 Args:
250 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600251 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600252 """
253 target = input_proto.build_target.name
254 output_dir = input_proto.output_dir
Evan Hernandeza478d802019-04-08 15:08:24 -0600255
256 # commands.BuildEbuildLogsTarball conflates "buildroot" with sysroot.
257 # Adjust accordingly...
258 build_root = os.path.join(constants.SOURCE_ROOT, 'chroot', 'build')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600259
Alex Kleine2612a02019-04-18 13:51:06 -0600260 # TODO(crbug.com/954303): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600261 archive = commands.BuildEbuildLogsTarball(build_root, target, output_dir)
262
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600263 if archive is None:
264 cros_build_lib.Die(
265 'Could not create ebuild logs archive. No logs found for %s.', target)
266
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600267 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Klein6504eca2019-04-18 15:37:56 -0600268
269
Alex Klein2275d692019-04-23 16:04:12 -0600270def BundleSimpleChromeArtifacts(input_proto, output_proto):
271 """Create the simple chrome artifacts."""
272 # Required args.
273 sysroot_path = input_proto.sysroot.path
274 build_target_name = input_proto.sysroot.build_target.name
275 output_dir = input_proto.output_dir
276
277 if not build_target_name:
278 cros_build_lib.Die('build_target.name is required')
279 if not output_dir:
280 cros_build_lib.Die('output_dir is required.')
281 if not os.path.exists(output_dir):
282 cros_build_lib.Die('output_dir (%s) does not exist.', output_dir)
283 if not sysroot_path:
284 cros_build_lib.Die('sysroot.path is required.')
285
286 # Optional args.
287 chroot_path = input_proto.chroot.path or constants.DEFAULT_CHROOT_PATH
288 cache_dir = input_proto.chroot.cache_dir
289
290 # Build out the argument instances.
291 build_target = build_target_util.BuildTarget(build_target_name)
292 chroot = chroot_lib.Chroot(path=chroot_path, cache_dir=cache_dir)
293 # Sysroot.path needs to be the fully qualified path, including the chroot.
294 full_sysroot_path = os.path.join(chroot.path, sysroot_path.lstrip(os.sep))
295 sysroot = sysroot_lib.Sysroot(full_sysroot_path)
296
297 # Quick sanity check that the sysroot exists before we go on.
298 if not sysroot.Exists():
299 cros_build_lib.Die('The sysroot does not exist.')
300
301 try:
302 results = artifacts.BundleSimpleChromeArtifacts(chroot, sysroot,
303 build_target, output_dir)
304 except artifacts.Error as e:
305 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
306 type(e), e)
307
308 for file_name in results:
309 output_proto.artifacts.add().path = file_name
310
311
Alex Klein2b236722019-06-19 15:44:26 -0600312@validate.require('chroot.path', 'sysroot.path', 'test_results_dir',
313 'output_dir')
Alex Klein6504eca2019-04-18 15:37:56 -0600314def BundleVmFiles(input_proto, output_proto):
315 """Tar VM disk and memory files.
316
317 Args:
318 input_proto (SysrootBundleRequest): The input proto.
319 output_proto (BundleResponse): The output proto.
320 """
321 chroot = input_proto.chroot.path
Alex Klein2b236722019-06-19 15:44:26 -0600322 sysroot = input_proto.sysroot.path.lstrip(os.sep)
323 test_results_dir = input_proto.test_results_dir.lstrip(os.sep)
Alex Klein6504eca2019-04-18 15:37:56 -0600324 output_dir = input_proto.output_dir
325
Alex Klein6504eca2019-04-18 15:37:56 -0600326 # TODO(crbug.com/954344): Replace with a chromite/service implementation.
Alex Klein2b236722019-06-19 15:44:26 -0600327 image_dir = os.path.join(chroot, sysroot, test_results_dir)
Alex Klein6504eca2019-04-18 15:37:56 -0600328 archives = vm_test_stages.ArchiveVMFilesFromImageDir(image_dir, output_dir)
329 for archive in archives:
330 output_proto.artifacts.add().path = archive
Tiancong Wangc4805b72019-06-11 12:12:03 -0700331
332def BundleOrderfileGenerationArtifacts(input_proto, output_proto):
333 """Create tarballs of all the artifacts of orderfile_generate builder.
334
335 Args:
336 input_proto (BundleRequest): The input proto.
337 output_proto (BundleResponse): The output proto.
338 """
339 # Required args.
340 build_target_name = input_proto.build_target.name
341 output_dir = input_proto.output_dir
342 chrome_version = input_proto.chrome_version
343
344 if not build_target_name:
345 cros_build_lib.Die('build_target.name is required.')
346 if not chrome_version:
347 cros_build_lib.Die('chrome_version is required.')
348 if not output_dir:
349 cros_build_lib.Die('output_dir is required.')
350 elif not os.path.isdir(output_dir):
351 cros_build_lib.Die('output_dir does not exist.')
352
353 chroot = controller_util.ParseChroot(input_proto.chroot)
354
355 try:
356 results = artifacts.BundleOrderfileGenerationArtifacts(
357 chroot, input_proto.build_target, chrome_version, output_dir)
358 except artifacts.Error as e:
359 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
360 type(e), e)
361
362 for file_name in results:
363 output_proto.artifacts.add().path = file_name