blob: 3e056a10a539c90ead0c8bb7af417fe3f00a52ea [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
10import os
11
Alex Klein238d8862019-05-07 11:32:46 -060012from chromite.api.controller import controller_util
Evan Hernandezf388cbf2019-04-01 11:15:23 -060013from chromite.cbuildbot import commands
Alex Klein6504eca2019-04-18 15:37:56 -060014from chromite.cbuildbot.stages import vm_test_stages
Alex Klein2275d692019-04-23 16:04:12 -060015from chromite.lib import build_target_util
16from chromite.lib import chroot_lib
Evan Hernandezf388cbf2019-04-01 11:15:23 -060017from chromite.lib import constants
18from chromite.lib import cros_build_lib
Evan Hernandezde445982019-04-22 13:42:34 -060019from chromite.lib import cros_logging as logging
Evan Hernandezf388cbf2019-04-01 11:15:23 -060020from chromite.lib import osutils
Alex Klein2275d692019-04-23 16:04:12 -060021from chromite.lib import sysroot_lib
22from chromite.service import artifacts
Evan Hernandezf388cbf2019-04-01 11:15:23 -060023
24
Evan Hernandez9f125ac2019-04-08 17:18:47 -060025def _GetImageDir(build_root, target):
26 """Return path containing images for the given build target.
27
Alex Kleine2612a02019-04-18 13:51:06 -060028 TODO(saklein) Expand image_lib.GetLatestImageLink to support this use case.
29
Evan Hernandez9f125ac2019-04-08 17:18:47 -060030 Args:
31 build_root (str): Path to checkout where build occurs.
32 target (str): Name of the build target.
33
34 Returns:
35 Path to the directory containing target images.
36
37 Raises:
38 DieSystemExit: If the image dir does not exist.
39 """
40 image_dir = os.path.join(build_root, 'src/build/images', target, 'latest')
41 if not os.path.exists(image_dir):
42 cros_build_lib.Die('Expected to find image output for target %s at %s, '
43 'but path does not exist' % (target, image_dir))
44 return image_dir
45
46
47def BundleImageZip(input_proto, output_proto):
48 """Bundle image.zip.
49
50 Args:
51 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -060052 output_proto (BundleResponse): The output proto.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060053 """
54 target = input_proto.build_target.name
55 output_dir = input_proto.output_dir
56 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
57 archive = commands.BuildImageZip(output_dir, image_dir)
58 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
59
60
Evan Hernandezf388cbf2019-04-01 11:15:23 -060061def BundleTestUpdatePayloads(input_proto, output_proto):
62 """Generate minimal update payloads for the build target for testing.
63
64 Args:
65 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -060066 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -060067 """
68 target = input_proto.build_target.name
69 output_dir = input_proto.output_dir
70 build_root = constants.SOURCE_ROOT
71
72 # Use the first available image to create the update payload.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060073 img_dir = _GetImageDir(build_root, target)
Evan Hernandezf388cbf2019-04-01 11:15:23 -060074 img_types = [
75 constants.IMAGE_TYPE_TEST, constants.IMAGE_TYPE_DEV,
76 constants.IMAGE_TYPE_BASE
77 ]
78 img_paths = []
79 for img_type in img_types:
Evan Hernandez9f125ac2019-04-08 17:18:47 -060080 img_path = os.path.join(img_dir, constants.IMAGE_TYPE_TO_NAME[img_type])
Evan Hernandezf388cbf2019-04-01 11:15:23 -060081 if os.path.exists(img_path):
82 img_paths.append(img_path)
83
84 if not img_paths:
85 cros_build_lib.Die(
86 'Expected to find an image of type among %r for target "%s" '
Evan Hernandez9f125ac2019-04-08 17:18:47 -060087 'at path %s.', img_types, target, img_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -060088 img = img_paths[0]
89
90 # Unfortunately, the relevant commands.py functions do not return
91 # a list of generated files. As a workaround, we have commands.py
92 # put the files in a separate temporary directory so we can catalog them,
93 # then move them to the output dir.
Alex Kleine2612a02019-04-18 13:51:06 -060094 # TODO(crbug.com/954283): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -060095 with osutils.TempDir() as temp:
96 commands.GeneratePayloads(img, temp, full=True, stateful=True, delta=True)
97 commands.GenerateQuickProvisionPayloads(img, temp)
98 for path in osutils.DirectoryIterator(temp):
99 if os.path.isfile(path):
100 rel_path = os.path.relpath(path, temp)
101 output_proto.artifacts.add().path = os.path.join(output_dir, rel_path)
Evan Hernandezb04e2aa2019-04-08 16:55:54 -0600102 osutils.CopyDirContents(temp, output_dir, allow_nonempty=True)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600103
104
105def BundleAutotestFiles(input_proto, output_proto):
106 """Tar the autotest files for a build target.
107
108 Args:
109 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600110 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600111 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600112 output_dir = input_proto.output_dir
Alex Klein238d8862019-05-07 11:32:46 -0600113 if not output_dir:
114 cros_build_lib.Die('output_dir is required.')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600115
Alex Klein238d8862019-05-07 11:32:46 -0600116 target = input_proto.build_target.name
117 if target:
118 # Legacy call, build out sysroot path from default source root and the
119 # build target.
120 target = input_proto.build_target.name
121 build_root = constants.SOURCE_ROOT
122 sysroot_path = os.path.join(build_root, constants.DEFAULT_CHROOT_DIR,
123 'build', target)
124 sysroot = sysroot_lib.Sysroot(sysroot_path)
125 else:
126 # New style call, use chroot and sysroot.
127 chroot = controller_util.ParseChroot(input_proto.chroot)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600128
Alex Klein238d8862019-05-07 11:32:46 -0600129 sysroot_path = input_proto.sysroot.path
130 if not sysroot_path:
131 cros_build_lib.Die('sysroot.path is required.')
132
133 # Since we're staying outside the chroot, prepend the chroot path to the
134 # sysroot path so we have a valid full path to the sysroot.
135 sysroot = sysroot_lib.Sysroot(os.path.join(chroot.path,
136 sysroot_path.lstrip(os.sep)))
137
138 if not sysroot.Exists():
139 cros_build_lib.Die('Sysroot path must exist: %s', sysroot.path)
140
141 try:
142 # Note that this returns the full path to *multiple* tarballs.
143 archives = artifacts.BundleAutotestFiles(sysroot, output_dir)
144 except artifacts.Error as e:
145 cros_build_lib.Die(e.message)
146
147 for archive in archives.values():
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600148 output_proto.artifacts.add().path = archive
149
150
151def BundleTastFiles(input_proto, output_proto):
152 """Tar the tast files for a build target.
153
154 Args:
155 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600156 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600157 """
158 target = input_proto.build_target.name
159 output_dir = input_proto.output_dir
160 build_root = constants.SOURCE_ROOT
Evan Hernandez36589c62019-04-05 18:14:42 -0600161 cwd = os.path.join(build_root, 'chroot/build', target, 'build')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600162
163 # Note that unlike the functions below, this returns the full path
164 # to the tarball.
Alex Kleine2612a02019-04-18 13:51:06 -0600165 # TODO(crbug.com/954294): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600166 archive = commands.BuildTastBundleTarball(build_root, cwd, output_dir)
167
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600168 if archive is None:
169 cros_build_lib.Die(
170 'Could not bundle Tast files. '
171 'No Tast directories found for %s.', target)
172
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600173 output_proto.artifacts.add().path = archive
174
175
176def BundlePinnedGuestImages(input_proto, output_proto):
177 """Tar the pinned guest images for a build target.
178
179 Args:
180 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600181 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600182 """
183 target = input_proto.build_target.name
184 output_dir = input_proto.output_dir
185 build_root = constants.SOURCE_ROOT
186
Alex Kleine2612a02019-04-18 13:51:06 -0600187 # TODO(crbug.com/954299): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600188 archive = commands.BuildPinnedGuestImagesTarball(build_root, target,
189 output_dir)
190
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600191 if archive is None:
Evan Hernandezde445982019-04-22 13:42:34 -0600192 logging.warning('Found no pinned guest images for %s.', target)
193 return
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600194
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600195 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
196
197
198def BundleFirmware(input_proto, output_proto):
199 """Tar the firmware images for a build target.
200
201 Args:
202 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600203 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600204 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600205 output_dir = input_proto.output_dir
Michael Mortensen3df9c762019-06-19 07:50:09 -0600206 if not output_dir:
207 cros_build_lib.Die('output_dir is required.')
208 chroot = controller_util.ParseChroot(input_proto.chroot)
209 sysroot_path = input_proto.sysroot.path
210 if not sysroot_path:
211 cros_build_lib.Die('sysroot.path is required.')
212 sysroot = sysroot_lib.Sysroot(sysroot_path)
213 archive = artifacts.BuildFirmwareArchive(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600214
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600215 if archive is None:
216 cros_build_lib.Die(
Michael Mortensen3df9c762019-06-19 07:50:09 -0600217 'Could not create firmware archive. No firmware found for %s.',
218 sysroot_path)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600219
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600220 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
221
222
223def BundleEbuildLogs(input_proto, output_proto):
224 """Tar the ebuild logs for a build target.
225
226 Args:
227 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600228 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600229 """
230 target = input_proto.build_target.name
231 output_dir = input_proto.output_dir
Evan Hernandeza478d802019-04-08 15:08:24 -0600232
233 # commands.BuildEbuildLogsTarball conflates "buildroot" with sysroot.
234 # Adjust accordingly...
235 build_root = os.path.join(constants.SOURCE_ROOT, 'chroot', 'build')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600236
Alex Kleine2612a02019-04-18 13:51:06 -0600237 # TODO(crbug.com/954303): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600238 archive = commands.BuildEbuildLogsTarball(build_root, target, output_dir)
239
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600240 if archive is None:
241 cros_build_lib.Die(
242 'Could not create ebuild logs archive. No logs found for %s.', target)
243
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600244 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Klein6504eca2019-04-18 15:37:56 -0600245
246
Alex Klein2275d692019-04-23 16:04:12 -0600247def BundleSimpleChromeArtifacts(input_proto, output_proto):
248 """Create the simple chrome artifacts."""
249 # Required args.
250 sysroot_path = input_proto.sysroot.path
251 build_target_name = input_proto.sysroot.build_target.name
252 output_dir = input_proto.output_dir
253
254 if not build_target_name:
255 cros_build_lib.Die('build_target.name is required')
256 if not output_dir:
257 cros_build_lib.Die('output_dir is required.')
258 if not os.path.exists(output_dir):
259 cros_build_lib.Die('output_dir (%s) does not exist.', output_dir)
260 if not sysroot_path:
261 cros_build_lib.Die('sysroot.path is required.')
262
263 # Optional args.
264 chroot_path = input_proto.chroot.path or constants.DEFAULT_CHROOT_PATH
265 cache_dir = input_proto.chroot.cache_dir
266
267 # Build out the argument instances.
268 build_target = build_target_util.BuildTarget(build_target_name)
269 chroot = chroot_lib.Chroot(path=chroot_path, cache_dir=cache_dir)
270 # Sysroot.path needs to be the fully qualified path, including the chroot.
271 full_sysroot_path = os.path.join(chroot.path, sysroot_path.lstrip(os.sep))
272 sysroot = sysroot_lib.Sysroot(full_sysroot_path)
273
274 # Quick sanity check that the sysroot exists before we go on.
275 if not sysroot.Exists():
276 cros_build_lib.Die('The sysroot does not exist.')
277
278 try:
279 results = artifacts.BundleSimpleChromeArtifacts(chroot, sysroot,
280 build_target, output_dir)
281 except artifacts.Error as e:
282 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
283 type(e), e)
284
285 for file_name in results:
286 output_proto.artifacts.add().path = file_name
287
288
Alex Klein6504eca2019-04-18 15:37:56 -0600289def BundleVmFiles(input_proto, output_proto):
290 """Tar VM disk and memory files.
291
292 Args:
293 input_proto (SysrootBundleRequest): The input proto.
294 output_proto (BundleResponse): The output proto.
295 """
296 chroot = input_proto.chroot.path
297 sysroot = input_proto.sysroot.path
298 test_results_dir = input_proto.test_results_dir
299 output_dir = input_proto.output_dir
300
301 if not chroot:
302 cros_build_lib.Die('chroot.path is required.')
303 if not sysroot:
304 cros_build_lib.Die('sysroot.path is required.')
305 if not test_results_dir:
306 cros_build_lib.Die('test_results_dir is required.')
307 if not output_dir:
308 cros_build_lib.Die('output_dir is required.')
309
310 # TODO(crbug.com/954344): Replace with a chromite/service implementation.
311 sysroot = sysroot.lstrip(os.sep)
312 result_dir = test_results_dir.lstrip(os.sep)
313 image_dir = os.path.join(chroot, sysroot, result_dir)
314 archives = vm_test_stages.ArchiveVMFilesFromImageDir(image_dir, output_dir)
315 for archive in archives:
316 output_proto.artifacts.add().path = archive
Tiancong Wangc4805b72019-06-11 12:12:03 -0700317
318def BundleOrderfileGenerationArtifacts(input_proto, output_proto):
319 """Create tarballs of all the artifacts of orderfile_generate builder.
320
321 Args:
322 input_proto (BundleRequest): The input proto.
323 output_proto (BundleResponse): The output proto.
324 """
325 # Required args.
326 build_target_name = input_proto.build_target.name
327 output_dir = input_proto.output_dir
328 chrome_version = input_proto.chrome_version
329
330 if not build_target_name:
331 cros_build_lib.Die('build_target.name is required.')
332 if not chrome_version:
333 cros_build_lib.Die('chrome_version is required.')
334 if not output_dir:
335 cros_build_lib.Die('output_dir is required.')
336 elif not os.path.isdir(output_dir):
337 cros_build_lib.Die('output_dir does not exist.')
338
339 chroot = controller_util.ParseChroot(input_proto.chroot)
340
341 try:
342 results = artifacts.BundleOrderfileGenerationArtifacts(
343 chroot, input_proto.build_target, chrome_version, output_dir)
344 except artifacts.Error as e:
345 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
346 type(e), e)
347
348 for file_name in results:
349 output_proto.artifacts.add().path = file_name