blob: c56b0f303d2881f8e1ab9d365a2d8d472eec940a [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.
C Shapiro09108252019-08-01 14:52:52 -050068 any_model, set to True to not pass the model parameter and allow
69 a test suite to run any/all models available for testing.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070070 priority, the string name of a priority from constants.Priorities.
71 timeout, the max lifetime of the suite in hours.
72 cros_build_spec, spec used to determine the ChromeOS build to test
73 with a firmware build, e.g., tot, R41 etc.
74 firmware_rw_build_spec, spec used to determine the firmware RW build
75 test with a ChromeOS build.
76 firmware_ro_build_spec, spec used to determine the firmware RO build
77 test with a ChromeOS build.
78 test_source, the source of test code when firmware will be updated in
79 the test. The value can be 'firmware_rw', 'firmware_ro' or 'cros'.
80 job_retry, set to True to enable job-level retry. Default is False.
Xixuan Wu80531932017-10-12 17:26:51 -070081 no_delay, set to True to raise the priority of this task in task.
82 force, set to True to schedule this suite no matter whether there's
83 duplicate jobs before.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070084 queue, so the suite jobs can start running tests with no waiting.
85 hour, an integer specifying the hour that a nightly run should be
86 triggered, default is set to 21.
87 day, an integer specifying the day of a week that a weekly run should
88 be triggered, default is set to 5 (Saturday).
89 os_type, type of OS, e.g., cros, brillo, android. Default is cros.
90 The argument is required for android/brillo builds.
91 launch_control_branches, comma separated string of launch control
92 branches. The argument is required and only applicable for
93 android/brillo builds.
94 launch_control_targets, comma separated string of build targets for
95 launch control builds. The argument is required and only
96 applicable for android/brillo builds.
97 testbed_dut_count, number of duts to test when using a testbed.
Xixuan Wu83118dd2018-08-27 12:11:35 -070098 board_family_config: A board family dictionary mapping board_family name
99 to its corresponding boards.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700100 tot: The tot manager for checking ToT. If it's None, a new tot_manager
101 instance will be initialized.
102 """
Xixuan Wu5451a662017-10-17 10:57:40 -0700103 # Indicate whether there're suites get pushed into taskqueue for this task.
104 self.is_pushed = False
105
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700106 self.name = task_info.name
107 self.suite = task_info.suite
108 self.branch_specs = task_info.branch_specs
109 self.pool = task_info.pool
110 self.num = task_info.num
111 self.priority = task_info.priority
112 self.timeout = task_info.timeout
113 self.cros_build_spec = task_info.cros_build_spec
114 self.firmware_rw_build_spec = task_info.firmware_rw_build_spec
115 self.firmware_ro_build_spec = task_info.firmware_ro_build_spec
116 self.test_source = task_info.test_source
117 self.job_retry = task_info.job_retry
118 self.no_delay = task_info.no_delay
Xixuan Wu80531932017-10-12 17:26:51 -0700119 self.force = task_info.force
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700120 self.os_type = task_info.os_type
Xinan Lin3ba18a02019-08-13 15:44:55 -0700121 self.frontdoor = task_info.frontdoor
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700122 self.testbed_dut_count = task_info.testbed_dut_count
Xixuan Wu008ee832017-10-12 16:59:34 -0700123 self.hour = task_info.hour
124 self.day = task_info.day
Craig Bergstrom58263d32018-04-26 14:11:35 -0600125 self.only_hwtest_sanity_required = task_info.only_hwtest_sanity_required
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700126
127 if task_info.lc_branches:
128 self.launch_control_branches = [
129 t.strip() for t in task_info.lc_branches.split(',')]
130 else:
131 self.launch_control_branches = []
132
133 if task_info.lc_targets:
134 self.launch_control_targets = [
135 t.strip() for t in task_info.lc_targets.split(',')]
136 else:
137 self.launch_control_targets = []
138
139 if task_info.boards:
140 self.boards = [t.strip() for t in task_info.boards.split(',')]
141 else:
142 self.boards = []
143
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700144 if task_info.exclude_boards:
145 self.exclude_boards = [
146 t.strip() for t in task_info.exclude_boards.split(',')]
147 else:
148 self.exclude_boards = []
149
Xixuan Wu89897182019-01-03 15:28:01 -0800150 if task_info.models:
151 self.models = [t.strip() for t in task_info.models.split(',')]
152 else:
153 self.models = []
154
155 if task_info.exclude_models:
156 self.exclude_models = [
157 t.strip() for t in task_info.exclude_models.split(',')]
158 else:
159 self.exclude_models = []
160
C Shapiro09108252019-08-01 14:52:52 -0500161 self.any_model = task_info.any_model
162
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700163 if task_info.board_families:
164 # Finetune the allowed boards list with board_families & boards.
165 families = [family.strip()
166 for family in task_info.board_families.split(',')]
167 for family in families:
168 self.boards += board_family_config.get(family, [])
Xixuan Wu89897182019-01-03 15:28:01 -0800169
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700170 if task_info.exclude_board_families:
171 # Finetune the disallowed boards list with exclude_board_families
172 # & exclude_boards.
173 families = [family.strip()
174 for family in task_info.exclude_board_families.split(',')]
175 for family in families:
176 self.exclude_boards += board_family_config.get(family, [])
177
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700178 if tot is None:
179 self.tot_manager = tot_manager.TotMilestoneManager()
180 else:
181 self.tot_manager = tot
182
183 self._set_spec_compare_info()
184
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700185 def schedule(self, launch_control_builds, cros_builds_tuple, configs,
Xixuan Wuc6819012019-05-23 11:34:59 -0700186 build_client):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700187 """Schedule the task by its settings.
188
189 Args:
190 launch_control_builds: the build dict for Android boards, see
191 return value of |get_launch_control_builds|.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600192 cros_builds_tuple: the two-tuple of build dicts for ChromeOS boards,
193 see return value of |get_cros_builds|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700194 configs: a config_reader.Configs object.
Xixuan Wuc6819012019-05-23 11:34:59 -0700195 build_client: a rest_client.BuildBucketBigqueryClient object, to
196 connect Buildbucket Bigquery.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700197
198 Raises:
199 SchedulingError: if tasks that should be scheduled fail to schedule.
Xixuan Wu5451a662017-10-17 10:57:40 -0700200
201 Returns:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700202 A boolean indicator; true if there were any suites related to this
203 task which got pushed into the suites queue.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700204 """
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700205 assert configs.lab_config is not None
Xixuan Wu5451a662017-10-17 10:57:40 -0700206 self.is_pushed = False
207
Craig Bergstrom58263d32018-04-26 14:11:35 -0600208 branch_builds, relaxed_builds = cros_builds_tuple
209 builds_dict = branch_builds
210 if self.only_hwtest_sanity_required:
211 builds_dict = relaxed_builds
212
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700213 logging.info('######## Scheduling task %s ########', self.name)
214 if self.os_type == build_lib.OS_TYPE_CROS:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600215 if not builds_dict:
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700216 logging.info('No CrOS build to run, skip running.')
217 else:
Xixuan Wuc6819012019-05-23 11:34:59 -0700218 self._schedule_cros_builds(builds_dict, configs, build_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700219 else:
220 if not launch_control_builds:
221 logging.info('No Android build to run, skip running.')
222 else:
223 self._schedule_launch_control_builds(launch_control_builds)
224
Xixuan Wu5451a662017-10-17 10:57:40 -0700225 return self.is_pushed
226
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700227 def _set_spec_compare_info(self):
228 """Set branch spec compare info for task for further check."""
229 self._bare_branches = []
230 self._version_equal_constraint = False
231 self._version_gte_constraint = False
232 self._version_lte_constraint = False
233
234 if not self.branch_specs:
235 # Any milestone is OK.
236 self._numeric_constraint = version.LooseVersion('0')
237 else:
238 self._numeric_constraint = None
239 for spec in self.branch_specs:
240 if 'tot' in spec.lower():
241 # Convert spec >=tot-1 to >=RXX.
242 tot_str = spec[spec.index('tot'):]
243 spec = spec.replace(
244 tot_str, self.tot_manager.convert_tot_spec(tot_str))
245
246 if spec.startswith('>='):
247 self._numeric_constraint = version.LooseVersion(
248 spec.lstrip('>=R'))
249 self._version_gte_constraint = True
250 elif spec.startswith('<='):
251 self._numeric_constraint = version.LooseVersion(
252 spec.lstrip('<=R'))
253 self._version_lte_constraint = True
254 elif spec.startswith('=='):
255 self._version_equal_constraint = True
256 self._numeric_constraint = version.LooseVersion(
257 spec.lstrip('==R'))
258 else:
259 self._bare_branches.append(spec)
260
261 def _fits_spec(self, branch):
262 """Check if a branch is deemed OK by this task's branch specs.
263
264 Will return whether a branch 'fits' the specifications stored in this task.
265
266 Examples:
267 Assuming tot=R40
268 t = Task('Name', 'suite', ['factory', '>=tot-1'])
269 t._fits_spec('factory') # True
270 t._fits_spec('40') # True
271 t._fits_spec('38') # False
272 t._fits_spec('firmware') # False
273
274 Args:
275 branch: the branch to check.
276
277 Returns:
278 True if branch 'fits' with stored specs, False otherwise.
279 """
280 if branch in build_lib.BARE_BRANCHES:
281 return branch in self._bare_branches
282
283 if self._numeric_constraint:
284 if self._version_equal_constraint:
285 return version.LooseVersion(branch) == self._numeric_constraint
286 elif self._version_gte_constraint:
287 return version.LooseVersion(branch) >= self._numeric_constraint
288 elif self._version_lte_constraint:
289 return version.LooseVersion(branch) <= self._numeric_constraint
290 else:
291 return version.LooseVersion(branch) >= self._numeric_constraint
292 else:
293 return False
294
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700295 def _get_latest_firmware_build(self, spec, board, build_client):
296 """Get the latest firmware build.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700297
298 Args:
299 spec: a string build spec for RO or RW firmware, eg. firmware,
300 cros. For RO firmware, the value can also be released_ro_X.
301 board: the board against which this task will run suite job.
Xixuan Wuc6819012019-05-23 11:34:59 -0700302 build_client: a rest_client.BuildBucketBigqueryClient object, to
303 connect Buildbucket Bigquery.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700304
305 Returns:
Xinan Lin39dcca82019-07-26 18:55:51 -0700306 A string the latest firmware build. This is the path for the
307 downstream systems to download the built firmware. For "cros"
308 build_type, it is "<board>-release/R<milestone>-<platform>".
309 For "firmware" type, it has the form of
310 "firmware-<board>-1234.56.A-firmwarebranch/RFoo-1.0.0-b123456/<board>".
311
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700312 """
313 build_type = 'release' if spec == 'cros' else spec
Xinan Lin39dcca82019-07-26 18:55:51 -0700314 suffix = ''
Xinan Lin318cf752019-07-19 14:50:23 -0700315 if build_type == 'firmware':
Xinan Lin39dcca82019-07-26 18:55:51 -0700316 artifact = build_client.get_latest_passed_builds_artifact_link_firmware(
317 board)
318 suffix = '/' + board
Xinan Lin318cf752019-07-19 14:50:23 -0700319 else:
Xinan Lin39dcca82019-07-26 18:55:51 -0700320 artifact = build_client.get_latest_passed_builds_artifact_link('%s-%s' %
321 (board, build_type))
322 if artifact is None:
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700323 return None
Xinan Lin39dcca82019-07-26 18:55:51 -0700324
325 ARTIFACT_PATTERN = r'gs://chromeos-image-archive/(?P<firmware_build>.+)'
326 match = re.match(ARTIFACT_PATTERN, artifact)
327 if not match:
328 raise ValueError('Artifact path of firmware is not valid: %s', artifact)
329
330 firmware_build = match.group('firmware_build') + suffix
331 logging.debug('latest firmware build for %s', firmware_build)
332 return firmware_build
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700333
334 def _get_latest_firmware_build_from_lab_config(self, spec, board,
335 lab_config):
336 """Get latest firmware from lab config file.
337
338 Args:
339 spec: a string build spec for RO or RW firmware, eg. firmware,
340 cros. For RO firmware, the value can also be released_ro_X.
341 board: a string board against which this task will run suite job.
342 lab_config: a config.LabConfig object, to read lab config file.
343
344 Returns:
345 A string latest firmware build.
346
347 Raises:
348 ValueError: if no firmware build list is found in lab config file.
349 """
350 index = int(spec[len(_RELEASE_RO_FIRMWARE_SPEC):])
351 released_ro_builds = lab_config.get_firmware_ro_build_list(
352 'RELEASED_RO_BUILDS_%s' % board).split(',')
353 if len(released_ro_builds) < index:
354 raise ValueError('No %dth ro_builds in the lab_config firmware '
355 'list %r' % (index, released_ro_builds))
356
357 logging.debug('Get ro_build: %s', released_ro_builds[index - 1])
358 return released_ro_builds[index - 1]
359
Xixuan Wuc6819012019-05-23 11:34:59 -0700360 def _get_firmware_build(self, spec, board, lab_config, build_client):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700361 """Get the firmware build name to test with ChromeOS build.
362
363 Args:
364 spec: a string build spec for RO or RW firmware, eg. firmware,
365 cros. For RO firmware, the value can also be released_ro_X.
366 board: a string board against which this task will run suite job.
367 lab_config: a config.LabConfig object, to read lab config file.
Xixuan Wuc6819012019-05-23 11:34:59 -0700368 build_client: a rest_client.BuildBucketBigqueryClient object, to
369 connect Buildbucket Bigquery.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700370
371 Returns:
372 A string firmware build name.
373
374 Raises:
375 ValueError: if failing to get firmware from lab config file;
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700376 """
377 if not spec or spec == 'stable':
378 # TODO(crbug.com/577316): Query stable RO firmware.
379 logging.debug('%s RO firmware build is not supported.', spec)
380 return None
381
382 try:
383 if spec.startswith(_RELEASE_RO_FIRMWARE_SPEC):
384 # For RO firmware whose value is released_ro_X, where X is the index of
385 # the list defined in lab config file:
386 # CROS/RELEASED_RO_BUILDS_[board].
387 # For example, for spec 'released_ro_2', and lab config file
388 # CROS/RELEASED_RO_BUILDS_veyron_jerry: build1,build2,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600389 # return firmware RO build should be 'build2'.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700390 return self._get_latest_firmware_build_from_lab_config(
391 spec, board, lab_config)
392 else:
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700393 return self._get_latest_firmware_build(spec, board, build_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700394 except ValueError as e:
395 logging.warning('Failed to get firmware from lab config file'
396 'for spec %s, board %s: %s', spec, board, str(e))
397 return None
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700398
C Shapiro7f24a002017-12-05 14:25:09 -0700399 def _push_suite(
400 self,
401 board=None,
402 model=None,
403 cros_build=None,
404 firmware_rw_build=None,
405 firmware_ro_build=None,
406 test_source_build=None,
407 launch_control_build=None,
Xixuan Wubb74a372018-08-21 17:37:08 -0700408 run_prod_code=False,
Xixuan Wu028f6732019-04-11 14:47:42 -0700409 is_skylab=False,
410 override_pool='',
411 override_qs_account=''):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700412 """Schedule suite job for the task by pushing suites to SuiteQueue.
413
414 Args:
415 board: the board against which this suite job run.
C Shapiro7f24a002017-12-05 14:25:09 -0700416 model: the model name for unibuild.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700417 cros_build: the CrOS build of this suite job.
418 firmware_rw_build: Firmware RW build to run this suite job with.
419 firmware_ro_build: Firmware RO build to run this suite job with.
420 test_source_build: Test source build, used for server-side
421 packaging of this suite job.
422 launch_control_build: the launch control build of this suite job.
423 run_prod_code: If True, the suite will run the test code that lives
424 in prod aka the test code currently on the lab servers. If
425 False, the control files and test code for this suite run will
426 be retrieved from the build artifacts. Default is False.
Xixuan Wubb74a372018-08-21 17:37:08 -0700427 is_skylab: If True, schedule this suite to skylab, otherwise schedule
428 it to AFE. Default is False.
Xixuan Wu028f6732019-04-11 14:47:42 -0700429 override_pool: A string to indicate pool of quota scheduler.
430 override_qs_account: A string of quota scheduler account.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700431 """
432 android_build = None
433 testbed_build = None
434
435 if self.testbed_dut_count:
436 launch_control_build = '%s#%d' % (launch_control_build,
437 self.testbed_dut_count)
438 test_source_build = launch_control_build
439 board = '%s-%d' % (board, self.testbed_dut_count)
440
441 if launch_control_build:
442 if not self.testbed_dut_count:
443 android_build = launch_control_build
444 else:
445 testbed_build = launch_control_build
446
447 suite_job_parameters = {
448 'suite': self.suite,
449 'board': board,
C Shapiro7f24a002017-12-05 14:25:09 -0700450 'model': model,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700451 build_lib.BuildVersionKey.CROS_VERSION: cros_build,
452 build_lib.BuildVersionKey.FW_RW_VERSION: firmware_rw_build,
453 build_lib.BuildVersionKey.FW_RO_VERSION: firmware_ro_build,
454 build_lib.BuildVersionKey.ANDROID_BUILD_VERSION: android_build,
455 build_lib.BuildVersionKey.TESTBED_BUILD_VERSION: testbed_build,
456 'num': self.num,
457 'pool': self.pool,
458 'priority': self.priority,
459 'timeout': self.timeout,
460 'timeout_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
461 'max_runtime_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
Xixuan Wu2ba72652017-09-15 15:49:42 -0700462 'no_wait_for_results': not self.job_retry,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700463 'test_source_build': test_source_build,
464 'job_retry': self.job_retry,
465 'no_delay': self.no_delay,
Xixuan Wu80531932017-10-12 17:26:51 -0700466 'force': self.force,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700467 'run_prod_code': run_prod_code,
Xixuan Wubb74a372018-08-21 17:37:08 -0700468 'is_skylab': is_skylab,
Xinan Lin6e097382019-08-27 18:43:35 -0700469 'is_frontdoor': self.frontdoor,
Xixuan Wu028f6732019-04-11 14:47:42 -0700470 'override_pool': override_pool,
471 'override_qs_account': override_qs_account,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700472 }
473
474 task_executor.push(task_executor.SUITES_QUEUE, **suite_job_parameters)
475 logging.info('Pushing task %r into taskqueue', suite_job_parameters)
Xixuan Wu5451a662017-10-17 10:57:40 -0700476 self.is_pushed = True
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700477
Xixuan Wuc6819012019-05-23 11:34:59 -0700478 def _schedule_cros_builds(self, build_dict, configs, build_client):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700479 """Schedule tasks with branch builds.
480
481 Args:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600482 build_dict: the build dict for ChromeOS boards, see return
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700483 value of |build_lib.get_cros_builds_since_date|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700484 configs: A config_reader.Configs object.
Xixuan Wuc6819012019-05-23 11:34:59 -0700485 build_client: a rest_client.BuildBucketBigqueryClient object, to
486 connect Buildbucket Bigquery.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700487 """
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700488 lab_config = configs.lab_config
C Shapiro7f24a002017-12-05 14:25:09 -0700489 models_by_board = lab_config.get_cros_model_map() if lab_config else {}
C Shapiro09108252019-08-01 14:52:52 -0500490 model_agnostic_cros_builds = set()
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700491 for (board, passed_model, build_type,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600492 milestone), manifest in build_dict.iteritems():
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700493 cros_build = str(build_lib.CrOSBuild(board, build_type, milestone,
494 manifest))
495 logging.info('Running %s on %s', self.name, cros_build)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700496 if self.exclude_boards and board in self.exclude_boards:
497 logging.debug('Board %s is in excluded board list: %s',
498 board, self.exclude_boards)
499 continue
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700500
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700501 if self.boards and board not in self.boards:
502 logging.debug('Board %s is not in supported board list: %s',
503 board, self.boards)
504 continue
505
506 # Check the fitness of the build's branch for task
507 branch_build_spec = _pick_branch(build_type, milestone)
508 if not self._fits_spec(branch_build_spec):
509 logging.debug("branch_build spec %s doesn't fit this task's "
510 "requirement: %s", branch_build_spec, self.branch_specs)
511 continue
512
513 firmware_rw_build = None
514 firmware_ro_build = None
515 if self.firmware_rw_build_spec or self.firmware_ro_build_spec:
516 firmware_rw_build = self._get_firmware_build(
Xixuan Wuc6819012019-05-23 11:34:59 -0700517 self.firmware_rw_build_spec, board, lab_config, build_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700518 firmware_ro_build = self._get_firmware_build(
Xixuan Wuc6819012019-05-23 11:34:59 -0700519 self.firmware_ro_build_spec, board, lab_config, build_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700520
521 if not firmware_ro_build and self.firmware_ro_build_spec:
522 logging.debug('No firmware ro build to run, skip running')
523 continue
524
525 if self.test_source == build_lib.BuildType.FIRMWARE_RW:
526 test_source_build = firmware_rw_build
527 else:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700528 # Default test source build to CrOS build if it's not specified.
529 # Past versions chose based on run_prod_code, but we no longer respect
530 # that option and scheduler settings should always set it to False.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700531 test_source_build = cros_build
532
Xixuan Wub4b2f412019-05-03 11:22:31 -0700533 hwtest_board = build_lib.reshape_board(board)
Xixuan Wu1f0be4c2019-03-18 16:53:23 -0700534 is_skylab = skylab.should_run_in_skylab(configs.migration_config,
Xixuan Wub4b2f412019-05-03 11:22:31 -0700535 hwtest_board,
Xixuan Wued878ea2019-03-18 15:32:16 -0700536 passed_model,
Xixuan Wu1e42c752019-03-21 13:41:49 -0700537 self.suite,
538 self.pool)
Xixuan Wu028f6732019-04-11 14:47:42 -0700539 override_pool, override_qs_account = skylab.get_override_info(
540 configs.migration_config,
Xixuan Wub4b2f412019-05-03 11:22:31 -0700541 hwtest_board,
Xixuan Wu028f6732019-04-11 14:47:42 -0700542 passed_model,
543 self.suite,
544 self.pool)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000545 models = models_by_board.get(board, [None])
C Shapiro7f24a002017-12-05 14:25:09 -0700546
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000547 for model in models:
548 if ((passed_model is not None and model == passed_model) or
549 passed_model is None):
Xixuan Wua41efa22019-05-17 14:28:04 -0700550 full_model_name = '%s_%s' % (board, model)
551 # Respect exclude first.
552 if self.exclude_models and full_model_name in self.exclude_models:
553 logging.debug("Skip model %s as it's in exclude model list %s",
554 model, self.exclude_models)
555 continue
556
557 if self.models and full_model_name not in self.models:
558 logging.debug("Skip model %s as it's not in support model list %s",
559 model, self.models)
560 continue
561
C Shapiro09108252019-08-01 14:52:52 -0500562 explicit_model = model
563
564 if self.any_model:
Xinan Lin3ba18a02019-08-13 15:44:55 -0700565 explicit_model = None
C Shapiro09108252019-08-01 14:52:52 -0500566 unique_build = str(cros_build)
567 if unique_build in model_agnostic_cros_builds:
568 # Skip since we've already run with no explicit model set.
569 continue
570 model_agnostic_cros_builds.add(unique_build)
571
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000572 self._push_suite(
Xixuan Wub4b2f412019-05-03 11:22:31 -0700573 board=hwtest_board,
C Shapiro09108252019-08-01 14:52:52 -0500574 model=explicit_model,
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000575 cros_build=cros_build,
576 firmware_rw_build=firmware_rw_build,
577 firmware_ro_build=firmware_ro_build,
578 test_source_build=test_source_build,
Xixuan Wu028f6732019-04-11 14:47:42 -0700579 is_skylab=is_skylab,
580 override_pool=override_pool,
581 override_qs_account=override_qs_account)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700582
583 def _schedule_launch_control_builds(self, launch_control_builds):
584 """Schedule tasks with launch control builds.
585
586 Args:
587 launch_control_builds: the build dict for Android boards.
588 """
589 for board, launch_control_build in launch_control_builds.iteritems():
590 logging.debug('Running %s on %s', self.name, board)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700591 if self.exclude_boards and board in self.exclude_boards:
592 logging.debug('Board %s is in excluded board list: %s',
593 board, self.exclude_boards)
594 continue
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700595 if self.boards and board not in self.boards:
596 logging.debug('Board %s is not in supported board list: %s',
597 board, self.boards)
598 continue
599
600 for android_build in launch_control_build:
601 if not any([branch in android_build
602 for branch in self.launch_control_branches]):
603 logging.debug('Branch %s is not required to run for task '
604 '%s', android_build, self.name)
605 continue
606
607 self._push_suite(board=board,
608 test_source_build=android_build,
609 launch_control_build=android_build)
610
611
612def _pick_branch(build_type, milestone):
613 """Select branch based on build type.
614
615 If the build_type is a bare branch, return build_type as the build spec.
616 If the build_type is a normal CrOS branch, return milestone as the build
617 spec.
618
619 Args:
620 build_type: a string builder name, like 'release'.
621 milestone: a string milestone, like '55'.
622
623 Returns:
624 A string milestone if build_type represents CrOS build, otherwise
625 return build_type.
626 """
627 return build_type if build_type in build_lib.BARE_BRANCHES else milestone