blob: 8b5b364413b1bf6a05a0796d10bdfe657ef3e9b2 [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
12from chromite.cbuildbot import commands
Alex Klein6504eca2019-04-18 15:37:56 -060013from chromite.cbuildbot.stages import vm_test_stages
Alex Klein2275d692019-04-23 16:04:12 -060014from chromite.lib import build_target_util
15from chromite.lib import chroot_lib
Evan Hernandezf388cbf2019-04-01 11:15:23 -060016from chromite.lib import constants
17from chromite.lib import cros_build_lib
Evan Hernandezde445982019-04-22 13:42:34 -060018from chromite.lib import cros_logging as logging
Evan Hernandezf388cbf2019-04-01 11:15:23 -060019from chromite.lib import osutils
Alex Klein2275d692019-04-23 16:04:12 -060020from chromite.lib import sysroot_lib
21from chromite.service import artifacts
Evan Hernandezf388cbf2019-04-01 11:15:23 -060022
23
Evan Hernandez9f125ac2019-04-08 17:18:47 -060024def _GetImageDir(build_root, target):
25 """Return path containing images for the given build target.
26
Alex Kleine2612a02019-04-18 13:51:06 -060027 TODO(saklein) Expand image_lib.GetLatestImageLink to support this use case.
28
Evan Hernandez9f125ac2019-04-08 17:18:47 -060029 Args:
30 build_root (str): Path to checkout where build occurs.
31 target (str): Name of the build target.
32
33 Returns:
34 Path to the directory containing target images.
35
36 Raises:
37 DieSystemExit: If the image dir does not exist.
38 """
39 image_dir = os.path.join(build_root, 'src/build/images', target, 'latest')
40 if not os.path.exists(image_dir):
41 cros_build_lib.Die('Expected to find image output for target %s at %s, '
42 'but path does not exist' % (target, image_dir))
43 return image_dir
44
45
46def BundleImageZip(input_proto, output_proto):
47 """Bundle image.zip.
48
49 Args:
50 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -060051 output_proto (BundleResponse): The output proto.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060052 """
53 target = input_proto.build_target.name
54 output_dir = input_proto.output_dir
55 image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
56 archive = commands.BuildImageZip(output_dir, image_dir)
57 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
58
59
Evan Hernandezf388cbf2019-04-01 11:15:23 -060060def BundleTestUpdatePayloads(input_proto, output_proto):
61 """Generate minimal update payloads for the build target for testing.
62
63 Args:
64 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -060065 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -060066 """
67 target = input_proto.build_target.name
68 output_dir = input_proto.output_dir
69 build_root = constants.SOURCE_ROOT
70
71 # Use the first available image to create the update payload.
Evan Hernandez9f125ac2019-04-08 17:18:47 -060072 img_dir = _GetImageDir(build_root, target)
Evan Hernandezf388cbf2019-04-01 11:15:23 -060073 img_types = [
74 constants.IMAGE_TYPE_TEST, constants.IMAGE_TYPE_DEV,
75 constants.IMAGE_TYPE_BASE
76 ]
77 img_paths = []
78 for img_type in img_types:
Evan Hernandez9f125ac2019-04-08 17:18:47 -060079 img_path = os.path.join(img_dir, constants.IMAGE_TYPE_TO_NAME[img_type])
Evan Hernandezf388cbf2019-04-01 11:15:23 -060080 if os.path.exists(img_path):
81 img_paths.append(img_path)
82
83 if not img_paths:
84 cros_build_lib.Die(
85 'Expected to find an image of type among %r for target "%s" '
Evan Hernandez9f125ac2019-04-08 17:18:47 -060086 'at path %s.', img_types, target, img_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -060087 img = img_paths[0]
88
89 # Unfortunately, the relevant commands.py functions do not return
90 # a list of generated files. As a workaround, we have commands.py
91 # put the files in a separate temporary directory so we can catalog them,
92 # then move them to the output dir.
Alex Kleine2612a02019-04-18 13:51:06 -060093 # TODO(crbug.com/954283): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -060094 with osutils.TempDir() as temp:
95 commands.GeneratePayloads(img, temp, full=True, stateful=True, delta=True)
96 commands.GenerateQuickProvisionPayloads(img, temp)
97 for path in osutils.DirectoryIterator(temp):
98 if os.path.isfile(path):
99 rel_path = os.path.relpath(path, temp)
100 output_proto.artifacts.add().path = os.path.join(output_dir, rel_path)
Evan Hernandezb04e2aa2019-04-08 16:55:54 -0600101 osutils.CopyDirContents(temp, output_dir, allow_nonempty=True)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600102
103
104def BundleAutotestFiles(input_proto, output_proto):
105 """Tar the autotest files for a build target.
106
107 Args:
108 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600109 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600110 """
111 target = input_proto.build_target.name
112 output_dir = input_proto.output_dir
113 build_root = constants.SOURCE_ROOT
Evan Hernandez36589c62019-04-05 18:14:42 -0600114 cwd = os.path.join(build_root, 'chroot/build', target, 'usr/local/build')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600115
116 # Note that unlike the functions below, this returns the full path
117 # to *multiple* tarballs.
Alex Kleine2612a02019-04-18 13:51:06 -0600118 # TODO(crbug.com/954289): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600119 archives = commands.BuildAutotestTarballsForHWTest(build_root, cwd,
120 output_dir)
121
122 for archive in archives:
123 output_proto.artifacts.add().path = archive
124
125
126def BundleTastFiles(input_proto, output_proto):
127 """Tar the tast files for a build target.
128
129 Args:
130 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600131 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600132 """
133 target = input_proto.build_target.name
134 output_dir = input_proto.output_dir
135 build_root = constants.SOURCE_ROOT
Evan Hernandez36589c62019-04-05 18:14:42 -0600136 cwd = os.path.join(build_root, 'chroot/build', target, 'build')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600137
138 # Note that unlike the functions below, this returns the full path
139 # to the tarball.
Alex Kleine2612a02019-04-18 13:51:06 -0600140 # TODO(crbug.com/954294): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600141 archive = commands.BuildTastBundleTarball(build_root, cwd, output_dir)
142
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600143 if archive is None:
144 cros_build_lib.Die(
145 'Could not bundle Tast files. '
146 'No Tast directories found for %s.', target)
147
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600148 output_proto.artifacts.add().path = archive
149
150
151def BundlePinnedGuestImages(input_proto, output_proto):
152 """Tar the pinned guest images 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
161
Alex Kleine2612a02019-04-18 13:51:06 -0600162 # TODO(crbug.com/954299): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600163 archive = commands.BuildPinnedGuestImagesTarball(build_root, target,
164 output_dir)
165
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600166 if archive is None:
Evan Hernandezde445982019-04-22 13:42:34 -0600167 logging.warning('Found no pinned guest images for %s.', target)
168 return
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600169
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600170 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
171
172
173def BundleFirmware(input_proto, output_proto):
174 """Tar the firmware images for a build target.
175
176 Args:
177 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600178 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600179 """
180 target = input_proto.build_target.name
181 output_dir = input_proto.output_dir
182 build_root = constants.SOURCE_ROOT
183
Alex Kleine2612a02019-04-18 13:51:06 -0600184 # TODO(crbug.com/954300): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600185 archive = commands.BuildFirmwareArchive(build_root, target, output_dir)
186
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600187 if archive is None:
188 cros_build_lib.Die(
189 'Could not create firmware archive. No firmware found for %s.', target)
190
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600191 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
192
193
194def BundleEbuildLogs(input_proto, output_proto):
195 """Tar the ebuild logs for a build target.
196
197 Args:
198 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600199 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600200 """
201 target = input_proto.build_target.name
202 output_dir = input_proto.output_dir
Evan Hernandeza478d802019-04-08 15:08:24 -0600203
204 # commands.BuildEbuildLogsTarball conflates "buildroot" with sysroot.
205 # Adjust accordingly...
206 build_root = os.path.join(constants.SOURCE_ROOT, 'chroot', 'build')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600207
Alex Kleine2612a02019-04-18 13:51:06 -0600208 # TODO(crbug.com/954303): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600209 archive = commands.BuildEbuildLogsTarball(build_root, target, output_dir)
210
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600211 if archive is None:
212 cros_build_lib.Die(
213 'Could not create ebuild logs archive. No logs found for %s.', target)
214
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600215 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Klein6504eca2019-04-18 15:37:56 -0600216
217
Alex Klein2275d692019-04-23 16:04:12 -0600218def BundleSimpleChromeArtifacts(input_proto, output_proto):
219 """Create the simple chrome artifacts."""
220 # Required args.
221 sysroot_path = input_proto.sysroot.path
222 build_target_name = input_proto.sysroot.build_target.name
223 output_dir = input_proto.output_dir
224
225 if not build_target_name:
226 cros_build_lib.Die('build_target.name is required')
227 if not output_dir:
228 cros_build_lib.Die('output_dir is required.')
229 if not os.path.exists(output_dir):
230 cros_build_lib.Die('output_dir (%s) does not exist.', output_dir)
231 if not sysroot_path:
232 cros_build_lib.Die('sysroot.path is required.')
233
234 # Optional args.
235 chroot_path = input_proto.chroot.path or constants.DEFAULT_CHROOT_PATH
236 cache_dir = input_proto.chroot.cache_dir
237
238 # Build out the argument instances.
239 build_target = build_target_util.BuildTarget(build_target_name)
240 chroot = chroot_lib.Chroot(path=chroot_path, cache_dir=cache_dir)
241 # Sysroot.path needs to be the fully qualified path, including the chroot.
242 full_sysroot_path = os.path.join(chroot.path, sysroot_path.lstrip(os.sep))
243 sysroot = sysroot_lib.Sysroot(full_sysroot_path)
244
245 # Quick sanity check that the sysroot exists before we go on.
246 if not sysroot.Exists():
247 cros_build_lib.Die('The sysroot does not exist.')
248
249 try:
250 results = artifacts.BundleSimpleChromeArtifacts(chroot, sysroot,
251 build_target, output_dir)
252 except artifacts.Error as e:
253 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
254 type(e), e)
255
256 for file_name in results:
257 output_proto.artifacts.add().path = file_name
258
259
Alex Klein6504eca2019-04-18 15:37:56 -0600260def BundleVmFiles(input_proto, output_proto):
261 """Tar VM disk and memory files.
262
263 Args:
264 input_proto (SysrootBundleRequest): The input proto.
265 output_proto (BundleResponse): The output proto.
266 """
267 chroot = input_proto.chroot.path
268 sysroot = input_proto.sysroot.path
269 test_results_dir = input_proto.test_results_dir
270 output_dir = input_proto.output_dir
271
272 if not chroot:
273 cros_build_lib.Die('chroot.path is required.')
274 if not sysroot:
275 cros_build_lib.Die('sysroot.path is required.')
276 if not test_results_dir:
277 cros_build_lib.Die('test_results_dir is required.')
278 if not output_dir:
279 cros_build_lib.Die('output_dir is required.')
280
281 # TODO(crbug.com/954344): Replace with a chromite/service implementation.
282 sysroot = sysroot.lstrip(os.sep)
283 result_dir = test_results_dir.lstrip(os.sep)
284 image_dir = os.path.join(chroot, sysroot, result_dir)
285 archives = vm_test_stages.ArchiveVMFilesFromImageDir(image_dir, output_dir)
286 for archive in archives:
287 output_proto.artifacts.add().path = archive