blob: 446d2a3a59352eb9ec1de339f6b8623a7af4c641 [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
Michael Mortensen01910922019-07-24 14:48:10 -060046@validate.require('build_target.name', 'output_dir')
Evan Hernandez9f125ac2019-04-08 17:18:47 -060047def 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)
Michael Mortensen01910922019-07-24 14:48:10 -060057 archive = artifacts.BundleImageZip(output_dir, image_dir)
Evan Hernandez9f125ac2019-04-08 17:18:47 -060058 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)
Alex Kleincb541e82019-06-26 15:06:11 -060074 img_types = [constants.IMAGE_TYPE_TEST, constants.IMAGE_TYPE_DEV,
75 constants.IMAGE_TYPE_BASE]
76 img_names = [constants.IMAGE_TYPE_TO_NAME[t] for t in img_types]
Mike Frysinger66ce4132019-07-17 22:52:52 -040077 img_paths = [os.path.join(img_dir, x) for x in img_names]
Mike Frysingera552be42018-08-17 14:39:32 -040078 valid_images = [x for x in img_paths if os.path.exists(x)]
Evan Hernandezf388cbf2019-04-01 11:15:23 -060079
Alex Kleincb541e82019-06-26 15:06:11 -060080 if not valid_images:
Evan Hernandezf388cbf2019-04-01 11:15:23 -060081 cros_build_lib.Die(
82 'Expected to find an image of type among %r for target "%s" '
Evan Hernandez9f125ac2019-04-08 17:18:47 -060083 'at path %s.', img_types, target, img_dir)
Alex Kleincb541e82019-06-26 15:06:11 -060084 image = valid_images[0]
Evan Hernandezf388cbf2019-04-01 11:15:23 -060085
Alex Kleincb541e82019-06-26 15:06:11 -060086 payloads = artifacts.BundleTestUpdatePayloads(image, output_dir)
87 for payload in payloads:
88 output_proto.artifacts.add().path = payload
Evan Hernandezf388cbf2019-04-01 11:15:23 -060089
90
91def BundleAutotestFiles(input_proto, output_proto):
92 """Tar the autotest files for a build target.
93
94 Args:
95 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -060096 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -060097 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -060098 output_dir = input_proto.output_dir
Alex Klein238d8862019-05-07 11:32:46 -060099 if not output_dir:
100 cros_build_lib.Die('output_dir is required.')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600101
Alex Klein238d8862019-05-07 11:32:46 -0600102 target = input_proto.build_target.name
103 if target:
104 # Legacy call, build out sysroot path from default source root and the
105 # build target.
106 target = input_proto.build_target.name
107 build_root = constants.SOURCE_ROOT
108 sysroot_path = os.path.join(build_root, constants.DEFAULT_CHROOT_DIR,
109 'build', target)
110 sysroot = sysroot_lib.Sysroot(sysroot_path)
111 else:
112 # New style call, use chroot and sysroot.
113 chroot = controller_util.ParseChroot(input_proto.chroot)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600114
Alex Klein238d8862019-05-07 11:32:46 -0600115 sysroot_path = input_proto.sysroot.path
116 if not sysroot_path:
117 cros_build_lib.Die('sysroot.path is required.')
118
119 # Since we're staying outside the chroot, prepend the chroot path to the
120 # sysroot path so we have a valid full path to the sysroot.
121 sysroot = sysroot_lib.Sysroot(os.path.join(chroot.path,
122 sysroot_path.lstrip(os.sep)))
123
124 if not sysroot.Exists():
125 cros_build_lib.Die('Sysroot path must exist: %s', sysroot.path)
126
127 try:
128 # Note that this returns the full path to *multiple* tarballs.
129 archives = artifacts.BundleAutotestFiles(sysroot, output_dir)
130 except artifacts.Error as e:
131 cros_build_lib.Die(e.message)
132
133 for archive in archives.values():
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600134 output_proto.artifacts.add().path = archive
135
136
Alex Kleinb9d810b2019-07-01 12:38:02 -0600137@validate.require('output_dir')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600138def BundleTastFiles(input_proto, output_proto):
139 """Tar the tast files for a build target.
140
141 Args:
142 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600143 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600144 """
145 target = input_proto.build_target.name
146 output_dir = input_proto.output_dir
147 build_root = constants.SOURCE_ROOT
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600148
Alex Kleinb9d810b2019-07-01 12:38:02 -0600149 chroot = controller_util.ParseChroot(input_proto.chroot)
150 sysroot_path = input_proto.sysroot.path
151
152 # TODO(saklein) Cleanup legacy handling after it has been switched over.
153 if target:
154 # Legacy handling.
155 chroot.path = os.path.join(build_root, 'chroot')
156 sysroot_path = os.path.join('/build', target)
157
158 # New handling - chroot & sysroot based.
159 # TODO(saklein) Switch this to the require decorator when legacy is removed.
160 if not sysroot_path:
161 cros_build_lib.Die('sysroot.path is required.')
162
163 sysroot = sysroot_lib.Sysroot(sysroot_path)
164 if not sysroot.Exists(chroot):
165 cros_build_lib.Die('Sysroot must exist.')
166
167 archive = artifacts.BundleTastFiles(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600168
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600169 if archive is None:
170 cros_build_lib.Die(
171 'Could not bundle Tast files. '
172 'No Tast directories found for %s.', target)
173
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600174 output_proto.artifacts.add().path = archive
175
176
177def BundlePinnedGuestImages(input_proto, output_proto):
178 """Tar the pinned guest images for a build target.
179
180 Args:
181 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600182 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600183 """
184 target = input_proto.build_target.name
185 output_dir = input_proto.output_dir
186 build_root = constants.SOURCE_ROOT
187
Alex Kleine2612a02019-04-18 13:51:06 -0600188 # TODO(crbug.com/954299): Replace with a chromite/service implementation.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600189 archive = commands.BuildPinnedGuestImagesTarball(build_root, target,
190 output_dir)
191
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600192 if archive is None:
Evan Hernandezde445982019-04-22 13:42:34 -0600193 logging.warning('Found no pinned guest images for %s.', target)
194 return
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600195
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600196 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
197
198
Alex Klein7bf0ecb2019-06-25 10:04:15 -0600199def FetchPinnedGuestImages(input_proto, output_proto):
200 """Get the pinned guest image information."""
201 sysroot_path = input_proto.sysroot.path
202 if not sysroot_path:
203 cros_build_lib.Die('sysroot.path is required.')
204
205 chroot = controller_util.ParseChroot(input_proto.chroot)
206 sysroot = sysroot_lib.Sysroot(sysroot_path)
207
208 if not chroot.exists():
209 cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
210
211 if not sysroot.Exists(chroot=chroot):
212 cros_build_lib.Die('Sysroot does not exist: %s',
213 chroot.full_path(sysroot.path))
214
215 pins = artifacts.FetchPinnedGuestImages(chroot, sysroot)
216
217 for pin in pins:
218 pinned_image = output_proto.pinned_images.add()
219 pinned_image.filename = pin.filename
220 pinned_image.uri = pin.uri
221
222
Michael Mortensen38675192019-06-28 16:52:55 +0000223@validate.require('output_dir', 'sysroot.path')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600224def BundleFirmware(input_proto, output_proto):
225 """Tar the firmware images for a build target.
226
227 Args:
228 input_proto (BundleRequest): The input proto.
Alex Klein6504eca2019-04-18 15:37:56 -0600229 output_proto (BundleResponse): The output proto.
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600230 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600231 output_dir = input_proto.output_dir
Michael Mortensen38675192019-06-28 16:52:55 +0000232 chroot = controller_util.ParseChroot(input_proto.chroot)
233 sysroot_path = input_proto.sysroot.path
234 sysroot = sysroot_lib.Sysroot(sysroot_path)
235 archive = artifacts.BuildFirmwareArchive(chroot, sysroot, output_dir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600236
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600237 if archive is None:
238 cros_build_lib.Die(
Michael Mortensen38675192019-06-28 16:52:55 +0000239 'Could not create firmware archive. No firmware found for %s.',
240 sysroot_path)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600241
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600242 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
243
244
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600245@validate.exists('output_dir')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600246def 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 """
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600253 output_dir = input_proto.output_dir
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600254 sysroot_path = input_proto.sysroot.path
255 chroot = controller_util.ParseChroot(input_proto.chroot)
Evan Hernandeza478d802019-04-08 15:08:24 -0600256
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600257 # TODO(mmortensen) Cleanup legacy handling after it has been switched over.
258 target = input_proto.build_target.name
259 if target:
260 # Legacy handling.
261 build_root = constants.SOURCE_ROOT
262 chroot.path = os.path.join(build_root, 'chroot')
263 sysroot_path = os.path.join('/build', target)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600264
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600265 sysroot = sysroot_lib.Sysroot(sysroot_path)
266 archive = artifacts.BundleEBuildLogsTarball(chroot, sysroot, output_dir)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600267 if archive is None:
268 cros_build_lib.Die(
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600269 'Could not create ebuild logs archive. No logs found for %s.',
270 sysroot.path)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600271 output_proto.artifacts.add().path = os.path.join(output_dir, archive)
Alex Klein6504eca2019-04-18 15:37:56 -0600272
273
Alex Klein2275d692019-04-23 16:04:12 -0600274def BundleSimpleChromeArtifacts(input_proto, output_proto):
275 """Create the simple chrome artifacts."""
276 # Required args.
277 sysroot_path = input_proto.sysroot.path
278 build_target_name = input_proto.sysroot.build_target.name
279 output_dir = input_proto.output_dir
280
281 if not build_target_name:
282 cros_build_lib.Die('build_target.name is required')
283 if not output_dir:
284 cros_build_lib.Die('output_dir is required.')
285 if not os.path.exists(output_dir):
286 cros_build_lib.Die('output_dir (%s) does not exist.', output_dir)
287 if not sysroot_path:
288 cros_build_lib.Die('sysroot.path is required.')
289
290 # Optional args.
291 chroot_path = input_proto.chroot.path or constants.DEFAULT_CHROOT_PATH
292 cache_dir = input_proto.chroot.cache_dir
293
294 # Build out the argument instances.
295 build_target = build_target_util.BuildTarget(build_target_name)
296 chroot = chroot_lib.Chroot(path=chroot_path, cache_dir=cache_dir)
297 # Sysroot.path needs to be the fully qualified path, including the chroot.
298 full_sysroot_path = os.path.join(chroot.path, sysroot_path.lstrip(os.sep))
299 sysroot = sysroot_lib.Sysroot(full_sysroot_path)
300
301 # Quick sanity check that the sysroot exists before we go on.
302 if not sysroot.Exists():
303 cros_build_lib.Die('The sysroot does not exist.')
304
305 try:
306 results = artifacts.BundleSimpleChromeArtifacts(chroot, sysroot,
307 build_target, output_dir)
308 except artifacts.Error as e:
309 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
310 type(e), e)
311
312 for file_name in results:
313 output_proto.artifacts.add().path = file_name
314
315
Michael Mortensen51f06722019-07-18 09:55:50 -0600316@validate.require('chroot.path', 'test_results_dir', 'output_dir')
Alex Klein6504eca2019-04-18 15:37:56 -0600317def BundleVmFiles(input_proto, output_proto):
318 """Tar VM disk and memory files.
319
320 Args:
321 input_proto (SysrootBundleRequest): The input proto.
322 output_proto (BundleResponse): The output proto.
323 """
Michael Mortensen51f06722019-07-18 09:55:50 -0600324 chroot = controller_util.ParseChroot(input_proto.chroot)
325 test_results_dir = input_proto.test_results_dir
Alex Klein6504eca2019-04-18 15:37:56 -0600326 output_dir = input_proto.output_dir
327
Michael Mortensen51f06722019-07-18 09:55:50 -0600328 archives = artifacts.BundleVmFiles(
329 chroot, test_results_dir, output_dir)
Alex Klein6504eca2019-04-18 15:37:56 -0600330 for archive in archives:
331 output_proto.artifacts.add().path = archive
Tiancong Wangc4805b72019-06-11 12:12:03 -0700332
333def BundleOrderfileGenerationArtifacts(input_proto, output_proto):
334 """Create tarballs of all the artifacts of orderfile_generate builder.
335
336 Args:
337 input_proto (BundleRequest): The input proto.
338 output_proto (BundleResponse): The output proto.
339 """
340 # Required args.
341 build_target_name = input_proto.build_target.name
342 output_dir = input_proto.output_dir
Tiancong Wangc4805b72019-06-11 12:12:03 -0700343
344 if not build_target_name:
345 cros_build_lib.Die('build_target.name is required.')
Tiancong Wangc4805b72019-06-11 12:12:03 -0700346 if not output_dir:
347 cros_build_lib.Die('output_dir is required.')
348 elif not os.path.isdir(output_dir):
349 cros_build_lib.Die('output_dir does not exist.')
350
351 chroot = controller_util.ParseChroot(input_proto.chroot)
352
353 try:
354 results = artifacts.BundleOrderfileGenerationArtifacts(
Tiancong Wang78b685d2019-07-29 13:57:23 -0700355 chroot, input_proto.build_target, output_dir)
Tiancong Wangc4805b72019-06-11 12:12:03 -0700356 except artifacts.Error as e:
357 cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
358 type(e), e)
359
360 for file_name in results:
361 output_proto.artifacts.add().path = file_name