blob: 239af7a5cf7669fa043a7eefde75c686470aa99b [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 Klein2b236722019-06-19 15:44:26 -060012from chromite.api import validate
Alex Klein238d8862019-05-07 11:32:46 -060013from chromite.api.controller import controller_util
Evan Hernandezf388cbf2019-04-01 11:15:23 -060014from chromite.cbuildbot import commands
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
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)
Alex Kleincb541e82019-06-26 15:06:11 -060073 img_types = [constants.IMAGE_TYPE_TEST, constants.IMAGE_TYPE_DEV,
74 constants.IMAGE_TYPE_BASE]
75 img_names = [constants.IMAGE_TYPE_TO_NAME[t] for t in img_types]
Mike Frysinger66ce4132019-07-17 22:52:52 -040076 img_paths = [os.path.join(img_dir, x) for x in img_names]
Mike Frysingera552be42018-08-17 14:39:32 -040077 valid_images = [x for x in img_paths if os.path.exists(x)]
Evan Hernandezf388cbf2019-04-01 11:15:23 -060078
Alex Kleincb541e82019-06-26 15:06:11 -060079 if not valid_images:
Evan Hernandezf388cbf2019-04-01 11:15:23 -060080 cros_build_lib.Die(
81 'Expected to find an image of type among %r for target "%s" '
Evan Hernandez9f125ac2019-04-08 17:18:47 -060082 'at path %s.', img_types, target, img_dir)
Alex Kleincb541e82019-06-26 15:06:11 -060083 image = valid_images[0]
Evan Hernandezf388cbf2019-04-01 11:15:23 -060084
Alex Kleincb541e82019-06-26 15:06:11 -060085 payloads = artifacts.BundleTestUpdatePayloads(image, output_dir)
86 for payload in payloads:
87 output_proto.artifacts.add().path = payload
Evan Hernandezf388cbf2019-04-01 11:15:23 -060088
89
90def BundleAutotestFiles(input_proto, output_proto):
91 """Tar the autotest files for a build target.
92
93 Args:
94 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -060095 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -060096 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -060097 output_dir = input_proto.output_dir
Alex Klein238d8862019-05-07 11:32:46 -060098 if not output_dir:
99 cros_build_lib.Die('output_dir is required.')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600100
Alex Klein238d8862019-05-07 11:32:46 -0600101 target = input_proto.build_target.name
102 if target:
103 # Legacy call, build out sysroot path from default source root and the
104 # build target.
105 target = input_proto.build_target.name
106 build_root = constants.SOURCE_ROOT
107 sysroot_path = os.path.join(build_root, constants.DEFAULT_CHROOT_DIR,
108 'build', target)
109 sysroot = sysroot_lib.Sysroot(sysroot_path)
110 else:
111 # New style call, use chroot and sysroot.
112 chroot = controller_util.ParseChroot(input_proto.chroot)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600113
Alex Klein238d8862019-05-07 11:32:46 -0600114 sysroot_path = input_proto.sysroot.path
115 if not sysroot_path:
116 cros_build_lib.Die('sysroot.path is required.')
117
118 # Since we're staying outside the chroot, prepend the chroot path to the
119 # sysroot path so we have a valid full path to the sysroot.
120 sysroot = sysroot_lib.Sysroot(os.path.join(chroot.path,
121 sysroot_path.lstrip(os.sep)))
122
123 if not sysroot.Exists():
124 cros_build_lib.Die('Sysroot path must exist: %s', sysroot.path)
125
126 try:
127 # Note that this returns the full path to *multiple* tarballs.
128 archives = artifacts.BundleAutotestFiles(sysroot, output_dir)
129 except artifacts.Error as e:
130 cros_build_lib.Die(e.message)
131
132 for archive in archives.values():
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600133 output_proto.artifacts.add().path = archive
134
135
Alex Kleinb9d810b2019-07-01 12:38:02 -0600136@validate.require('output_dir')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600137def BundleTastFiles(input_proto, output_proto):
138 """Tar the tast files for a build target.
139
140 Args:
141 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600142 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600143 """
144 target = input_proto.build_target.name
145 output_dir = input_proto.output_dir
146 build_root = constants.SOURCE_ROOT
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600147
Alex Kleinb9d810b2019-07-01 12:38:02 -0600148 chroot = controller_util.ParseChroot(input_proto.chroot)
149 sysroot_path = input_proto.sysroot.path
150
151 # TODO(saklein) Cleanup legacy handling after it has been switched over.
152 if target:
153 # Legacy handling.
154 chroot.path = os.path.join(build_root, 'chroot')
155 sysroot_path = os.path.join('/build', target)
156
157 # New handling - chroot & sysroot based.
158 # TODO(saklein) Switch this to the require decorator when legacy is removed.
159 if not sysroot_path:
160 cros_build_lib.Die('sysroot.path is required.')
161
162 sysroot = sysroot_lib.Sysroot(sysroot_path)
163 if not sysroot.Exists(chroot):
164 cros_build_lib.Die('Sysroot must exist.')
165
166 archive = artifacts.BundleTastFiles(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600167
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
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600198def FetchPinnedGuestImages(input_proto, output_proto):
199 """Get the pinned guest image information."""
200 sysroot_path = input_proto.sysroot.path
201 if not sysroot_path:
202 cros_build_lib.Die('sysroot.path is required.')
203
204 chroot = controller_util.ParseChroot(input_proto.chroot)
205 sysroot = sysroot_lib.Sysroot(sysroot_path)
206
207 if not chroot.exists():
208 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
209
210 if not sysroot.Exists(chroot=chroot):
211 cros_build_lib.Die('Sysroot does not exist: %s',
212 chroot.full_path(sysroot.path))
213
214 pins = artifacts.FetchPinnedGuestImages(chroot, sysroot)
215
216 for pin in pins:
217 pinned_image = output_proto.pinned_images.add()
218 pinned_image.filename = pin.filename
219 pinned_image.uri = pin.uri
220
221
Michael Mortensen38675192019-06-28 16:52:55 +0000222@validate.require('output_dir', 'sysroot.path')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600223def BundleFirmware(input_proto, output_proto):
224 """Tar the firmware images 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 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600230 output_dir = input_proto.output_dir
Michael Mortensen38675192019-06-28 16:52:55 +0000231 chroot = controller_util.ParseChroot(input_proto.chroot)
232 sysroot_path = input_proto.sysroot.path
233 sysroot = sysroot_lib.Sysroot(sysroot_path)
234 archive = artifacts.BuildFirmwareArchive(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600235
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600236 if archive is None:
237 cros_build_lib.Die(
Michael Mortensen38675192019-06-28 16:52:55 +0000238 'Could not create firmware archive. No firmware found for %s.',
239 sysroot_path)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600240
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600241 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
242
243
244def BundleEbuildLogs(input_proto, output_proto):
245 """Tar the ebuild logs for a build target.
246
247 Args:
248 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600249 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600250 """
251 target = input_proto.build_target.name
252 output_dir = input_proto.output_dir
Evan Hernandeza478d802019-04-08 15:08:24 -0600253
254 # commands.BuildEbuildLogsTarball conflates "buildroot" with sysroot.
255 # Adjust accordingly...
256 build_root = os.path.join(constants.SOURCE_ROOT, 'chroot', 'build')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600257
Alex Kleine2612a02019-04-18 13:51:06 -0600258 # TODO(crbug.com/954303): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600259 archive = commands.BuildEbuildLogsTarball(build_root, target, output_dir)
260
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600261 if archive is None:
262 cros_build_lib.Die(
263 'Could not create ebuild logs archive. No logs found for %s.', target)
264
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600265 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Klein6504eca2019-04-18 15:37:56 -0600266
267
Alex Klein2275d692019-04-23 16:04:12 -0600268def BundleSimpleChromeArtifacts(input_proto, output_proto):
269 """Create the simple chrome artifacts."""
270 # Required args.
271 sysroot_path = input_proto.sysroot.path
272 build_target_name = input_proto.sysroot.build_target.name
273 output_dir = input_proto.output_dir
274
275 if not build_target_name:
276 cros_build_lib.Die('build_target.name is required')
277 if not output_dir:
278 cros_build_lib.Die('output_dir is required.')
279 if not os.path.exists(output_dir):
280 cros_build_lib.Die('output_dir (%s) does not exist.', output_dir)
281 if not sysroot_path:
282 cros_build_lib.Die('sysroot.path is required.')
283
284 # Optional args.
285 chroot_path = input_proto.chroot.path or constants.DEFAULT_CHROOT_PATH
286 cache_dir = input_proto.chroot.cache_dir
287
288 # Build out the argument instances.
289 build_target = build_target_util.BuildTarget(build_target_name)
290 chroot = chroot_lib.Chroot(path=chroot_path, cache_dir=cache_dir)
291 # Sysroot.path needs to be the fully qualified path, including the chroot.
292 full_sysroot_path = os.path.join(chroot.path, sysroot_path.lstrip(os.sep))
293 sysroot = sysroot_lib.Sysroot(full_sysroot_path)
294
295 # Quick sanity check that the sysroot exists before we go on.
296 if not sysroot.Exists():
297 cros_build_lib.Die('The sysroot does not exist.')
298
299 try:
300 results = artifacts.BundleSimpleChromeArtifacts(chroot, sysroot,
301 build_target, output_dir)
302 except artifacts.Error as e:
303 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
304 type(e), e)
305
306 for file_name in results:
307 output_proto.artifacts.add().path = file_name
308
309
Michael Mortensen51f06722019-07-18 09:55:50 -0600310@validate.require('chroot.path', 'test_results_dir', 'output_dir')
Alex Klein6504eca2019-04-18 15:37:56 -0600311def BundleVmFiles(input_proto, output_proto):
312 """Tar VM disk and memory files.
313
314 Args:
315 input_proto (SysrootBundleRequest): The input proto.
316 output_proto (BundleResponse): The output proto.
317 """
Michael Mortensen51f06722019-07-18 09:55:50 -0600318 chroot = controller_util.ParseChroot(input_proto.chroot)
319 test_results_dir = input_proto.test_results_dir
Alex Klein6504eca2019-04-18 15:37:56 -0600320 output_dir = input_proto.output_dir
321
Michael Mortensen51f06722019-07-18 09:55:50 -0600322 archives = artifacts.BundleVmFiles(
323 chroot, test_results_dir, output_dir)
Alex Klein6504eca2019-04-18 15:37:56 -0600324 for archive in archives:
325 output_proto.artifacts.add().path = archive
Tiancong Wangc4805b72019-06-11 12:12:03 -0700326
327def BundleOrderfileGenerationArtifacts(input_proto, output_proto):
328 """Create tarballs of all the artifacts of orderfile_generate builder.
329
330 Args:
331 input_proto (BundleRequest): The input proto.
332 output_proto (BundleResponse): The output proto.
333 """
334 # Required args.
335 build_target_name = input_proto.build_target.name
336 output_dir = input_proto.output_dir
337 chrome_version = input_proto.chrome_version
338
339 if not build_target_name:
340 cros_build_lib.Die('build_target.name is required.')
341 if not chrome_version:
342 cros_build_lib.Die('chrome_version is required.')
343 if not output_dir:
344 cros_build_lib.Die('output_dir is required.')
345 elif not os.path.isdir(output_dir):
346 cros_build_lib.Die('output_dir does not exist.')
347
348 chroot = controller_util.ParseChroot(input_proto.chroot)
349
350 try:
351 results = artifacts.BundleOrderfileGenerationArtifacts(
352 chroot, input_proto.build_target, chrome_version, output_dir)
353 except artifacts.Error as e:
354 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
355 type(e), e)
356
357 for file_name in results:
358 output_proto.artifacts.add().path = file_name