blob: 35d0e9fa6cb5d3e08d54de516c288dea30f36542 [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
121 self.testbed_dut_count = task_info.testbed_dut_count
Xixuan Wu008ee832017-10-12 16:59:34 -0700122 self.hour = task_info.hour
123 self.day = task_info.day
Craig Bergstrom58263d32018-04-26 14:11:35 -0600124 self.only_hwtest_sanity_required = task_info.only_hwtest_sanity_required
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700125
126 if task_info.lc_branches:
127 self.launch_control_branches = [
128 t.strip() for t in task_info.lc_branches.split(',')]
129 else:
130 self.launch_control_branches = []
131
132 if task_info.lc_targets:
133 self.launch_control_targets = [
134 t.strip() for t in task_info.lc_targets.split(',')]
135 else:
136 self.launch_control_targets = []
137
138 if task_info.boards:
139 self.boards = [t.strip() for t in task_info.boards.split(',')]
140 else:
141 self.boards = []
142
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700143 if task_info.exclude_boards:
144 self.exclude_boards = [
145 t.strip() for t in task_info.exclude_boards.split(',')]
146 else:
147 self.exclude_boards = []
148
Xixuan Wu89897182019-01-03 15:28:01 -0800149 if task_info.models:
150 self.models = [t.strip() for t in task_info.models.split(',')]
151 else:
152 self.models = []
153
154 if task_info.exclude_models:
155 self.exclude_models = [
156 t.strip() for t in task_info.exclude_models.split(',')]
157 else:
158 self.exclude_models = []
159
C Shapiro09108252019-08-01 14:52:52 -0500160 self.any_model = task_info.any_model
161
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700162 if task_info.board_families:
163 # Finetune the allowed boards list with board_families & boards.
164 families = [family.strip()
165 for family in task_info.board_families.split(',')]
166 for family in families:
167 self.boards += board_family_config.get(family, [])
Xixuan Wu89897182019-01-03 15:28:01 -0800168
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700169 if task_info.exclude_board_families:
170 # Finetune the disallowed boards list with exclude_board_families
171 # & exclude_boards.
172 families = [family.strip()
173 for family in task_info.exclude_board_families.split(',')]
174 for family in families:
175 self.exclude_boards += board_family_config.get(family, [])
176
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700177 if tot is None:
178 self.tot_manager = tot_manager.TotMilestoneManager()
179 else:
180 self.tot_manager = tot
181
182 self._set_spec_compare_info()
183
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700184 def schedule(self, launch_control_builds, cros_builds_tuple, configs,
Xixuan Wuc6819012019-05-23 11:34:59 -0700185 build_client):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700186 """Schedule the task by its settings.
187
188 Args:
189 launch_control_builds: the build dict for Android boards, see
190 return value of |get_launch_control_builds|.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600191 cros_builds_tuple: the two-tuple of build dicts for ChromeOS boards,
192 see return value of |get_cros_builds|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700193 configs: a config_reader.Configs object.
Xixuan Wuc6819012019-05-23 11:34:59 -0700194 build_client: a rest_client.BuildBucketBigqueryClient object, to
195 connect Buildbucket Bigquery.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700196
197 Raises:
198 SchedulingError: if tasks that should be scheduled fail to schedule.
Xixuan Wu5451a662017-10-17 10:57:40 -0700199
200 Returns:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700201 A boolean indicator; true if there were any suites related to this
202 task which got pushed into the suites queue.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700203 """
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700204 assert configs.lab_config is not None
Xixuan Wu5451a662017-10-17 10:57:40 -0700205 self.is_pushed = False
206
Craig Bergstrom58263d32018-04-26 14:11:35 -0600207 branch_builds, relaxed_builds = cros_builds_tuple
208 builds_dict = branch_builds
209 if self.only_hwtest_sanity_required:
210 builds_dict = relaxed_builds
211
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700212 logging.info('######## Scheduling task %s ########', self.name)
213 if self.os_type == build_lib.OS_TYPE_CROS:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600214 if not builds_dict:
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700215 logging.info('No CrOS build to run, skip running.')
216 else:
Xixuan Wuc6819012019-05-23 11:34:59 -0700217 self._schedule_cros_builds(builds_dict, configs, build_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700218 else:
219 if not launch_control_builds:
220 logging.info('No Android build to run, skip running.')
221 else:
222 self._schedule_launch_control_builds(launch_control_builds)
223
Xixuan Wu5451a662017-10-17 10:57:40 -0700224 return self.is_pushed
225
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700226 def _set_spec_compare_info(self):
227 """Set branch spec compare info for task for further check."""
228 self._bare_branches = []
229 self._version_equal_constraint = False
230 self._version_gte_constraint = False
231 self._version_lte_constraint = False
232
233 if not self.branch_specs:
234 # Any milestone is OK.
235 self._numeric_constraint = version.LooseVersion('0')
236 else:
237 self._numeric_constraint = None
238 for spec in self.branch_specs:
239 if 'tot' in spec.lower():
240 # Convert spec >=tot-1 to >=RXX.
241 tot_str = spec[spec.index('tot'):]
242 spec = spec.replace(
243 tot_str, self.tot_manager.convert_tot_spec(tot_str))
244
245 if spec.startswith('>='):
246 self._numeric_constraint = version.LooseVersion(
247 spec.lstrip('>=R'))
248 self._version_gte_constraint = True
249 elif spec.startswith('<='):
250 self._numeric_constraint = version.LooseVersion(
251 spec.lstrip('<=R'))
252 self._version_lte_constraint = True
253 elif spec.startswith('=='):
254 self._version_equal_constraint = True
255 self._numeric_constraint = version.LooseVersion(
256 spec.lstrip('==R'))
257 else:
258 self._bare_branches.append(spec)
259
260 def _fits_spec(self, branch):
261 """Check if a branch is deemed OK by this task's branch specs.
262
263 Will return whether a branch 'fits' the specifications stored in this task.
264
265 Examples:
266 Assuming tot=R40
267 t = Task('Name', 'suite', ['factory', '>=tot-1'])
268 t._fits_spec('factory') # True
269 t._fits_spec('40') # True
270 t._fits_spec('38') # False
271 t._fits_spec('firmware') # False
272
273 Args:
274 branch: the branch to check.
275
276 Returns:
277 True if branch 'fits' with stored specs, False otherwise.
278 """
279 if branch in build_lib.BARE_BRANCHES:
280 return branch in self._bare_branches
281
282 if self._numeric_constraint:
283 if self._version_equal_constraint:
284 return version.LooseVersion(branch) == self._numeric_constraint
285 elif self._version_gte_constraint:
286 return version.LooseVersion(branch) >= self._numeric_constraint
287 elif self._version_lte_constraint:
288 return version.LooseVersion(branch) <= self._numeric_constraint
289 else:
290 return version.LooseVersion(branch) >= self._numeric_constraint
291 else:
292 return False
293
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700294 def _get_latest_firmware_build(self, spec, board, build_client):
295 """Get the latest firmware build.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700296
297 Args:
298 spec: a string build spec for RO or RW firmware, eg. firmware,
299 cros. For RO firmware, the value can also be released_ro_X.
300 board: the board against which this task will run suite job.
Xixuan Wuc6819012019-05-23 11:34:59 -0700301 build_client: a rest_client.BuildBucketBigqueryClient object, to
302 connect Buildbucket Bigquery.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700303
304 Returns:
Xinan Lin39dcca82019-07-26 18:55:51 -0700305 A string the latest firmware build. This is the path for the
306 downstream systems to download the built firmware. For "cros"
307 build_type, it is "<board>-release/R<milestone>-<platform>".
308 For "firmware" type, it has the form of
309 "firmware-<board>-1234.56.A-firmwarebranch/RFoo-1.0.0-b123456/<board>".
310
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700311 """
312 build_type = 'release' if spec == 'cros' else spec
Xinan Lin39dcca82019-07-26 18:55:51 -0700313 suffix = ''
Xinan Lin318cf752019-07-19 14:50:23 -0700314 if build_type == 'firmware':
Xinan Lin39dcca82019-07-26 18:55:51 -0700315 artifact = build_client.get_latest_passed_builds_artifact_link_firmware(
316 board)
317 suffix = '/' + board
Xinan Lin318cf752019-07-19 14:50:23 -0700318 else:
Xinan Lin39dcca82019-07-26 18:55:51 -0700319 artifact = build_client.get_latest_passed_builds_artifact_link('%s-%s' %
320 (board, build_type))
321 if artifact is None:
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700322 return None
Xinan Lin39dcca82019-07-26 18:55:51 -0700323
324 ARTIFACT_PATTERN = r'gs://chromeos-image-archive/(?P<firmware_build>.+)'
325 match = re.match(ARTIFACT_PATTERN, artifact)
326 if not match:
327 raise ValueError('Artifact path of firmware is not valid: %s', artifact)
328
329 firmware_build = match.group('firmware_build') + suffix
330 logging.debug('latest firmware build for %s', firmware_build)
331 return firmware_build
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700332
333 def _get_latest_firmware_build_from_lab_config(self, spec, board,
334 lab_config):
335 """Get latest firmware from lab config file.
336
337 Args:
338 spec: a string build spec for RO or RW firmware, eg. firmware,
339 cros. For RO firmware, the value can also be released_ro_X.
340 board: a string board against which this task will run suite job.
341 lab_config: a config.LabConfig object, to read lab config file.
342
343 Returns:
344 A string latest firmware build.
345
346 Raises:
347 ValueError: if no firmware build list is found in lab config file.
348 """
349 index = int(spec[len(_RELEASE_RO_FIRMWARE_SPEC):])
350 released_ro_builds = lab_config.get_firmware_ro_build_list(
351 'RELEASED_RO_BUILDS_%s' % board).split(',')
352 if len(released_ro_builds) < index:
353 raise ValueError('No %dth ro_builds in the lab_config firmware '
354 'list %r' % (index, released_ro_builds))
355
356 logging.debug('Get ro_build: %s', released_ro_builds[index - 1])
357 return released_ro_builds[index - 1]
358
Xixuan Wuc6819012019-05-23 11:34:59 -0700359 def _get_firmware_build(self, spec, board, lab_config, build_client):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700360 """Get the firmware build name to test with ChromeOS build.
361
362 Args:
363 spec: a string build spec for RO or RW firmware, eg. firmware,
364 cros. For RO firmware, the value can also be released_ro_X.
365 board: a string board against which this task will run suite job.
366 lab_config: a config.LabConfig object, to read lab config file.
Xixuan Wuc6819012019-05-23 11:34:59 -0700367 build_client: a rest_client.BuildBucketBigqueryClient object, to
368 connect Buildbucket Bigquery.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700369
370 Returns:
371 A string firmware build name.
372
373 Raises:
374 ValueError: if failing to get firmware from lab config file;
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700375 """
376 if not spec or spec == 'stable':
377 # TODO(crbug.com/577316): Query stable RO firmware.
378 logging.debug('%s RO firmware build is not supported.', spec)
379 return None
380
381 try:
382 if spec.startswith(_RELEASE_RO_FIRMWARE_SPEC):
383 # For RO firmware whose value is released_ro_X, where X is the index of
384 # the list defined in lab config file:
385 # CROS/RELEASED_RO_BUILDS_[board].
386 # For example, for spec 'released_ro_2', and lab config file
387 # CROS/RELEASED_RO_BUILDS_veyron_jerry: build1,build2,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600388 # return firmware RO build should be 'build2'.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700389 return self._get_latest_firmware_build_from_lab_config(
390 spec, board, lab_config)
391 else:
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700392 return self._get_latest_firmware_build(spec, board, build_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700393 except ValueError as e:
394 logging.warning('Failed to get firmware from lab config file'
395 'for spec %s, board %s: %s', spec, board, str(e))
396 return None
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700397
C Shapiro7f24a002017-12-05 14:25:09 -0700398 def _push_suite(
399 self,
400 board=None,
401 model=None,
402 cros_build=None,
403 firmware_rw_build=None,
404 firmware_ro_build=None,
405 test_source_build=None,
406 launch_control_build=None,
Xixuan Wubb74a372018-08-21 17:37:08 -0700407 run_prod_code=False,
Xixuan Wu028f6732019-04-11 14:47:42 -0700408 is_skylab=False,
409 override_pool='',
410 override_qs_account=''):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700411 """Schedule suite job for the task by pushing suites to SuiteQueue.
412
413 Args:
414 board: the board against which this suite job run.
C Shapiro7f24a002017-12-05 14:25:09 -0700415 model: the model name for unibuild.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700416 cros_build: the CrOS build of this suite job.
417 firmware_rw_build: Firmware RW build to run this suite job with.
418 firmware_ro_build: Firmware RO build to run this suite job with.
419 test_source_build: Test source build, used for server-side
420 packaging of this suite job.
421 launch_control_build: the launch control build of this suite job.
422 run_prod_code: If True, the suite will run the test code that lives
423 in prod aka the test code currently on the lab servers. If
424 False, the control files and test code for this suite run will
425 be retrieved from the build artifacts. Default is False.
Xixuan Wubb74a372018-08-21 17:37:08 -0700426 is_skylab: If True, schedule this suite to skylab, otherwise schedule
427 it to AFE. Default is False.
Xixuan Wu028f6732019-04-11 14:47:42 -0700428 override_pool: A string to indicate pool of quota scheduler.
429 override_qs_account: A string of quota scheduler account.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700430 """
431 android_build = None
432 testbed_build = None
433
434 if self.testbed_dut_count:
435 launch_control_build = '%s#%d' % (launch_control_build,
436 self.testbed_dut_count)
437 test_source_build = launch_control_build
438 board = '%s-%d' % (board, self.testbed_dut_count)
439
440 if launch_control_build:
441 if not self.testbed_dut_count:
442 android_build = launch_control_build
443 else:
444 testbed_build = launch_control_build
445
446 suite_job_parameters = {
447 'suite': self.suite,
448 'board': board,
C Shapiro7f24a002017-12-05 14:25:09 -0700449 'model': model,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700450 build_lib.BuildVersionKey.CROS_VERSION: cros_build,
451 build_lib.BuildVersionKey.FW_RW_VERSION: firmware_rw_build,
452 build_lib.BuildVersionKey.FW_RO_VERSION: firmware_ro_build,
453 build_lib.BuildVersionKey.ANDROID_BUILD_VERSION: android_build,
454 build_lib.BuildVersionKey.TESTBED_BUILD_VERSION: testbed_build,
455 'num': self.num,
456 'pool': self.pool,
457 'priority': self.priority,
458 'timeout': self.timeout,
459 'timeout_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
460 'max_runtime_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
Xixuan Wu2ba72652017-09-15 15:49:42 -0700461 'no_wait_for_results': not self.job_retry,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700462 'test_source_build': test_source_build,
463 'job_retry': self.job_retry,
464 'no_delay': self.no_delay,
Xixuan Wu80531932017-10-12 17:26:51 -0700465 'force': self.force,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700466 'run_prod_code': run_prod_code,
Xixuan Wubb74a372018-08-21 17:37:08 -0700467 'is_skylab': is_skylab,
Xixuan Wu028f6732019-04-11 14:47:42 -0700468 'override_pool': override_pool,
469 'override_qs_account': override_qs_account,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700470 }
471
472 task_executor.push(task_executor.SUITES_QUEUE, **suite_job_parameters)
473 logging.info('Pushing task %r into taskqueue', suite_job_parameters)
Xixuan Wu5451a662017-10-17 10:57:40 -0700474 self.is_pushed = True
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700475
Xixuan Wuc6819012019-05-23 11:34:59 -0700476 def _schedule_cros_builds(self, build_dict, configs, build_client):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700477 """Schedule tasks with branch builds.
478
479 Args:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600480 build_dict: the build dict for ChromeOS boards, see return
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700481 value of |build_lib.get_cros_builds_since_date|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700482 configs: A config_reader.Configs object.
Xixuan Wuc6819012019-05-23 11:34:59 -0700483 build_client: a rest_client.BuildBucketBigqueryClient object, to
484 connect Buildbucket Bigquery.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700485 """
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700486 lab_config = configs.lab_config
C Shapiro7f24a002017-12-05 14:25:09 -0700487 models_by_board = lab_config.get_cros_model_map() if lab_config else {}
C Shapiro09108252019-08-01 14:52:52 -0500488 model_agnostic_cros_builds = set()
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700489 for (board, passed_model, build_type,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600490 milestone), manifest in build_dict.iteritems():
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700491 cros_build = str(build_lib.CrOSBuild(board, build_type, milestone,
492 manifest))
493 logging.info('Running %s on %s', self.name, cros_build)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700494 if self.exclude_boards and board in self.exclude_boards:
495 logging.debug('Board %s is in excluded board list: %s',
496 board, self.exclude_boards)
497 continue
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700498
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700499 if self.boards and board not in self.boards:
500 logging.debug('Board %s is not in supported board list: %s',
501 board, self.boards)
502 continue
503
504 # Check the fitness of the build's branch for task
505 branch_build_spec = _pick_branch(build_type, milestone)
506 if not self._fits_spec(branch_build_spec):
507 logging.debug("branch_build spec %s doesn't fit this task's "
508 "requirement: %s", branch_build_spec, self.branch_specs)
509 continue
510
511 firmware_rw_build = None
512 firmware_ro_build = None
513 if self.firmware_rw_build_spec or self.firmware_ro_build_spec:
514 firmware_rw_build = self._get_firmware_build(
Xixuan Wuc6819012019-05-23 11:34:59 -0700515 self.firmware_rw_build_spec, board, lab_config, build_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700516 firmware_ro_build = self._get_firmware_build(
Xixuan Wuc6819012019-05-23 11:34:59 -0700517 self.firmware_ro_build_spec, board, lab_config, build_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700518
519 if not firmware_ro_build and self.firmware_ro_build_spec:
520 logging.debug('No firmware ro build to run, skip running')
521 continue
522
523 if self.test_source == build_lib.BuildType.FIRMWARE_RW:
524 test_source_build = firmware_rw_build
525 else:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700526 # Default test source build to CrOS build if it's not specified.
527 # Past versions chose based on run_prod_code, but we no longer respect
528 # that option and scheduler settings should always set it to False.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700529 test_source_build = cros_build
530
Xixuan Wub4b2f412019-05-03 11:22:31 -0700531 hwtest_board = build_lib.reshape_board(board)
Xixuan Wu1f0be4c2019-03-18 16:53:23 -0700532 is_skylab = skylab.should_run_in_skylab(configs.migration_config,
Xixuan Wub4b2f412019-05-03 11:22:31 -0700533 hwtest_board,
Xixuan Wued878ea2019-03-18 15:32:16 -0700534 passed_model,
Xixuan Wu1e42c752019-03-21 13:41:49 -0700535 self.suite,
536 self.pool)
Xixuan Wu028f6732019-04-11 14:47:42 -0700537 override_pool, override_qs_account = skylab.get_override_info(
538 configs.migration_config,
Xixuan Wub4b2f412019-05-03 11:22:31 -0700539 hwtest_board,
Xixuan Wu028f6732019-04-11 14:47:42 -0700540 passed_model,
541 self.suite,
542 self.pool)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000543 models = models_by_board.get(board, [None])
C Shapiro7f24a002017-12-05 14:25:09 -0700544
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000545 for model in models:
546 if ((passed_model is not None and model == passed_model) or
547 passed_model is None):
Xixuan Wua41efa22019-05-17 14:28:04 -0700548 full_model_name = '%s_%s' % (board, model)
549 # Respect exclude first.
550 if self.exclude_models and full_model_name in self.exclude_models:
551 logging.debug("Skip model %s as it's in exclude model list %s",
552 model, self.exclude_models)
553 continue
554
555 if self.models and full_model_name not in self.models:
556 logging.debug("Skip model %s as it's not in support model list %s",
557 model, self.models)
558 continue
559
C Shapiro09108252019-08-01 14:52:52 -0500560 explicit_model = model
561
562 if self.any_model:
563 explicit_model=None
564 unique_build = str(cros_build)
565 if unique_build in model_agnostic_cros_builds:
566 # Skip since we've already run with no explicit model set.
567 continue
568 model_agnostic_cros_builds.add(unique_build)
569
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000570 self._push_suite(
Xixuan Wub4b2f412019-05-03 11:22:31 -0700571 board=hwtest_board,
C Shapiro09108252019-08-01 14:52:52 -0500572 model=explicit_model,
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000573 cros_build=cros_build,
574 firmware_rw_build=firmware_rw_build,
575 firmware_ro_build=firmware_ro_build,
576 test_source_build=test_source_build,
Xixuan Wu028f6732019-04-11 14:47:42 -0700577 is_skylab=is_skylab,
578 override_pool=override_pool,
579 override_qs_account=override_qs_account)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700580
581 def _schedule_launch_control_builds(self, launch_control_builds):
582 """Schedule tasks with launch control builds.
583
584 Args:
585 launch_control_builds: the build dict for Android boards.
586 """
587 for board, launch_control_build in launch_control_builds.iteritems():
588 logging.debug('Running %s on %s', self.name, board)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700589 if self.exclude_boards and board in self.exclude_boards:
590 logging.debug('Board %s is in excluded board list: %s',
591 board, self.exclude_boards)
592 continue
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700593 if self.boards and board not in self.boards:
594 logging.debug('Board %s is not in supported board list: %s',
595 board, self.boards)
596 continue
597
598 for android_build in launch_control_build:
599 if not any([branch in android_build
600 for branch in self.launch_control_branches]):
601 logging.debug('Branch %s is not required to run for task '
602 '%s', android_build, self.name)
603 continue
604
605 self._push_suite(board=board,
606 test_source_build=android_build,
607 launch_control_build=android_build)
608
609
610def _pick_branch(build_type, milestone):
611 """Select branch based on build type.
612
613 If the build_type is a bare branch, return build_type as the build spec.
614 If the build_type is a normal CrOS branch, return milestone as the build
615 spec.
616
617 Args:
618 build_type: a string builder name, like 'release'.
619 milestone: a string milestone, like '55'.
620
621 Returns:
622 A string milestone if build_type represents CrOS build, otherwise
623 return build_type.
624 """
625 return build_type if build_type in build_lib.BARE_BRANCHES else milestone