blob: 984550b925ea98234804e2ca39ea84f5de5b04ba [file] [log] [blame]
Xixuan Wu0c76d5b2017-08-30 16:40:17 -07001# Copyright 2017 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Module for tasks triggered by suite scheduler."""
6# pylint: disable=g-bad-import-order
Xixuan Wu244e0ec2018-05-23 14:49:55 -07007# pylint: disable=dangerous-default-value
Xixuan Wu0c76d5b2017-08-30 16:40:17 -07008
9from distutils import version
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070010import logging
11
12import build_lib
Xinan Lin39dcca82019-07-26 18:55:51 -070013import re
Xixuan Wued878ea2019-03-18 15:32:16 -070014import skylab
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070015import task_executor
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070016import tot_manager
17
18# The max lifetime of a suite scheduled by suite scheduler
19_JOB_MAX_RUNTIME_MINS_DEFAULT = 72 * 60
20
21# One kind of formats for RO firmware spec.
22_RELEASE_RO_FIRMWARE_SPEC = 'released_ro_'
23
24
25class SchedulingError(Exception):
26 """Raised to indicate a failure in scheduling a task."""
27
28
29class Task(object):
30 """Represents an entry from the suite_scheduler config file.
31
32 Each entry from the suite_scheduler config file maps one-to-one to a
33 Task. Each instance has enough information to schedule itself.
34 """
35
Po-Hsien Wangdd833072018-08-16 18:09:20 -070036 def __init__(self, task_info, board_family_config={}, tot=None):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070037 """Initialize a task instance.
38
39 Args:
40 task_info: a config_reader.TaskInfo object, which includes:
41 name, name of this task, e.g. 'NightlyPower'
42 suite, the name of the suite to run, e.g. 'graphics_per-day'
43 branch_specs, a pre-vetted iterable of branch specifiers,
44 e.g. ['>=R18', 'factory']
45 pool, the pool of machines to schedule tasks. Default is None.
46 num, the number of devices to shard the test suite. It could
47 be an Integer or None. By default it's None.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070048 board_families, a common separated list of board family to run this
49 task on. Boards belong to one of the board family in this list
50 would be added to task_info.boards.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070051 boards, a comma separated list of boards to run this task on. Default
Po-Hsien Wangdd833072018-08-16 18:09:20 -070052 is None, which allows this task to run on all boards. If same board
53 is specified in 'boards' and 'exclude_boards', we exclude this
54 board.
55 exclude_board_families, a common separated list of board family not to
56 run task on. Boards belong to one of the board family in this list
57 would be added to task_info.exclude_boards.
Po-Hsien Wang6d589732018-05-15 17:19:34 -070058 exclude_boards, a comma separated list of boards not to run this task
59 on. Default is None, which allows this task to run on all boards.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070060 If same board is specified in 'boards' and 'exclude_boards', we
61 exclude this board.
Xixuan Wu89897182019-01-03 15:28:01 -080062 models, a comma separated list of models to run this task on. Default
63 is None, which allows this task to run on all models. If same model
64 is specified in 'models' and 'exclude_models', we exclude this
65 model.
66 exclude_models, a comma separated list of models not to run this task
67 on. Default is None, which allows this task to run on all models.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070068 priority, the string name of a priority from constants.Priorities.
69 timeout, the max lifetime of the suite in hours.
70 cros_build_spec, spec used to determine the ChromeOS build to test
71 with a firmware build, e.g., tot, R41 etc.
72 firmware_rw_build_spec, spec used to determine the firmware RW build
73 test with a ChromeOS build.
74 firmware_ro_build_spec, spec used to determine the firmware RO build
75 test with a ChromeOS build.
76 test_source, the source of test code when firmware will be updated in
77 the test. The value can be 'firmware_rw', 'firmware_ro' or 'cros'.
78 job_retry, set to True to enable job-level retry. Default is False.
Xixuan Wu80531932017-10-12 17:26:51 -070079 no_delay, set to True to raise the priority of this task in task.
80 force, set to True to schedule this suite no matter whether there's
81 duplicate jobs before.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070082 queue, so the suite jobs can start running tests with no waiting.
83 hour, an integer specifying the hour that a nightly run should be
84 triggered, default is set to 21.
85 day, an integer specifying the day of a week that a weekly run should
86 be triggered, default is set to 5 (Saturday).
87 os_type, type of OS, e.g., cros, brillo, android. Default is cros.
88 The argument is required for android/brillo builds.
89 launch_control_branches, comma separated string of launch control
90 branches. The argument is required and only applicable for
91 android/brillo builds.
92 launch_control_targets, comma separated string of build targets for
93 launch control builds. The argument is required and only
94 applicable for android/brillo builds.
95 testbed_dut_count, number of duts to test when using a testbed.
Xixuan Wu83118dd2018-08-27 12:11:35 -070096 board_family_config: A board family dictionary mapping board_family name
97 to its corresponding boards.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070098 tot: The tot manager for checking ToT. If it's None, a new tot_manager
99 instance will be initialized.
100 """
Xixuan Wu5451a662017-10-17 10:57:40 -0700101 # Indicate whether there're suites get pushed into taskqueue for this task.
102 self.is_pushed = False
103
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700104 self.name = task_info.name
105 self.suite = task_info.suite
106 self.branch_specs = task_info.branch_specs
107 self.pool = task_info.pool
108 self.num = task_info.num
109 self.priority = task_info.priority
110 self.timeout = task_info.timeout
111 self.cros_build_spec = task_info.cros_build_spec
112 self.firmware_rw_build_spec = task_info.firmware_rw_build_spec
113 self.firmware_ro_build_spec = task_info.firmware_ro_build_spec
114 self.test_source = task_info.test_source
115 self.job_retry = task_info.job_retry
116 self.no_delay = task_info.no_delay
Xixuan Wu80531932017-10-12 17:26:51 -0700117 self.force = task_info.force
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700118 self.os_type = task_info.os_type
119 self.testbed_dut_count = task_info.testbed_dut_count
Xixuan Wu008ee832017-10-12 16:59:34 -0700120 self.hour = task_info.hour
121 self.day = task_info.day
Craig Bergstrom58263d32018-04-26 14:11:35 -0600122 self.only_hwtest_sanity_required = task_info.only_hwtest_sanity_required
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700123
124 if task_info.lc_branches:
125 self.launch_control_branches = [
126 t.strip() for t in task_info.lc_branches.split(',')]
127 else:
128 self.launch_control_branches = []
129
130 if task_info.lc_targets:
131 self.launch_control_targets = [
132 t.strip() for t in task_info.lc_targets.split(',')]
133 else:
134 self.launch_control_targets = []
135
136 if task_info.boards:
137 self.boards = [t.strip() for t in task_info.boards.split(',')]
138 else:
139 self.boards = []
140
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700141 if task_info.exclude_boards:
142 self.exclude_boards = [
143 t.strip() for t in task_info.exclude_boards.split(',')]
144 else:
145 self.exclude_boards = []
146
Xixuan Wu89897182019-01-03 15:28:01 -0800147 if task_info.models:
148 self.models = [t.strip() for t in task_info.models.split(',')]
149 else:
150 self.models = []
151
152 if task_info.exclude_models:
153 self.exclude_models = [
154 t.strip() for t in task_info.exclude_models.split(',')]
155 else:
156 self.exclude_models = []
157
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700158 if task_info.board_families:
159 # Finetune the allowed boards list with board_families & boards.
160 families = [family.strip()
161 for family in task_info.board_families.split(',')]
162 for family in families:
163 self.boards += board_family_config.get(family, [])
Xixuan Wu89897182019-01-03 15:28:01 -0800164
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700165 if task_info.exclude_board_families:
166 # Finetune the disallowed boards list with exclude_board_families
167 # & exclude_boards.
168 families = [family.strip()
169 for family in task_info.exclude_board_families.split(',')]
170 for family in families:
171 self.exclude_boards += board_family_config.get(family, [])
172
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700173 if tot is None:
174 self.tot_manager = tot_manager.TotMilestoneManager()
175 else:
176 self.tot_manager = tot
177
178 self._set_spec_compare_info()
179
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700180 def schedule(self, launch_control_builds, cros_builds_tuple, configs,
Xixuan Wuc6819012019-05-23 11:34:59 -0700181 build_client):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700182 """Schedule the task by its settings.
183
184 Args:
185 launch_control_builds: the build dict for Android boards, see
186 return value of |get_launch_control_builds|.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600187 cros_builds_tuple: the two-tuple of build dicts for ChromeOS boards,
188 see return value of |get_cros_builds|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700189 configs: a config_reader.Configs object.
Xixuan Wuc6819012019-05-23 11:34:59 -0700190 build_client: a rest_client.BuildBucketBigqueryClient object, to
191 connect Buildbucket Bigquery.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700192
193 Raises:
194 SchedulingError: if tasks that should be scheduled fail to schedule.
Xixuan Wu5451a662017-10-17 10:57:40 -0700195
196 Returns:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700197 A boolean indicator; true if there were any suites related to this
198 task which got pushed into the suites queue.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700199 """
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700200 assert configs.lab_config is not None
Xixuan Wu5451a662017-10-17 10:57:40 -0700201 self.is_pushed = False
202
Craig Bergstrom58263d32018-04-26 14:11:35 -0600203 branch_builds, relaxed_builds = cros_builds_tuple
204 builds_dict = branch_builds
205 if self.only_hwtest_sanity_required:
206 builds_dict = relaxed_builds
207
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700208 logging.info('######## Scheduling task %s ########', self.name)
209 if self.os_type == build_lib.OS_TYPE_CROS:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600210 if not builds_dict:
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700211 logging.info('No CrOS build to run, skip running.')
212 else:
Xixuan Wuc6819012019-05-23 11:34:59 -0700213 self._schedule_cros_builds(builds_dict, configs, build_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700214 else:
215 if not launch_control_builds:
216 logging.info('No Android build to run, skip running.')
217 else:
218 self._schedule_launch_control_builds(launch_control_builds)
219
Xixuan Wu5451a662017-10-17 10:57:40 -0700220 return self.is_pushed
221
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700222 def _set_spec_compare_info(self):
223 """Set branch spec compare info for task for further check."""
224 self._bare_branches = []
225 self._version_equal_constraint = False
226 self._version_gte_constraint = False
227 self._version_lte_constraint = False
228
229 if not self.branch_specs:
230 # Any milestone is OK.
231 self._numeric_constraint = version.LooseVersion('0')
232 else:
233 self._numeric_constraint = None
234 for spec in self.branch_specs:
235 if 'tot' in spec.lower():
236 # Convert spec >=tot-1 to >=RXX.
237 tot_str = spec[spec.index('tot'):]
238 spec = spec.replace(
239 tot_str, self.tot_manager.convert_tot_spec(tot_str))
240
241 if spec.startswith('>='):
242 self._numeric_constraint = version.LooseVersion(
243 spec.lstrip('>=R'))
244 self._version_gte_constraint = True
245 elif spec.startswith('<='):
246 self._numeric_constraint = version.LooseVersion(
247 spec.lstrip('<=R'))
248 self._version_lte_constraint = True
249 elif spec.startswith('=='):
250 self._version_equal_constraint = True
251 self._numeric_constraint = version.LooseVersion(
252 spec.lstrip('==R'))
253 else:
254 self._bare_branches.append(spec)
255
256 def _fits_spec(self, branch):
257 """Check if a branch is deemed OK by this task's branch specs.
258
259 Will return whether a branch 'fits' the specifications stored in this task.
260
261 Examples:
262 Assuming tot=R40
263 t = Task('Name', 'suite', ['factory', '>=tot-1'])
264 t._fits_spec('factory') # True
265 t._fits_spec('40') # True
266 t._fits_spec('38') # False
267 t._fits_spec('firmware') # False
268
269 Args:
270 branch: the branch to check.
271
272 Returns:
273 True if branch 'fits' with stored specs, False otherwise.
274 """
275 if branch in build_lib.BARE_BRANCHES:
276 return branch in self._bare_branches
277
278 if self._numeric_constraint:
279 if self._version_equal_constraint:
280 return version.LooseVersion(branch) == self._numeric_constraint
281 elif self._version_gte_constraint:
282 return version.LooseVersion(branch) >= self._numeric_constraint
283 elif self._version_lte_constraint:
284 return version.LooseVersion(branch) <= self._numeric_constraint
285 else:
286 return version.LooseVersion(branch) >= self._numeric_constraint
287 else:
288 return False
289
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700290 def _get_latest_firmware_build(self, spec, board, build_client):
291 """Get the latest firmware build.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700292
293 Args:
294 spec: a string build spec for RO or RW firmware, eg. firmware,
295 cros. For RO firmware, the value can also be released_ro_X.
296 board: the board against which this task will run suite job.
Xixuan Wuc6819012019-05-23 11:34:59 -0700297 build_client: a rest_client.BuildBucketBigqueryClient object, to
298 connect Buildbucket Bigquery.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700299
300 Returns:
Xinan Lin39dcca82019-07-26 18:55:51 -0700301 A string the latest firmware build. This is the path for the
302 downstream systems to download the built firmware. For "cros"
303 build_type, it is "<board>-release/R<milestone>-<platform>".
304 For "firmware" type, it has the form of
305 "firmware-<board>-1234.56.A-firmwarebranch/RFoo-1.0.0-b123456/<board>".
306
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700307 """
308 build_type = 'release' if spec == 'cros' else spec
Xinan Lin39dcca82019-07-26 18:55:51 -0700309 suffix = ''
Xinan Lin318cf752019-07-19 14:50:23 -0700310 if build_type == 'firmware':
Xinan Lin39dcca82019-07-26 18:55:51 -0700311 artifact = build_client.get_latest_passed_builds_artifact_link_firmware(
312 board)
313 suffix = '/' + board
Xinan Lin318cf752019-07-19 14:50:23 -0700314 else:
Xinan Lin39dcca82019-07-26 18:55:51 -0700315 artifact = build_client.get_latest_passed_builds_artifact_link('%s-%s' %
316 (board, build_type))
317 if artifact is None:
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700318 return None
Xinan Lin39dcca82019-07-26 18:55:51 -0700319
320 ARTIFACT_PATTERN = r'gs://chromeos-image-archive/(?P<firmware_build>.+)'
321 match = re.match(ARTIFACT_PATTERN, artifact)
322 if not match:
323 raise ValueError('Artifact path of firmware is not valid: %s', artifact)
324
325 firmware_build = match.group('firmware_build') + suffix
326 logging.debug('latest firmware build for %s', firmware_build)
327 return firmware_build
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700328
329 def _get_latest_firmware_build_from_lab_config(self, spec, board,
330 lab_config):
331 """Get latest firmware from lab config file.
332
333 Args:
334 spec: a string build spec for RO or RW firmware, eg. firmware,
335 cros. For RO firmware, the value can also be released_ro_X.
336 board: a string board against which this task will run suite job.
337 lab_config: a config.LabConfig object, to read lab config file.
338
339 Returns:
340 A string latest firmware build.
341
342 Raises:
343 ValueError: if no firmware build list is found in lab config file.
344 """
345 index = int(spec[len(_RELEASE_RO_FIRMWARE_SPEC):])
346 released_ro_builds = lab_config.get_firmware_ro_build_list(
347 'RELEASED_RO_BUILDS_%s' % board).split(',')
348 if len(released_ro_builds) < index:
349 raise ValueError('No %dth ro_builds in the lab_config firmware '
350 'list %r' % (index, released_ro_builds))
351
352 logging.debug('Get ro_build: %s', released_ro_builds[index - 1])
353 return released_ro_builds[index - 1]
354
Xixuan Wuc6819012019-05-23 11:34:59 -0700355 def _get_firmware_build(self, spec, board, lab_config, build_client):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700356 """Get the firmware build name to test with ChromeOS build.
357
358 Args:
359 spec: a string build spec for RO or RW firmware, eg. firmware,
360 cros. For RO firmware, the value can also be released_ro_X.
361 board: a string board against which this task will run suite job.
362 lab_config: a config.LabConfig object, to read lab config file.
Xixuan Wuc6819012019-05-23 11:34:59 -0700363 build_client: a rest_client.BuildBucketBigqueryClient object, to
364 connect Buildbucket Bigquery.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700365
366 Returns:
367 A string firmware build name.
368
369 Raises:
370 ValueError: if failing to get firmware from lab config file;
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700371 """
372 if not spec or spec == 'stable':
373 # TODO(crbug.com/577316): Query stable RO firmware.
374 logging.debug('%s RO firmware build is not supported.', spec)
375 return None
376
377 try:
378 if spec.startswith(_RELEASE_RO_FIRMWARE_SPEC):
379 # For RO firmware whose value is released_ro_X, where X is the index of
380 # the list defined in lab config file:
381 # CROS/RELEASED_RO_BUILDS_[board].
382 # For example, for spec 'released_ro_2', and lab config file
383 # CROS/RELEASED_RO_BUILDS_veyron_jerry: build1,build2,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600384 # return firmware RO build should be 'build2'.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700385 return self._get_latest_firmware_build_from_lab_config(
386 spec, board, lab_config)
387 else:
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700388 return self._get_latest_firmware_build(spec, board, build_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700389 except ValueError as e:
390 logging.warning('Failed to get firmware from lab config file'
391 'for spec %s, board %s: %s', spec, board, str(e))
392 return None
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700393
C Shapiro7f24a002017-12-05 14:25:09 -0700394 def _push_suite(
395 self,
396 board=None,
397 model=None,
398 cros_build=None,
399 firmware_rw_build=None,
400 firmware_ro_build=None,
401 test_source_build=None,
402 launch_control_build=None,
Xixuan Wubb74a372018-08-21 17:37:08 -0700403 run_prod_code=False,
Xixuan Wu028f6732019-04-11 14:47:42 -0700404 is_skylab=False,
405 override_pool='',
406 override_qs_account=''):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700407 """Schedule suite job for the task by pushing suites to SuiteQueue.
408
409 Args:
410 board: the board against which this suite job run.
C Shapiro7f24a002017-12-05 14:25:09 -0700411 model: the model name for unibuild.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700412 cros_build: the CrOS build of this suite job.
413 firmware_rw_build: Firmware RW build to run this suite job with.
414 firmware_ro_build: Firmware RO build to run this suite job with.
415 test_source_build: Test source build, used for server-side
416 packaging of this suite job.
417 launch_control_build: the launch control build of this suite job.
418 run_prod_code: If True, the suite will run the test code that lives
419 in prod aka the test code currently on the lab servers. If
420 False, the control files and test code for this suite run will
421 be retrieved from the build artifacts. Default is False.
Xixuan Wubb74a372018-08-21 17:37:08 -0700422 is_skylab: If True, schedule this suite to skylab, otherwise schedule
423 it to AFE. Default is False.
Xixuan Wu028f6732019-04-11 14:47:42 -0700424 override_pool: A string to indicate pool of quota scheduler.
425 override_qs_account: A string of quota scheduler account.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700426 """
427 android_build = None
428 testbed_build = None
429
430 if self.testbed_dut_count:
431 launch_control_build = '%s#%d' % (launch_control_build,
432 self.testbed_dut_count)
433 test_source_build = launch_control_build
434 board = '%s-%d' % (board, self.testbed_dut_count)
435
436 if launch_control_build:
437 if not self.testbed_dut_count:
438 android_build = launch_control_build
439 else:
440 testbed_build = launch_control_build
441
442 suite_job_parameters = {
443 'suite': self.suite,
444 'board': board,
C Shapiro7f24a002017-12-05 14:25:09 -0700445 'model': model,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700446 build_lib.BuildVersionKey.CROS_VERSION: cros_build,
447 build_lib.BuildVersionKey.FW_RW_VERSION: firmware_rw_build,
448 build_lib.BuildVersionKey.FW_RO_VERSION: firmware_ro_build,
449 build_lib.BuildVersionKey.ANDROID_BUILD_VERSION: android_build,
450 build_lib.BuildVersionKey.TESTBED_BUILD_VERSION: testbed_build,
451 'num': self.num,
452 'pool': self.pool,
453 'priority': self.priority,
454 'timeout': self.timeout,
455 'timeout_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
456 'max_runtime_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
Xixuan Wu2ba72652017-09-15 15:49:42 -0700457 'no_wait_for_results': not self.job_retry,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700458 'test_source_build': test_source_build,
459 'job_retry': self.job_retry,
460 'no_delay': self.no_delay,
Xixuan Wu80531932017-10-12 17:26:51 -0700461 'force': self.force,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700462 'run_prod_code': run_prod_code,
Xixuan Wubb74a372018-08-21 17:37:08 -0700463 'is_skylab': is_skylab,
Xixuan Wu028f6732019-04-11 14:47:42 -0700464 'override_pool': override_pool,
465 'override_qs_account': override_qs_account,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700466 }
467
468 task_executor.push(task_executor.SUITES_QUEUE, **suite_job_parameters)
469 logging.info('Pushing task %r into taskqueue', suite_job_parameters)
Xixuan Wu5451a662017-10-17 10:57:40 -0700470 self.is_pushed = True
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700471
Xixuan Wuc6819012019-05-23 11:34:59 -0700472 def _schedule_cros_builds(self, build_dict, configs, build_client):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700473 """Schedule tasks with branch builds.
474
475 Args:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600476 build_dict: the build dict for ChromeOS boards, see return
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700477 value of |build_lib.get_cros_builds_since_date|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700478 configs: A config_reader.Configs object.
Xixuan Wuc6819012019-05-23 11:34:59 -0700479 build_client: a rest_client.BuildBucketBigqueryClient object, to
480 connect Buildbucket Bigquery.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700481 """
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700482 lab_config = configs.lab_config
C Shapiro7f24a002017-12-05 14:25:09 -0700483 models_by_board = lab_config.get_cros_model_map() if lab_config else {}
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700484 for (board, passed_model, build_type,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600485 milestone), manifest in build_dict.iteritems():
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700486 cros_build = str(build_lib.CrOSBuild(board, build_type, milestone,
487 manifest))
488 logging.info('Running %s on %s', self.name, cros_build)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700489 if self.exclude_boards and board in self.exclude_boards:
490 logging.debug('Board %s is in excluded board list: %s',
491 board, self.exclude_boards)
492 continue
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700493
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700494 if self.boards and board not in self.boards:
495 logging.debug('Board %s is not in supported board list: %s',
496 board, self.boards)
497 continue
498
499 # Check the fitness of the build's branch for task
500 branch_build_spec = _pick_branch(build_type, milestone)
501 if not self._fits_spec(branch_build_spec):
502 logging.debug("branch_build spec %s doesn't fit this task's "
503 "requirement: %s", branch_build_spec, self.branch_specs)
504 continue
505
506 firmware_rw_build = None
507 firmware_ro_build = None
508 if self.firmware_rw_build_spec or self.firmware_ro_build_spec:
509 firmware_rw_build = self._get_firmware_build(
Xixuan Wuc6819012019-05-23 11:34:59 -0700510 self.firmware_rw_build_spec, board, lab_config, build_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700511 firmware_ro_build = self._get_firmware_build(
Xixuan Wuc6819012019-05-23 11:34:59 -0700512 self.firmware_ro_build_spec, board, lab_config, build_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700513
514 if not firmware_ro_build and self.firmware_ro_build_spec:
515 logging.debug('No firmware ro build to run, skip running')
516 continue
517
518 if self.test_source == build_lib.BuildType.FIRMWARE_RW:
519 test_source_build = firmware_rw_build
520 else:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700521 # Default test source build to CrOS build if it's not specified.
522 # Past versions chose based on run_prod_code, but we no longer respect
523 # that option and scheduler settings should always set it to False.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700524 test_source_build = cros_build
525
Xixuan Wub4b2f412019-05-03 11:22:31 -0700526 hwtest_board = build_lib.reshape_board(board)
Xixuan Wu1f0be4c2019-03-18 16:53:23 -0700527 is_skylab = skylab.should_run_in_skylab(configs.migration_config,
Xixuan Wub4b2f412019-05-03 11:22:31 -0700528 hwtest_board,
Xixuan Wued878ea2019-03-18 15:32:16 -0700529 passed_model,
Xixuan Wu1e42c752019-03-21 13:41:49 -0700530 self.suite,
531 self.pool)
Xixuan Wu028f6732019-04-11 14:47:42 -0700532 override_pool, override_qs_account = skylab.get_override_info(
533 configs.migration_config,
Xixuan Wub4b2f412019-05-03 11:22:31 -0700534 hwtest_board,
Xixuan Wu028f6732019-04-11 14:47:42 -0700535 passed_model,
536 self.suite,
537 self.pool)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000538 models = models_by_board.get(board, [None])
C Shapiro7f24a002017-12-05 14:25:09 -0700539
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000540 for model in models:
541 if ((passed_model is not None and model == passed_model) or
542 passed_model is None):
Xixuan Wua41efa22019-05-17 14:28:04 -0700543 full_model_name = '%s_%s' % (board, model)
544 # Respect exclude first.
545 if self.exclude_models and full_model_name in self.exclude_models:
546 logging.debug("Skip model %s as it's in exclude model list %s",
547 model, self.exclude_models)
548 continue
549
550 if self.models and full_model_name not in self.models:
551 logging.debug("Skip model %s as it's not in support model list %s",
552 model, self.models)
553 continue
554
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000555 self._push_suite(
Xixuan Wub4b2f412019-05-03 11:22:31 -0700556 board=hwtest_board,
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000557 model=model,
558 cros_build=cros_build,
559 firmware_rw_build=firmware_rw_build,
560 firmware_ro_build=firmware_ro_build,
561 test_source_build=test_source_build,
Xixuan Wu028f6732019-04-11 14:47:42 -0700562 is_skylab=is_skylab,
563 override_pool=override_pool,
564 override_qs_account=override_qs_account)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700565
566 def _schedule_launch_control_builds(self, launch_control_builds):
567 """Schedule tasks with launch control builds.
568
569 Args:
570 launch_control_builds: the build dict for Android boards.
571 """
572 for board, launch_control_build in launch_control_builds.iteritems():
573 logging.debug('Running %s on %s', self.name, board)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700574 if self.exclude_boards and board in self.exclude_boards:
575 logging.debug('Board %s is in excluded board list: %s',
576 board, self.exclude_boards)
577 continue
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700578 if self.boards and board not in self.boards:
579 logging.debug('Board %s is not in supported board list: %s',
580 board, self.boards)
581 continue
582
583 for android_build in launch_control_build:
584 if not any([branch in android_build
585 for branch in self.launch_control_branches]):
586 logging.debug('Branch %s is not required to run for task '
587 '%s', android_build, self.name)
588 continue
589
590 self._push_suite(board=board,
591 test_source_build=android_build,
592 launch_control_build=android_build)
593
594
595def _pick_branch(build_type, milestone):
596 """Select branch based on build type.
597
598 If the build_type is a bare branch, return build_type as the build spec.
599 If the build_type is a normal CrOS branch, return milestone as the build
600 spec.
601
602 Args:
603 build_type: a string builder name, like 'release'.
604 milestone: a string milestone, like '55'.
605
606 Returns:
607 A string milestone if build_type represents CrOS build, otherwise
608 return build_type.
609 """
610 return build_type if build_type in build_lib.BARE_BRANCHES else milestone