blob: 4fd3182704404c1c03538451c999e06024f3be60 [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Don Garrettc4114cc2016-11-01 20:04:06 -07002# Copyright 2016 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"""Bootstrap for cbuildbot.
7
8This script is intended to checkout chromite on the branch specified by -b or
9--branch (as normally accepted by cbuildbot), and then invoke cbuildbot. Most
10arguments are not parsed, only passed along. If a branch is not specified, this
11script will use 'master'.
12
13Among other things, this allows us to invoke build configs that exist on a given
14branch, but not on TOT.
15"""
16
17from __future__ import print_function
18
Benjamin Gordon90b2dd92018-04-12 14:04:21 -060019import base64
Don Garrett125d4dc2017-04-25 16:26:03 -070020import functools
Don Garrettc4114cc2016-11-01 20:04:06 -070021import os
Prathmesh Prabhuc41a0f52018-04-03 13:26:52 -070022import time
Don Garrettc4114cc2016-11-01 20:04:06 -070023
24from chromite.cbuildbot import repository
Don Garrett597ddff2017-02-17 18:29:37 -080025from chromite.cbuildbot.stages import sync_stages
Lann Martinebae73d2018-05-21 17:12:00 -060026from chromite.lib import boto_compat
Benjamin Gordon90b2dd92018-04-12 14:04:21 -060027from chromite.lib import build_summary
Don Garrett86881cb2017-02-15 15:41:55 -080028from chromite.lib import config_lib
Don Garretta50bf492017-09-28 18:33:02 -070029from chromite.lib import constants
Don Garrettc4114cc2016-11-01 20:04:06 -070030from chromite.lib import cros_build_lib
31from chromite.lib import cros_logging as logging
Benjamin Gordon74645232018-05-04 17:40:42 -060032from chromite.lib import cros_sdk_lib
Don Garrettacbb2392017-05-11 18:27:41 -070033from chromite.lib import metrics
Don Garrettc4114cc2016-11-01 20:04:06 -070034from chromite.lib import osutils
Don Garrettacbb2392017-05-11 18:27:41 -070035from chromite.lib import ts_mon_config
Don Garrett86881cb2017-02-15 15:41:55 -080036from chromite.scripts import cbuildbot
Don Garrettc4114cc2016-11-01 20:04:06 -070037
Don Garrett60967922017-04-12 18:51:44 -070038# This number should be incremented when we change the layout of the buildroot
39# in a non-backwards compatible way. This wipes all buildroots.
Don Garrettbf90cdf2017-05-19 15:54:02 -070040BUILDROOT_BUILDROOT_LAYOUT = 2
Prathmesh Prabhuc41a0f52018-04-03 13:26:52 -070041_DISTFILES_CACHE_EXPIRY_HOURS = 8 * 24
Don Garrett60967922017-04-12 18:51:44 -070042
Don Garrettacbb2392017-05-11 18:27:41 -070043# Metrics reported to Monarch.
Mike Nicholscb29fbd2018-07-24 11:09:33 -060044METRIC_PREFIX = 'chromeos/chromite/cbuildbot_launch/'
45METRIC_ACTIVE = METRIC_PREFIX + 'active'
46METRIC_INVOKED = METRIC_PREFIX + 'invoked'
47METRIC_COMPLETED = METRIC_PREFIX + 'completed'
48METRIC_PREP = METRIC_PREFIX + 'prep_completed'
49METRIC_CLEAN = METRIC_PREFIX + 'clean_buildroot_durations'
50METRIC_INITIAL = METRIC_PREFIX + 'initial_checkout_durations'
51METRIC_CBUILDBOT = METRIC_PREFIX + 'cbuildbot_durations'
52METRIC_CBUILDBOT_INSTANCE = METRIC_PREFIX + 'cbuildbot_instance_durations'
53METRIC_CLOBBER = METRIC_PREFIX + 'clobber'
54METRIC_BRANCH_CLEANUP = METRIC_PREFIX + 'branch_cleanup'
55METRIC_DISTFILES_CLEANUP = METRIC_PREFIX + 'distfiles_cleanup'
56METRIC_CHROOT_CLEANUP = METRIC_PREFIX + 'chroot_cleanup'
Don Garrettacbb2392017-05-11 18:27:41 -070057
Benjamin Gordon90b2dd92018-04-12 14:04:21 -060058# Builder state
59BUILDER_STATE_FILENAME = '.cbuildbot_build_state.json'
60
Don Garrett60967922017-04-12 18:51:44 -070061
Don Garrett125d4dc2017-04-25 16:26:03 -070062def StageDecorator(functor):
63 """A Decorator that adds buildbot stage tags around a method.
64
Don Garrettacbb2392017-05-11 18:27:41 -070065 It uses the method name as the stage name, and assumes failure on a true
66 return value, or an exception.
Don Garrett125d4dc2017-04-25 16:26:03 -070067 """
68 @functools.wraps(functor)
69 def wrapped_functor(*args, **kwargs):
70 try:
71 logging.PrintBuildbotStepName(functor.__name__)
Don Garrettacbb2392017-05-11 18:27:41 -070072 result = functor(*args, **kwargs)
Don Garrett125d4dc2017-04-25 16:26:03 -070073 except Exception:
74 logging.PrintBuildbotStepFailure()
75 raise
76
Don Garrettacbb2392017-05-11 18:27:41 -070077 if result:
78 logging.PrintBuildbotStepFailure()
79 return result
80
Don Garrett125d4dc2017-04-25 16:26:03 -070081 return wrapped_functor
82
83
Don Garrettb5fc08b2017-11-20 21:51:16 +000084def field(fields, **kwargs):
Don Garrettacbb2392017-05-11 18:27:41 -070085 """Helper for inserting more fields into a metrics fields dictionary.
86
87 Args:
88 fields: Dictionary of metrics fields.
89 kwargs: Each argument is a key/value pair to insert into dict.
90
91 Returns:
92 Copy of original dictionary with kwargs set as fields.
93 """
94 f = fields.copy()
95 f.update(kwargs)
96 return f
97
Don Garretta50bf492017-09-28 18:33:02 -070098
99def PrependPath(prepend):
100 """Generate path with new directory at the beginning.
101
102 Args:
103 prepend: Directory to add at the beginning of the path.
104
105 Returns:
106 Extended path as a string.
107 """
108 return os.pathsep.join([prepend, os.environ.get('PATH', os.defpath)])
109
Don Garrett86881cb2017-02-15 15:41:55 -0800110def PreParseArguments(argv):
Don Garrettc4114cc2016-11-01 20:04:06 -0700111 """Extract the branch name from cbuildbot command line arguments.
112
Don Garrettc4114cc2016-11-01 20:04:06 -0700113 Args:
114 argv: The command line arguments to parse.
115
116 Returns:
117 Branch as a string ('master' if nothing is specified).
118 """
Don Garrett86881cb2017-02-15 15:41:55 -0800119 parser = cbuildbot.CreateParser()
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400120 options = cbuildbot.ParseCommandLine(parser, argv)
Don Garrettd1d90dd2017-06-13 17:35:52 -0700121 options.Freeze()
Don Garrett86881cb2017-02-15 15:41:55 -0800122
123 # This option isn't required for cbuildbot, but is for us.
124 if not options.buildroot:
125 cros_build_lib.Die('--buildroot is a required option.')
126
127 return options
Don Garrettc4114cc2016-11-01 20:04:06 -0700128
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600129def GetCurrentBuildState(options, branch):
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600130 """Extract information about the current build state from command-line args.
131
132 Args:
133 options: A parsed options object from a cbuildbot parser.
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600134 branch: The name of the branch this builder was called with.
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600135
136 Returns:
137 A BuildSummary object describing the current build.
138 """
139 build_state = build_summary.BuildSummary(
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600140 status=constants.BUILDER_STATUS_INFLIGHT,
141 buildroot_layout=BUILDROOT_BUILDROOT_LAYOUT,
142 branch=branch)
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600143 if options.buildnumber:
144 build_state.build_number = options.buildnumber
145 if options.buildbucket_id:
146 build_state.buildbucket_id = options.buildbucket_id
147 if options.master_build_id:
148 build_state.master_build_id = options.master_build_id
149 return build_state
150
151
152def GetLastBuildState(root):
153 """Fetch the state of the last build run from |root|.
154
155 If the saved state file can't be read or doesn't contain valid JSON, a default
156 state will be returned.
157
158 Args:
159 root: Root of the working directory tree as a string.
160
161 Returns:
162 A BuildSummary object representing the previous build.
163 """
164 state_file = os.path.join(root, BUILDER_STATE_FILENAME)
165
166 state = build_summary.BuildSummary()
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600167
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600168 try:
169 state_raw = osutils.ReadFile(state_file)
170 state.from_json(state_raw)
171 except IOError as e:
172 logging.warning('Unable to read %s: %s', state_file, e)
173 return state
174 except ValueError as e:
175 logging.warning('Saved state file %s is not valid JSON: %s', state_file, e)
176 return state
177
178 if not state.is_valid():
179 logging.warning('Previous build state is not valid. Ignoring.')
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600180 state = build_summary.BuildSummary()
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600181
182 return state
183
184
185def SetLastBuildState(root, new_state):
186 """Save the state of the last build under |root|.
187
188 Args:
189 root: Root of the working directory tree as a string.
190 new_state: BuildSummary object containing the state to be saved.
191 """
192 state_file = os.path.join(root, BUILDER_STATE_FILENAME)
193 osutils.WriteFile(state_file, new_state.to_json())
194
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600195 # Remove old state file. Its contents have been migrated into the new file.
196 old_state_file = os.path.join(root, '.cbuildbot_launch_state')
197 osutils.SafeUnlink(old_state_file)
198
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600199
Prathmesh Prabhuc41a0f52018-04-03 13:26:52 -0700200def _MaybeCleanDistfiles(repo, distfiles_ts, metrics_fields):
201 """Cleans the distfiles directory if too old.
202
203 Args:
204 repo: repository.RepoRepository instance.
205 distfiles_ts: A timestamp str for the last time distfiles was cleaned. May
206 be None.
207 metrics_fields: Dictionary of fields to include in metrics.
208
209 Returns:
210 The new distfiles_ts to persist in state.
211 """
Don Garrette3f1a472018-06-19 13:03:21 -0700212 # distfiles_ts can be None for a fresh environment, which means clean.
Prathmesh Prabhuc41a0f52018-04-03 13:26:52 -0700213 if distfiles_ts is None:
Don Garrette3f1a472018-06-19 13:03:21 -0700214 return time.time()
Prathmesh Prabhuc41a0f52018-04-03 13:26:52 -0700215
216 distfiles_age = (time.time() - distfiles_ts) / 3600.0
217 if distfiles_age < _DISTFILES_CACHE_EXPIRY_HOURS:
218 return distfiles_ts
219
220 logging.info('Remove old distfiles cache (cache expiry %d hours)',
221 _DISTFILES_CACHE_EXPIRY_HOURS)
222 osutils.RmDir(os.path.join(repo.directory, '.cache', 'distfiles'),
223 ignore_missing=True, sudo=True)
224 metrics.Counter(METRIC_DISTFILES_CLEANUP).increment(
225 field(metrics_fields, reason='cache_expired'))
Don Garrette3f1a472018-06-19 13:03:21 -0700226
Prathmesh Prabhuc41a0f52018-04-03 13:26:52 -0700227 # Cleaned cache, so reset distfiles_ts
Don Garrette3f1a472018-06-19 13:03:21 -0700228 return time.time()
Prathmesh Prabhuc41a0f52018-04-03 13:26:52 -0700229
230
Don Garrett125d4dc2017-04-25 16:26:03 -0700231@StageDecorator
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600232def CleanBuildRoot(root, repo, metrics_fields, build_state):
Don Garrett7ade05a2017-02-17 13:31:47 -0800233 """Some kinds of branch transitions break builds.
234
Don Garrettbf90cdf2017-05-19 15:54:02 -0700235 This method ensures that cbuildbot's buildroot is a clean checkout on the
236 given branch when it starts. If necessary (a branch transition) it will wipe
237 assorted state that cannot be safely reused from the previous build.
Don Garrett7ade05a2017-02-17 13:31:47 -0800238
Don Garrett7ade05a2017-02-17 13:31:47 -0800239 Args:
Don Garrettbf90cdf2017-05-19 15:54:02 -0700240 root: Root directory owned by cbuildbot_launch.
Don Garrettf324bc32017-05-23 14:00:53 -0700241 repo: repository.RepoRepository instance.
Don Garrettacbb2392017-05-11 18:27:41 -0700242 metrics_fields: Dictionary of fields to include in metrics.
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600243 build_state: BuildSummary object containing the current build state that
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600244 will be saved into the cleaned root. The distfiles_ts property will
245 be updated if the distfiles cache is cleaned.
Don Garrett7ade05a2017-02-17 13:31:47 -0800246 """
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600247 previous_state = GetLastBuildState(root)
248 build_state.distfiles_ts = _MaybeCleanDistfiles(
249 repo, previous_state.distfiles_ts, metrics_fields)
Don Garrette17e1d92017-04-12 15:28:19 -0700250
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600251 if previous_state.buildroot_layout != BUILDROOT_BUILDROOT_LAYOUT:
Don Garrett125d4dc2017-04-25 16:26:03 -0700252 logging.PrintBuildbotStepText('Unknown layout: Wiping buildroot.')
Don Garrettb5fc08b2017-11-20 21:51:16 +0000253 metrics.Counter(METRIC_CLOBBER).increment(
254 field(metrics_fields, reason='layout_change'))
Benjamin Gordonaee36b82018-02-05 14:25:26 -0700255 chroot_dir = os.path.join(root, constants.DEFAULT_CHROOT_DIR)
Don Garrettb5fc08b2017-11-20 21:51:16 +0000256 if os.path.exists(chroot_dir) or os.path.exists(chroot_dir + '.img'):
Don Garrett36650112018-06-28 15:54:34 -0700257 cros_sdk_lib.CleanupChrootMount(chroot_dir, delete=True)
Don Garrettb5fc08b2017-11-20 21:51:16 +0000258 osutils.RmDir(root, ignore_missing=True, sudo=True)
Don Garrettf324bc32017-05-23 14:00:53 -0700259 else:
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600260 if previous_state.branch != repo.branch:
Don Garrettf324bc32017-05-23 14:00:53 -0700261 logging.PrintBuildbotStepText('Branch change: Cleaning buildroot.')
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600262 logging.info('Unmatched branch: %s -> %s', previous_state.branch,
263 repo.branch)
Don Garrettacbb2392017-05-11 18:27:41 -0700264 metrics.Counter(METRIC_BRANCH_CLEANUP).increment(
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600265 field(metrics_fields, old_branch=previous_state.branch))
Don Garrett39963602017-02-27 14:41:58 -0800266
Don Garrettf324bc32017-05-23 14:00:53 -0700267 logging.info('Remove Chroot.')
Benjamin Gordonaee36b82018-02-05 14:25:26 -0700268 chroot_dir = os.path.join(repo.directory, constants.DEFAULT_CHROOT_DIR)
Benjamin Gordon59ba2f82017-08-28 15:31:06 -0600269 if os.path.exists(chroot_dir) or os.path.exists(chroot_dir + '.img'):
Don Garrett36650112018-06-28 15:54:34 -0700270 cros_sdk_lib.CleanupChrootMount(chroot_dir, delete=True)
Don Garrett7ade05a2017-02-17 13:31:47 -0800271
Don Garrettf324bc32017-05-23 14:00:53 -0700272 logging.info('Remove Chrome checkout.')
Don Garrettbf90cdf2017-05-19 15:54:02 -0700273 osutils.RmDir(os.path.join(repo.directory, '.cache', 'distfiles'),
Don Garrettf324bc32017-05-23 14:00:53 -0700274 ignore_missing=True, sudo=True)
275
Don Garrett1241c4e2018-08-06 17:33:41 -0700276 try:
277 # If there is any failure doing the cleanup, wipe everything.
278 # The previous run might have been killed in the middle leaving stale git
279 # locks. Clean those up, first.
280 repo.PreLoad()
281 repo.CleanStaleLocks()
282 repo.BuildRootGitCleanup(prune_all=True)
283 except Exception:
284 logging.info('Checkout cleanup failed, wiping buildroot:', exc_info=True)
285 metrics.Counter(METRIC_CLOBBER).increment(
286 field(metrics_fields, reason='repo_cleanup_failure'))
287 repository.ClearBuildRoot(repo.directory)
Don Garrett39963602017-02-27 14:41:58 -0800288
Don Garrettbf90cdf2017-05-19 15:54:02 -0700289 # Ensure buildroot exists. Save the state we are prepped for.
290 osutils.SafeMakedirs(repo.directory)
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600291 SetLastBuildState(root, build_state)
Don Garrett7ade05a2017-02-17 13:31:47 -0800292
293
Don Garrett125d4dc2017-04-25 16:26:03 -0700294@StageDecorator
Don Garrettf324bc32017-05-23 14:00:53 -0700295def InitialCheckout(repo):
Don Garrett86881cb2017-02-15 15:41:55 -0800296 """Preliminary ChromeOS checkout.
297
298 Perform a complete checkout of ChromeOS on the specified branch. This does NOT
299 match what the build needs, but ensures the buildroot both has a 'hot'
300 checkout, and is close enough that the branched cbuildbot can successfully get
301 the right checkout.
302
303 This checks out full ChromeOS, even if a ChromiumOS build is going to be
304 performed. This is because we have no knowledge of the build config to be
305 used.
Don Garrettc4114cc2016-11-01 20:04:06 -0700306
307 Args:
Don Garrettf324bc32017-05-23 14:00:53 -0700308 repo: repository.RepoRepository instance.
Don Garrettc4114cc2016-11-01 20:04:06 -0700309 """
Don Garrettf324bc32017-05-23 14:00:53 -0700310 logging.PrintBuildbotStepText('Branch: %s' % repo.branch)
Don Garrett7ade05a2017-02-17 13:31:47 -0800311 logging.info('Bootstrap script starting initial sync on branch: %s',
Don Garrettf324bc32017-05-23 14:00:53 -0700312 repo.branch)
Don Garrett76496912017-05-11 16:59:11 -0700313 repo.Sync(detach=True)
Don Garrettc4114cc2016-11-01 20:04:06 -0700314
315
Lann Martin8c4c6802018-05-23 11:09:46 -0600316def ShouldFixBotoCerts(options):
317 """Decide if FixBotoCerts should be applied for this branch."""
318 try:
319 # Only apply to factory and firmware branches.
320 branch = options.branch or ''
321 prefix = branch.split('-')[0]
322 if prefix not in ('factory', 'firmware'):
323 return False
324
325 # Only apply to "old" branches.
326 if branch.endswith('.B'):
327 version = branch[:-2].split('-')[-1]
328 major = int(version.split('.')[0])
329 return major <= 9667 # This is the newest known to be failing.
330
331 return False
Mike Frysinger9f470262018-08-03 15:09:58 -0400332 except Exception as e:
Lann Martin8c4c6802018-05-23 11:09:46 -0600333 logging.warning(' failed: %s', e)
334 # Conservatively continue without the fix.
335 return False
336
337
Don Garrett066e6f52017-09-28 19:14:01 -0700338@StageDecorator
Don Garrett6e5c6b92018-04-06 17:58:49 -0700339def Cbuildbot(buildroot, depot_tools_path, argv):
Don Garrettc4114cc2016-11-01 20:04:06 -0700340 """Start cbuildbot in specified directory with all arguments.
341
342 Args:
Don Garrettbf90cdf2017-05-19 15:54:02 -0700343 buildroot: Directory to be passed to cbuildbot with --buildroot.
Don Garretta50bf492017-09-28 18:33:02 -0700344 depot_tools_path: Directory for depot_tools to be used by cbuildbot.
Don Garrettd1d90dd2017-06-13 17:35:52 -0700345 argv: Command line options passed to cbuildbot_launch.
Don Garrettc4114cc2016-11-01 20:04:06 -0700346
347 Returns:
348 Return code of cbuildbot as an integer.
349 """
Don Garrettbf90cdf2017-05-19 15:54:02 -0700350 logging.info('Bootstrap cbuildbot in: %s', buildroot)
Don Garrettbf90cdf2017-05-19 15:54:02 -0700351
Don Garrettd1d90dd2017-06-13 17:35:52 -0700352 # Fixup buildroot parameter.
353 argv = argv[:]
354 for i in xrange(len(argv)):
355 if argv[i] in ('-r', '--buildroot'):
356 argv[i+1] = buildroot
Don Garrett597ddff2017-02-17 18:29:37 -0800357
Don Garrettd1d90dd2017-06-13 17:35:52 -0700358 # This filters out command line arguments not supported by older versions
359 # of cbuildbot.
360 parser = cbuildbot.CreateParser()
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400361 options = cbuildbot.ParseCommandLine(parser, argv)
Don Garrettd1d90dd2017-06-13 17:35:52 -0700362 cbuildbot_path = os.path.join(buildroot, 'chromite', 'bin', 'cbuildbot')
Don Garrett597ddff2017-02-17 18:29:37 -0800363 cmd = sync_stages.BootstrapStage.FilterArgsForTargetCbuildbot(
Don Garrettbf90cdf2017-05-19 15:54:02 -0700364 buildroot, cbuildbot_path, options)
Don Garrett597ddff2017-02-17 18:29:37 -0800365
Don Garretta50bf492017-09-28 18:33:02 -0700366 # We want cbuildbot to use branched depot_tools scripts from our manifest,
367 # so that depot_tools is branched to match cbuildbot.
368 logging.info('Adding depot_tools into PATH: %s', depot_tools_path)
369 extra_env = {'PATH': PrependPath(depot_tools_path)}
370
Lann Martinebae73d2018-05-21 17:12:00 -0600371 # TODO(crbug.com/845304): Remove once underlying boto issues are resolved.
Lann Martin8c4c6802018-05-23 11:09:46 -0600372 fix_boto = ShouldFixBotoCerts(options)
Lann Martinebae73d2018-05-21 17:12:00 -0600373
374 with boto_compat.FixBotoCerts(activate=fix_boto):
375 result = cros_build_lib.RunCommand(
376 cmd, extra_env=extra_env, error_code_ok=True, cwd=buildroot)
377
Don Garrettacbb2392017-05-11 18:27:41 -0700378 return result.returncode
Don Garrettc4114cc2016-11-01 20:04:06 -0700379
Don Garrett60967922017-04-12 18:51:44 -0700380
Benjamin Gordonaee36b82018-02-05 14:25:26 -0700381@StageDecorator
382def CleanupChroot(buildroot):
383 """Unmount/clean up an image-based chroot without deleting the backing image.
384
385 Args:
386 buildroot: Directory containing the chroot to be cleaned up.
387 """
388 chroot_dir = os.path.join(buildroot, constants.DEFAULT_CHROOT_DIR)
389 logging.info('Cleaning up chroot at %s', chroot_dir)
390 if os.path.exists(chroot_dir) or os.path.exists(chroot_dir + '.img'):
Don Garrett36650112018-06-28 15:54:34 -0700391 cros_sdk_lib.CleanupChrootMount(chroot_dir, delete=False)
Benjamin Gordonaee36b82018-02-05 14:25:26 -0700392
393
Don Garrettf15d65b2017-04-12 12:39:55 -0700394def ConfigureGlobalEnvironment():
395 """Setup process wide environmental changes."""
Don Garrettf15d65b2017-04-12 12:39:55 -0700396 # Set umask to 022 so files created by buildbot are readable.
397 os.umask(0o22)
398
Don Garrett86fec482017-05-17 18:13:33 -0700399 # These variables can interfere with LANG / locale behavior.
400 unwanted_local_vars = [
401 'LC_ALL', 'LC_CTYPE', 'LC_COLLATE', 'LC_TIME', 'LC_NUMERIC',
402 'LC_MONETARY', 'LC_MESSAGES', 'LC_PAPER', 'LC_NAME', 'LC_ADDRESS',
403 'LC_TELEPHONE', 'LC_MEASUREMENT', 'LC_IDENTIFICATION',
404 ]
405 for v in unwanted_local_vars:
406 os.environ.pop(v, None)
407
408 # This variable is required for repo sync's to work in all cases.
409 os.environ['LANG'] = 'en_US.UTF-8'
410
Don Garrettacbb2392017-05-11 18:27:41 -0700411def _main(argv):
Don Garrettc4114cc2016-11-01 20:04:06 -0700412 """main method of script.
413
414 Args:
415 argv: All command line arguments to pass as list of strings.
416
417 Returns:
418 Return code of cbuildbot as an integer.
419 """
Don Garrettd1d90dd2017-06-13 17:35:52 -0700420 options = PreParseArguments(argv)
Don Garrettd1d90dd2017-06-13 17:35:52 -0700421 branchname = options.branch or 'master'
422 root = options.buildroot
423 buildroot = os.path.join(root, 'repository')
Don Garrettb497f552018-07-09 16:01:13 -0700424 workspace = os.path.join(root, 'workspace')
Don Garretta50bf492017-09-28 18:33:02 -0700425 depot_tools_path = os.path.join(buildroot, constants.DEPOT_TOOLS_SUBPATH)
Don Garrettd1d90dd2017-06-13 17:35:52 -0700426
427 metrics_fields = {
428 'branch_name': branchname,
Don Garrettf0761152017-10-19 19:38:27 -0700429 'build_config': options.build_config_name,
Don Garrettd1d90dd2017-06-13 17:35:52 -0700430 'tryjob': options.remote_trybot,
431 }
Don Garrettf15d65b2017-04-12 12:39:55 -0700432
Dhanya Ganeshc3084772018-09-12 11:54:03 -0600433 #TODO: Move error handling to lib.metrics
434 try:
435 metrics.SetupMetricFields(fields=metrics_fields)
436 except Exception:
437 logging.error('SetupMetricFields Exception:', exc_info=True)
438
Ben Pastenec8e4e792018-05-14 20:20:25 +0000439 # Does the entire build pass or fail.
Dhanya Ganeshf362a462018-08-24 13:45:15 -0600440 with metrics.Presence(METRIC_ACTIVE), \
441 metrics.SuccessCounter(METRIC_COMPLETED) as s_fields:
Don Garrettc4114cc2016-11-01 20:04:06 -0700442
Ben Pastenec8e4e792018-05-14 20:20:25 +0000443 # Preliminary set, mostly command line parsing.
Dhanya Ganeshf362a462018-08-24 13:45:15 -0600444 with metrics.SuccessCounter(METRIC_INVOKED):
Ben Pastenec8e4e792018-05-14 20:20:25 +0000445 if options.enable_buildbot_tags:
446 logging.EnableBuildbotMarkers()
447 ConfigureGlobalEnvironment()
Don Garrett86881cb2017-02-15 15:41:55 -0800448
Ben Pastenec8e4e792018-05-14 20:20:25 +0000449 # Prepare the buildroot with source for the build.
Dhanya Ganeshf362a462018-08-24 13:45:15 -0600450 with metrics.SuccessCounter(METRIC_PREP):
Alex Klein2ab29cc2018-07-19 12:01:00 -0600451 manifest_url = config_lib.GetSiteParams().MANIFEST_INT_URL
Ben Pastenec8e4e792018-05-14 20:20:25 +0000452 repo = repository.RepoRepository(manifest_url, buildroot,
453 branch=branchname,
Don Garrett33872502018-08-03 22:30:40 +0000454 git_cache_dir=options.git_cache_dir)
Ben Pastenec8e4e792018-05-14 20:20:25 +0000455 previous_build_state = GetLastBuildState(root)
Don Garrett86881cb2017-02-15 15:41:55 -0800456
Ben Pastenec8e4e792018-05-14 20:20:25 +0000457 # Clean up the buildroot to a safe state.
Dhanya Ganeshf362a462018-08-24 13:45:15 -0600458 with metrics.SecondsTimer(METRIC_CLEAN):
Ben Pastenec8e4e792018-05-14 20:20:25 +0000459 build_state = GetCurrentBuildState(options, branchname)
460 CleanBuildRoot(root, repo, metrics_fields, build_state)
Don Garrettacbb2392017-05-11 18:27:41 -0700461
Ben Pastenec8e4e792018-05-14 20:20:25 +0000462 # Get a checkout close enough to the branch that cbuildbot can handle it.
463 if options.sync:
Dhanya Ganeshf362a462018-08-24 13:45:15 -0600464 with metrics.SecondsTimer(METRIC_INITIAL):
Ben Pastenec8e4e792018-05-14 20:20:25 +0000465 InitialCheckout(repo)
Don Garrettacbb2392017-05-11 18:27:41 -0700466
Ben Pastenec8e4e792018-05-14 20:20:25 +0000467 # Run cbuildbot inside the full ChromeOS checkout, on the specified branch.
Dhanya Ganeshf362a462018-08-24 13:45:15 -0600468 with metrics.SecondsTimer(METRIC_CBUILDBOT), \
469 metrics.SecondsInstanceTimer(METRIC_CBUILDBOT_INSTANCE):
Ben Pastenec8e4e792018-05-14 20:20:25 +0000470 if previous_build_state.is_valid():
471 argv.append('--previous-build-state')
472 argv.append(base64.b64encode(previous_build_state.to_json()))
Don Garrettb497f552018-07-09 16:01:13 -0700473 argv.extend(['--workspace', workspace])
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600474
Ben Pastenec8e4e792018-05-14 20:20:25 +0000475 result = Cbuildbot(buildroot, depot_tools_path, argv)
476 s_fields['success'] = (result == 0)
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600477
Ben Pastenec8e4e792018-05-14 20:20:25 +0000478 build_state.status = (
479 constants.BUILDER_STATUS_PASSED
480 if result == 0 else constants.BUILDER_STATUS_FAILED)
481 SetLastBuildState(root, build_state)
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600482
Dhanya Ganeshf362a462018-08-24 13:45:15 -0600483 with metrics.SecondsTimer(METRIC_CHROOT_CLEANUP):
Don Garrett91a8cfc2018-06-22 15:39:36 -0700484 CleanupChroot(buildroot)
485
Ben Pastenec8e4e792018-05-14 20:20:25 +0000486 return result
487
Don Garrettacbb2392017-05-11 18:27:41 -0700488
489def main(argv):
Ben Pastenec8e4e792018-05-14 20:20:25 +0000490 # Enable Monarch metrics gathering.
Dhanya Ganeshf362a462018-08-24 13:45:15 -0600491 with ts_mon_config.SetupTsMonGlobalState('cbuildbot_launch',
492 indirect=True):
Ben Pastenec8e4e792018-05-14 20:20:25 +0000493 return _main(argv)