blob: 717589806847f168decec76061db0f56738b347e [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
10import MySQLdb
11import logging
12
13import build_lib
14import task_executor
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070015import tot_manager
16
17# The max lifetime of a suite scheduled by suite scheduler
18_JOB_MAX_RUNTIME_MINS_DEFAULT = 72 * 60
19
20# One kind of formats for RO firmware spec.
21_RELEASE_RO_FIRMWARE_SPEC = 'released_ro_'
22
23
24class SchedulingError(Exception):
25 """Raised to indicate a failure in scheduling a task."""
26
27
28class Task(object):
29 """Represents an entry from the suite_scheduler config file.
30
31 Each entry from the suite_scheduler config file maps one-to-one to a
32 Task. Each instance has enough information to schedule itself.
33 """
34
Po-Hsien Wangdd833072018-08-16 18:09:20 -070035 def __init__(self, task_info, board_family_config={}, tot=None):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070036 """Initialize a task instance.
37
38 Args:
39 task_info: a config_reader.TaskInfo object, which includes:
40 name, name of this task, e.g. 'NightlyPower'
41 suite, the name of the suite to run, e.g. 'graphics_per-day'
42 branch_specs, a pre-vetted iterable of branch specifiers,
43 e.g. ['>=R18', 'factory']
44 pool, the pool of machines to schedule tasks. Default is None.
45 num, the number of devices to shard the test suite. It could
46 be an Integer or None. By default it's None.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070047 board_families, a common separated list of board family to run this
48 task on. Boards belong to one of the board family in this list
49 would be added to task_info.boards.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070050 boards, a comma separated list of boards to run this task on. Default
Po-Hsien Wangdd833072018-08-16 18:09:20 -070051 is None, which allows this task to run on all boards. If same board
52 is specified in 'boards' and 'exclude_boards', we exclude this
53 board.
54 exclude_board_families, a common separated list of board family not to
55 run task on. Boards belong to one of the board family in this list
56 would be added to task_info.exclude_boards.
Po-Hsien Wang6d589732018-05-15 17:19:34 -070057 exclude_boards, a comma separated list of boards not to run this task
58 on. Default is None, which allows this task to run on all boards.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070059 If same board is specified in 'boards' and 'exclude_boards', we
60 exclude this board.
Xixuan Wu89897182019-01-03 15:28:01 -080061 models, a comma separated list of models to run this task on. Default
62 is None, which allows this task to run on all models. If same model
63 is specified in 'models' and 'exclude_models', we exclude this
64 model.
65 exclude_models, a comma separated list of models not to run this task
66 on. Default is None, which allows this task to run on all models.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070067 priority, the string name of a priority from constants.Priorities.
68 timeout, the max lifetime of the suite in hours.
69 cros_build_spec, spec used to determine the ChromeOS build to test
70 with a firmware build, e.g., tot, R41 etc.
71 firmware_rw_build_spec, spec used to determine the firmware RW build
72 test with a ChromeOS build.
73 firmware_ro_build_spec, spec used to determine the firmware RO build
74 test with a ChromeOS build.
75 test_source, the source of test code when firmware will be updated in
76 the test. The value can be 'firmware_rw', 'firmware_ro' or 'cros'.
77 job_retry, set to True to enable job-level retry. Default is False.
Xixuan Wu80531932017-10-12 17:26:51 -070078 no_delay, set to True to raise the priority of this task in task.
79 force, set to True to schedule this suite no matter whether there's
80 duplicate jobs before.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070081 queue, so the suite jobs can start running tests with no waiting.
82 hour, an integer specifying the hour that a nightly run should be
83 triggered, default is set to 21.
84 day, an integer specifying the day of a week that a weekly run should
85 be triggered, default is set to 5 (Saturday).
86 os_type, type of OS, e.g., cros, brillo, android. Default is cros.
87 The argument is required for android/brillo builds.
88 launch_control_branches, comma separated string of launch control
89 branches. The argument is required and only applicable for
90 android/brillo builds.
91 launch_control_targets, comma separated string of build targets for
92 launch control builds. The argument is required and only
93 applicable for android/brillo builds.
94 testbed_dut_count, number of duts to test when using a testbed.
Xixuan Wu83118dd2018-08-27 12:11:35 -070095 board_family_config: A board family dictionary mapping board_family name
96 to its corresponding boards.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070097 tot: The tot manager for checking ToT. If it's None, a new tot_manager
98 instance will be initialized.
99 """
Xixuan Wu5451a662017-10-17 10:57:40 -0700100 # Indicate whether there're suites get pushed into taskqueue for this task.
101 self.is_pushed = False
102
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700103 self.name = task_info.name
104 self.suite = task_info.suite
105 self.branch_specs = task_info.branch_specs
106 self.pool = task_info.pool
107 self.num = task_info.num
108 self.priority = task_info.priority
109 self.timeout = task_info.timeout
110 self.cros_build_spec = task_info.cros_build_spec
111 self.firmware_rw_build_spec = task_info.firmware_rw_build_spec
112 self.firmware_ro_build_spec = task_info.firmware_ro_build_spec
113 self.test_source = task_info.test_source
114 self.job_retry = task_info.job_retry
115 self.no_delay = task_info.no_delay
Xixuan Wu80531932017-10-12 17:26:51 -0700116 self.force = task_info.force
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700117 self.os_type = task_info.os_type
118 self.testbed_dut_count = task_info.testbed_dut_count
Xixuan Wu008ee832017-10-12 16:59:34 -0700119 self.hour = task_info.hour
120 self.day = task_info.day
Craig Bergstrom58263d32018-04-26 14:11:35 -0600121 self.only_hwtest_sanity_required = task_info.only_hwtest_sanity_required
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700122
123 if task_info.lc_branches:
124 self.launch_control_branches = [
125 t.strip() for t in task_info.lc_branches.split(',')]
126 else:
127 self.launch_control_branches = []
128
129 if task_info.lc_targets:
130 self.launch_control_targets = [
131 t.strip() for t in task_info.lc_targets.split(',')]
132 else:
133 self.launch_control_targets = []
134
135 if task_info.boards:
136 self.boards = [t.strip() for t in task_info.boards.split(',')]
137 else:
138 self.boards = []
139
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700140 if task_info.exclude_boards:
141 self.exclude_boards = [
142 t.strip() for t in task_info.exclude_boards.split(',')]
143 else:
144 self.exclude_boards = []
145
Xixuan Wu89897182019-01-03 15:28:01 -0800146 if task_info.models:
147 self.models = [t.strip() for t in task_info.models.split(',')]
148 else:
149 self.models = []
150
151 if task_info.exclude_models:
152 self.exclude_models = [
153 t.strip() for t in task_info.exclude_models.split(',')]
154 else:
155 self.exclude_models = []
156
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700157 if task_info.board_families:
158 # Finetune the allowed boards list with board_families & boards.
159 families = [family.strip()
160 for family in task_info.board_families.split(',')]
161 for family in families:
162 self.boards += board_family_config.get(family, [])
Xixuan Wu89897182019-01-03 15:28:01 -0800163
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700164 if task_info.exclude_board_families:
165 # Finetune the disallowed boards list with exclude_board_families
166 # & exclude_boards.
167 families = [family.strip()
168 for family in task_info.exclude_board_families.split(',')]
169 for family in families:
170 self.exclude_boards += board_family_config.get(family, [])
171
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700172 if tot is None:
173 self.tot_manager = tot_manager.TotMilestoneManager()
174 else:
175 self.tot_manager = tot
176
177 self._set_spec_compare_info()
178
Craig Bergstrom58263d32018-04-26 14:11:35 -0600179 def schedule(self, launch_control_builds, cros_builds_tuple, lab_config,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700180 db_client):
181 """Schedule the task by its settings.
182
183 Args:
184 launch_control_builds: the build dict for Android boards, see
185 return value of |get_launch_control_builds|.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600186 cros_builds_tuple: the two-tuple of build dicts for ChromeOS boards,
187 see return value of |get_cros_builds|.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700188 lab_config: a config.LabConfig object, to read lab config file.
189 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
190
191 Raises:
192 SchedulingError: if tasks that should be scheduled fail to schedule.
Xixuan Wu5451a662017-10-17 10:57:40 -0700193
194 Returns:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700195 A boolean indicator; true if there were any suites related to this
196 task which got pushed into the suites queue.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700197 """
198 assert lab_config is not None
Xixuan Wu5451a662017-10-17 10:57:40 -0700199 self.is_pushed = False
200
Craig Bergstrom58263d32018-04-26 14:11:35 -0600201 branch_builds, relaxed_builds = cros_builds_tuple
202 builds_dict = branch_builds
203 if self.only_hwtest_sanity_required:
204 builds_dict = relaxed_builds
205
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700206 logging.info('######## Scheduling task %s ########', self.name)
207 if self.os_type == build_lib.OS_TYPE_CROS:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600208 if not builds_dict:
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700209 logging.info('No CrOS build to run, skip running.')
210 else:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600211 self._schedule_cros_builds(builds_dict, lab_config, db_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700212 else:
213 if not launch_control_builds:
214 logging.info('No Android build to run, skip running.')
215 else:
216 self._schedule_launch_control_builds(launch_control_builds)
217
Xixuan Wu5451a662017-10-17 10:57:40 -0700218 return self.is_pushed
219
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700220 def _set_spec_compare_info(self):
221 """Set branch spec compare info for task for further check."""
222 self._bare_branches = []
223 self._version_equal_constraint = False
224 self._version_gte_constraint = False
225 self._version_lte_constraint = False
226
227 if not self.branch_specs:
228 # Any milestone is OK.
229 self._numeric_constraint = version.LooseVersion('0')
230 else:
231 self._numeric_constraint = None
232 for spec in self.branch_specs:
233 if 'tot' in spec.lower():
234 # Convert spec >=tot-1 to >=RXX.
235 tot_str = spec[spec.index('tot'):]
236 spec = spec.replace(
237 tot_str, self.tot_manager.convert_tot_spec(tot_str))
238
239 if spec.startswith('>='):
240 self._numeric_constraint = version.LooseVersion(
241 spec.lstrip('>=R'))
242 self._version_gte_constraint = True
243 elif spec.startswith('<='):
244 self._numeric_constraint = version.LooseVersion(
245 spec.lstrip('<=R'))
246 self._version_lte_constraint = True
247 elif spec.startswith('=='):
248 self._version_equal_constraint = True
249 self._numeric_constraint = version.LooseVersion(
250 spec.lstrip('==R'))
251 else:
252 self._bare_branches.append(spec)
253
254 def _fits_spec(self, branch):
255 """Check if a branch is deemed OK by this task's branch specs.
256
257 Will return whether a branch 'fits' the specifications stored in this task.
258
259 Examples:
260 Assuming tot=R40
261 t = Task('Name', 'suite', ['factory', '>=tot-1'])
262 t._fits_spec('factory') # True
263 t._fits_spec('40') # True
264 t._fits_spec('38') # False
265 t._fits_spec('firmware') # False
266
267 Args:
268 branch: the branch to check.
269
270 Returns:
271 True if branch 'fits' with stored specs, False otherwise.
272 """
273 if branch in build_lib.BARE_BRANCHES:
274 return branch in self._bare_branches
275
276 if self._numeric_constraint:
277 if self._version_equal_constraint:
278 return version.LooseVersion(branch) == self._numeric_constraint
279 elif self._version_gte_constraint:
280 return version.LooseVersion(branch) >= self._numeric_constraint
281 elif self._version_lte_constraint:
282 return version.LooseVersion(branch) <= self._numeric_constraint
283 else:
284 return version.LooseVersion(branch) >= self._numeric_constraint
285 else:
286 return False
287
288 def _get_latest_firmware_build_from_db(self, spec, board, db_client):
289 """Get the latest firmware build from CIDB database.
290
291 Args:
292 spec: a string build spec for RO or RW firmware, eg. firmware,
293 cros. For RO firmware, the value can also be released_ro_X.
294 board: the board against which this task will run suite job.
295 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
296
297 Returns:
298 the latest firmware build.
299
300 Raises:
301 MySQLdb.OperationalError: if connection operations are not valid.
302 """
303 build_type = 'release' if spec == 'cros' else spec
304 # TODO(xixuan): not all firmware are saved in cidb.
305 build = db_client.get_latest_passed_builds('%s-%s' % (board, build_type))
306
307 if build is None:
308 return None
309 else:
310 latest_build = str(build_lib.CrOSBuild(
311 board, build_type, build.milestone, build.platform))
312 logging.debug('latest firmware build for %s-%s: %s', board,
313 build_type, latest_build)
314 return latest_build
315
316 def _get_latest_firmware_build_from_lab_config(self, spec, board,
317 lab_config):
318 """Get latest firmware from lab config file.
319
320 Args:
321 spec: a string build spec for RO or RW firmware, eg. firmware,
322 cros. For RO firmware, the value can also be released_ro_X.
323 board: a string board against which this task will run suite job.
324 lab_config: a config.LabConfig object, to read lab config file.
325
326 Returns:
327 A string latest firmware build.
328
329 Raises:
330 ValueError: if no firmware build list is found in lab config file.
331 """
332 index = int(spec[len(_RELEASE_RO_FIRMWARE_SPEC):])
333 released_ro_builds = lab_config.get_firmware_ro_build_list(
334 'RELEASED_RO_BUILDS_%s' % board).split(',')
335 if len(released_ro_builds) < index:
336 raise ValueError('No %dth ro_builds in the lab_config firmware '
337 'list %r' % (index, released_ro_builds))
338
339 logging.debug('Get ro_build: %s', released_ro_builds[index - 1])
340 return released_ro_builds[index - 1]
341
342 def _get_firmware_build(self, spec, board, lab_config, db_client):
343 """Get the firmware build name to test with ChromeOS build.
344
345 Args:
346 spec: a string build spec for RO or RW firmware, eg. firmware,
347 cros. For RO firmware, the value can also be released_ro_X.
348 board: a string board against which this task will run suite job.
349 lab_config: a config.LabConfig object, to read lab config file.
350 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
351
352 Returns:
353 A string firmware build name.
354
355 Raises:
356 ValueError: if failing to get firmware from lab config file;
357 MySQLdb.OperationalError: if DB connection is not available.
358 """
359 if not spec or spec == 'stable':
360 # TODO(crbug.com/577316): Query stable RO firmware.
361 logging.debug('%s RO firmware build is not supported.', spec)
362 return None
363
364 try:
365 if spec.startswith(_RELEASE_RO_FIRMWARE_SPEC):
366 # For RO firmware whose value is released_ro_X, where X is the index of
367 # the list defined in lab config file:
368 # CROS/RELEASED_RO_BUILDS_[board].
369 # For example, for spec 'released_ro_2', and lab config file
370 # CROS/RELEASED_RO_BUILDS_veyron_jerry: build1,build2,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600371 # return firmware RO build should be 'build2'.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700372 return self._get_latest_firmware_build_from_lab_config(
373 spec, board, lab_config)
374 else:
375 return self._get_latest_firmware_build_from_db(spec, board, db_client)
376 except ValueError as e:
377 logging.warning('Failed to get firmware from lab config file'
378 'for spec %s, board %s: %s', spec, board, str(e))
379 return None
380 except MySQLdb.OperationalError as e:
381 logging.warning('Failed to get firmware from cidb for spec %s, '
382 'board %s: %s', spec, board, str(e))
383 return None
384
C Shapiro7f24a002017-12-05 14:25:09 -0700385 def _push_suite(
386 self,
387 board=None,
388 model=None,
389 cros_build=None,
390 firmware_rw_build=None,
391 firmware_ro_build=None,
392 test_source_build=None,
393 launch_control_build=None,
Xixuan Wubb74a372018-08-21 17:37:08 -0700394 run_prod_code=False,
395 is_skylab=False):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700396 """Schedule suite job for the task by pushing suites to SuiteQueue.
397
398 Args:
399 board: the board against which this suite job run.
C Shapiro7f24a002017-12-05 14:25:09 -0700400 model: the model name for unibuild.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700401 cros_build: the CrOS build of this suite job.
402 firmware_rw_build: Firmware RW build to run this suite job with.
403 firmware_ro_build: Firmware RO build to run this suite job with.
404 test_source_build: Test source build, used for server-side
405 packaging of this suite job.
406 launch_control_build: the launch control build of this suite job.
407 run_prod_code: If True, the suite will run the test code that lives
408 in prod aka the test code currently on the lab servers. If
409 False, the control files and test code for this suite run will
410 be retrieved from the build artifacts. Default is False.
Xixuan Wubb74a372018-08-21 17:37:08 -0700411 is_skylab: If True, schedule this suite to skylab, otherwise schedule
412 it to AFE. Default is False.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700413 """
414 android_build = None
415 testbed_build = None
416
417 if self.testbed_dut_count:
418 launch_control_build = '%s#%d' % (launch_control_build,
419 self.testbed_dut_count)
420 test_source_build = launch_control_build
421 board = '%s-%d' % (board, self.testbed_dut_count)
422
423 if launch_control_build:
424 if not self.testbed_dut_count:
425 android_build = launch_control_build
426 else:
427 testbed_build = launch_control_build
428
429 suite_job_parameters = {
430 'suite': self.suite,
431 'board': board,
C Shapiro7f24a002017-12-05 14:25:09 -0700432 'model': model,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700433 build_lib.BuildVersionKey.CROS_VERSION: cros_build,
434 build_lib.BuildVersionKey.FW_RW_VERSION: firmware_rw_build,
435 build_lib.BuildVersionKey.FW_RO_VERSION: firmware_ro_build,
436 build_lib.BuildVersionKey.ANDROID_BUILD_VERSION: android_build,
437 build_lib.BuildVersionKey.TESTBED_BUILD_VERSION: testbed_build,
438 'num': self.num,
439 'pool': self.pool,
440 'priority': self.priority,
441 'timeout': self.timeout,
442 'timeout_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
443 'max_runtime_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
Xixuan Wu2ba72652017-09-15 15:49:42 -0700444 'no_wait_for_results': not self.job_retry,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700445 'test_source_build': test_source_build,
446 'job_retry': self.job_retry,
447 'no_delay': self.no_delay,
Xixuan Wu80531932017-10-12 17:26:51 -0700448 'force': self.force,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700449 'run_prod_code': run_prod_code,
Xixuan Wubb74a372018-08-21 17:37:08 -0700450 'is_skylab': is_skylab,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700451 }
452
453 task_executor.push(task_executor.SUITES_QUEUE, **suite_job_parameters)
454 logging.info('Pushing task %r into taskqueue', suite_job_parameters)
Xixuan Wu5451a662017-10-17 10:57:40 -0700455 self.is_pushed = True
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700456
Xixuan Wu3b9dfb42019-01-03 16:48:55 -0800457 def _check_model(self, models_by_board, board, passed_model):
458 """Check whether this task should be run on the passed-in model.
459
460 Args:
461 models_by_board: The mapping from board to its models.
462 board: The board to check whether to run the task.
463 passed_model: the model to check whether to run the task.
464
465 Returns:
466 A list of valid model to run the task.
467 """
468 if passed_model is None:
469 logging.debug('Model is not set. Run the task with empty model.')
470 return [None]
471
472 all_models = models_by_board.get(board, [])
473 if passed_model not in all_models:
474 logging.debug('Model %s is not in valid model list %s', passed_model,
475 all_models)
476 return []
477
478 full_model_name = '%s_%s' % (board, passed_model)
479 if self.exclude_models and full_model_name in self.exclude_models:
480 logging.debug('Model %s is in exclude board list %s', passed_model,
481 self.exclude_models)
482 return []
483
484 if self.models and full_model_name not in self.models:
485 logging.debug('Model %s is not in support model list %s', passed_model,
486 self.models)
487 return []
488
489 return [passed_model]
490
Craig Bergstrom58263d32018-04-26 14:11:35 -0600491 def _schedule_cros_builds(self, build_dict, lab_config, db_client):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700492 """Schedule tasks with branch builds.
493
494 Args:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600495 build_dict: the build dict for ChromeOS boards, see return
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700496 value of |build_lib.get_cros_builds_since_date_from_db|.
497 lab_config: a config.LabConfig object, to read lab config file.
498 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
499 """
C Shapiro7f24a002017-12-05 14:25:09 -0700500 models_by_board = lab_config.get_cros_model_map() if lab_config else {}
Xixuan Wubb74a372018-08-21 17:37:08 -0700501 skylab_boards = lab_config.get_skylab_board_list() if lab_config else []
Xixuan Wu446b8ad2018-08-23 11:25:43 -0700502 skylab_suites = lab_config.get_skylab_suite_list() if lab_config else []
Xixuan Wu83118dd2018-08-27 12:11:35 -0700503 logging.info('Skylab_boards: %r', skylab_boards)
504 logging.info('Skylab suites: %r', skylab_suites)
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700505 for (board, passed_model, build_type,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600506 milestone), manifest in build_dict.iteritems():
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700507 cros_build = str(build_lib.CrOSBuild(board, build_type, milestone,
508 manifest))
509 logging.info('Running %s on %s', self.name, cros_build)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700510 if self.exclude_boards and board in self.exclude_boards:
511 logging.debug('Board %s is in excluded board list: %s',
512 board, self.exclude_boards)
513 continue
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700514
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700515 if self.boards and board not in self.boards:
516 logging.debug('Board %s is not in supported board list: %s',
517 board, self.boards)
518 continue
519
520 # Check the fitness of the build's branch for task
521 branch_build_spec = _pick_branch(build_type, milestone)
522 if not self._fits_spec(branch_build_spec):
523 logging.debug("branch_build spec %s doesn't fit this task's "
524 "requirement: %s", branch_build_spec, self.branch_specs)
525 continue
526
527 firmware_rw_build = None
528 firmware_ro_build = None
529 if self.firmware_rw_build_spec or self.firmware_ro_build_spec:
530 firmware_rw_build = self._get_firmware_build(
531 self.firmware_rw_build_spec, board, lab_config, db_client)
532 firmware_ro_build = self._get_firmware_build(
533 self.firmware_ro_build_spec, board, lab_config, db_client)
534
535 if not firmware_ro_build and self.firmware_ro_build_spec:
536 logging.debug('No firmware ro build to run, skip running')
537 continue
538
539 if self.test_source == build_lib.BuildType.FIRMWARE_RW:
540 test_source_build = firmware_rw_build
541 else:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700542 # Default test source build to CrOS build if it's not specified.
543 # Past versions chose based on run_prod_code, but we no longer respect
544 # that option and scheduler settings should always set it to False.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700545 test_source_build = cros_build
546
Xixuan Wu83118dd2018-08-27 12:11:35 -0700547 is_skylab = (board in skylab_boards) and (self.suite in skylab_suites)
C Shapiro7f24a002017-12-05 14:25:09 -0700548
Xixuan Wu3b9dfb42019-01-03 16:48:55 -0800549 for model in self._check_model(models_by_board, board, passed_model):
550 self._push_suite(
551 board=board,
552 model=model,
553 cros_build=cros_build,
554 firmware_rw_build=firmware_rw_build,
555 firmware_ro_build=firmware_ro_build,
556 test_source_build=test_source_build,
557 is_skylab=is_skylab)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700558
559 def _schedule_launch_control_builds(self, launch_control_builds):
560 """Schedule tasks with launch control builds.
561
562 Args:
563 launch_control_builds: the build dict for Android boards.
564 """
565 for board, launch_control_build in launch_control_builds.iteritems():
566 logging.debug('Running %s on %s', self.name, board)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700567 if self.exclude_boards and board in self.exclude_boards:
568 logging.debug('Board %s is in excluded board list: %s',
569 board, self.exclude_boards)
570 continue
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700571 if self.boards and board not in self.boards:
572 logging.debug('Board %s is not in supported board list: %s',
573 board, self.boards)
574 continue
575
576 for android_build in launch_control_build:
577 if not any([branch in android_build
578 for branch in self.launch_control_branches]):
579 logging.debug('Branch %s is not required to run for task '
580 '%s', android_build, self.name)
581 continue
582
583 self._push_suite(board=board,
584 test_source_build=android_build,
585 launch_control_build=android_build)
586
587
588def _pick_branch(build_type, milestone):
589 """Select branch based on build type.
590
591 If the build_type is a bare branch, return build_type as the build spec.
592 If the build_type is a normal CrOS branch, return milestone as the build
593 spec.
594
595 Args:
596 build_type: a string builder name, like 'release'.
597 milestone: a string milestone, like '55'.
598
599 Returns:
600 A string milestone if build_type represents CrOS build, otherwise
601 return build_type.
602 """
603 return build_type if build_type in build_lib.BARE_BRANCHES else milestone