blob: 58e0346951c53cf908eb96e63455bdb7b80837d0 [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."""
Xixuan Wu244e0ec2018-05-23 14:49:55 -07006# pylint: disable=dangerous-default-value
Xixuan Wu0c76d5b2017-08-30 16:40:17 -07007
8from distutils import version
Xixuan Wu0c76d5b2017-08-30 16:40:17 -07009import logging
Xinan Lindf0698a2020-02-05 22:38:11 -080010import uuid
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070011
Xinan Lindf0698a2020-02-05 22:38:11 -080012import analytics
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070013import 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.
Xinan Linc8647112020-02-04 16:45:56 -080054 dimensions, a comma separated lists of labels. Each label is in
55 the form of 'key:value'.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070056 exclude_board_families, a common separated list of board family not to
57 run task on. Boards belong to one of the board family in this list
58 would be added to task_info.exclude_boards.
Po-Hsien Wang6d589732018-05-15 17:19:34 -070059 exclude_boards, a comma separated list of boards not to run this task
60 on. Default is None, which allows this task to run on all boards.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070061 If same board is specified in 'boards' and 'exclude_boards', we
62 exclude this board.
Xixuan Wu89897182019-01-03 15:28:01 -080063 models, a comma separated list of models to run this task on. Default
64 is None, which allows this task to run on all models. If same model
65 is specified in 'models' and 'exclude_models', we exclude this
66 model.
67 exclude_models, a comma separated list of models not to run this task
68 on. Default is None, which allows this task to run on all models.
C Shapiro09108252019-08-01 14:52:52 -050069 any_model, set to True to not pass the model parameter and allow
70 a test suite to run any/all models available for testing.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070071 priority, the string name of a priority from constants.Priorities.
72 timeout, the max lifetime of the suite in hours.
73 cros_build_spec, spec used to determine the ChromeOS build to test
74 with a firmware build, e.g., tot, R41 etc.
75 firmware_rw_build_spec, spec used to determine the firmware RW build
76 test with a ChromeOS build.
77 firmware_ro_build_spec, spec used to determine the firmware RO build
78 test with a ChromeOS build.
79 test_source, the source of test code when firmware will be updated in
80 the test. The value can be 'firmware_rw', 'firmware_ro' or 'cros'.
81 job_retry, set to True to enable job-level retry. Default is False.
Xixuan Wu80531932017-10-12 17:26:51 -070082 no_delay, set to True to raise the priority of this task in task.
83 force, set to True to schedule this suite no matter whether there's
84 duplicate jobs before.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070085 queue, so the suite jobs can start running tests with no waiting.
86 hour, an integer specifying the hour that a nightly run should be
87 triggered, default is set to 21.
88 day, an integer specifying the day of a week that a weekly run should
89 be triggered, default is set to 5 (Saturday).
90 os_type, type of OS, e.g., cros, brillo, android. Default is cros.
91 The argument is required for android/brillo builds.
92 launch_control_branches, comma separated string of launch control
93 branches. The argument is required and only applicable for
94 android/brillo builds.
95 launch_control_targets, comma separated string of build targets for
96 launch control builds. The argument is required and only
97 applicable for android/brillo builds.
98 testbed_dut_count, number of duts to test when using a testbed.
Xixuan Wu83118dd2018-08-27 12:11:35 -070099 board_family_config: A board family dictionary mapping board_family name
100 to its corresponding boards.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700101 tot: The tot manager for checking ToT. If it's None, a new tot_manager
102 instance will be initialized.
103 """
Xixuan Wu5451a662017-10-17 10:57:40 -0700104 # Indicate whether there're suites get pushed into taskqueue for this task.
105 self.is_pushed = False
106
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700107 self.name = task_info.name
108 self.suite = task_info.suite
109 self.branch_specs = task_info.branch_specs
110 self.pool = task_info.pool
111 self.num = task_info.num
112 self.priority = task_info.priority
113 self.timeout = task_info.timeout
114 self.cros_build_spec = task_info.cros_build_spec
115 self.firmware_rw_build_spec = task_info.firmware_rw_build_spec
116 self.firmware_ro_build_spec = task_info.firmware_ro_build_spec
117 self.test_source = task_info.test_source
118 self.job_retry = task_info.job_retry
119 self.no_delay = task_info.no_delay
Xixuan Wu80531932017-10-12 17:26:51 -0700120 self.force = task_info.force
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700121 self.os_type = task_info.os_type
Xinan Lin3ba18a02019-08-13 15:44:55 -0700122 self.frontdoor = task_info.frontdoor
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700123 self.testbed_dut_count = task_info.testbed_dut_count
Xixuan Wu008ee832017-10-12 16:59:34 -0700124 self.hour = task_info.hour
125 self.day = task_info.day
Craig Bergstrom58263d32018-04-26 14:11:35 -0600126 self.only_hwtest_sanity_required = task_info.only_hwtest_sanity_required
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700127
128 if task_info.lc_branches:
129 self.launch_control_branches = [
130 t.strip() for t in task_info.lc_branches.split(',')]
131 else:
132 self.launch_control_branches = []
133
134 if task_info.lc_targets:
135 self.launch_control_targets = [
136 t.strip() for t in task_info.lc_targets.split(',')]
137 else:
138 self.launch_control_targets = []
139
140 if task_info.boards:
141 self.boards = [t.strip() for t in task_info.boards.split(',')]
142 else:
143 self.boards = []
144
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700145 if task_info.exclude_boards:
146 self.exclude_boards = [
147 t.strip() for t in task_info.exclude_boards.split(',')]
148 else:
149 self.exclude_boards = []
150
Xixuan Wu89897182019-01-03 15:28:01 -0800151 if task_info.models:
152 self.models = [t.strip() for t in task_info.models.split(',')]
153 else:
154 self.models = []
155
156 if task_info.exclude_models:
157 self.exclude_models = [
158 t.strip() for t in task_info.exclude_models.split(',')]
159 else:
160 self.exclude_models = []
161
C Shapiro09108252019-08-01 14:52:52 -0500162 self.any_model = task_info.any_model
163
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700164 if task_info.board_families:
165 # Finetune the allowed boards list with board_families & boards.
166 families = [family.strip()
167 for family in task_info.board_families.split(',')]
168 for family in families:
169 self.boards += board_family_config.get(family, [])
Xixuan Wu89897182019-01-03 15:28:01 -0800170
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700171 if task_info.exclude_board_families:
172 # Finetune the disallowed boards list with exclude_board_families
173 # & exclude_boards.
174 families = [family.strip()
175 for family in task_info.exclude_board_families.split(',')]
176 for family in families:
177 self.exclude_boards += board_family_config.get(family, [])
178
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700179 if tot is None:
180 self.tot_manager = tot_manager.TotMilestoneManager()
181 else:
182 self.tot_manager = tot
183
Xinan Linc8647112020-02-04 16:45:56 -0800184 self.dimensions = task_info.dimensions
185
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700186 self._set_spec_compare_info()
Xinan Lindf0698a2020-02-05 22:38:11 -0800187 self.job_section = analytics.ScheduleJobSection(task_info)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700188
Xinan Lin028f9582019-12-11 10:55:33 -0800189 def schedule(self, launch_control_builds, cros_builds_tuple,
190 firmware_builds, configs):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700191 """Schedule the task by its settings.
192
193 Args:
194 launch_control_builds: the build dict for Android boards, see
195 return value of |get_launch_control_builds|.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600196 cros_builds_tuple: the two-tuple of build dicts for ChromeOS boards,
197 see return value of |get_cros_builds|.
Xinan Lin028f9582019-12-11 10:55:33 -0800198 firmware_builds: a dict of firmware artifact, see return value of
199 |base_event.get_firmware_builds|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700200 configs: a config_reader.Configs object.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700201
202 Raises:
203 SchedulingError: if tasks that should be scheduled fail to schedule.
Xixuan Wu5451a662017-10-17 10:57:40 -0700204
205 Returns:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700206 A boolean indicator; true if there were any suites related to this
207 task which got pushed into the suites queue.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700208 """
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700209 assert configs.lab_config is not None
Xixuan Wu5451a662017-10-17 10:57:40 -0700210 self.is_pushed = False
211
Craig Bergstrom58263d32018-04-26 14:11:35 -0600212 branch_builds, relaxed_builds = cros_builds_tuple
213 builds_dict = branch_builds
214 if self.only_hwtest_sanity_required:
Xinan Linae7d6372019-09-12 14:42:10 -0700215 builds_dict = _split_unibuilds(relaxed_builds, configs)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600216
Xinan Lindf0698a2020-02-05 22:38:11 -0800217 # Record all target boards and models into job section.
218 lab_config = configs.lab_config
219 models_by_board = lab_config.get_cros_model_map() if lab_config else {}
220 boards = self.boards if self.boards else lab_config.get_cros_board_list()
221 for b in boards:
222 if self.exclude_boards and b in self.exclude_boards:
223 continue
224 self.job_section.add_board(b)
225 models = self.models or models_by_board.get(b, [])
226 for m in models:
227 if m and '%s_%s' % (b, m) not in self.exclude_models:
228 self.job_section.add_model(m)
229
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700230 logging.info('######## Scheduling task %s ########', self.name)
231 if self.os_type == build_lib.OS_TYPE_CROS:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600232 if not builds_dict:
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700233 logging.info('No CrOS build to run, skip running.')
234 else:
Xinan Lin028f9582019-12-11 10:55:33 -0800235 self._schedule_cros_builds(builds_dict, firmware_builds, configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700236 else:
237 if not launch_control_builds:
238 logging.info('No Android build to run, skip running.')
239 else:
240 self._schedule_launch_control_builds(launch_control_builds)
Xinan Lindf0698a2020-02-05 22:38:11 -0800241 upload_result = False
242 try:
243 upload_result = self.job_section.upload()
244 # For any exceptions from BQ, only log it and move on.
245 except Exception as e: #pylint: disable=broad-except
246 logging.exception(str(e))
247 if not upload_result:
248 logging.warning('Failed to insert row: %r', self.job_section)
Xixuan Wu5451a662017-10-17 10:57:40 -0700249 return self.is_pushed
250
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700251 def _set_spec_compare_info(self):
252 """Set branch spec compare info for task for further check."""
253 self._bare_branches = []
254 self._version_equal_constraint = False
255 self._version_gte_constraint = False
256 self._version_lte_constraint = False
257
258 if not self.branch_specs:
259 # Any milestone is OK.
260 self._numeric_constraint = version.LooseVersion('0')
261 else:
262 self._numeric_constraint = None
263 for spec in self.branch_specs:
264 if 'tot' in spec.lower():
265 # Convert spec >=tot-1 to >=RXX.
266 tot_str = spec[spec.index('tot'):]
267 spec = spec.replace(
268 tot_str, self.tot_manager.convert_tot_spec(tot_str))
269
270 if spec.startswith('>='):
271 self._numeric_constraint = version.LooseVersion(
272 spec.lstrip('>=R'))
273 self._version_gte_constraint = True
274 elif spec.startswith('<='):
275 self._numeric_constraint = version.LooseVersion(
276 spec.lstrip('<=R'))
277 self._version_lte_constraint = True
278 elif spec.startswith('=='):
279 self._version_equal_constraint = True
280 self._numeric_constraint = version.LooseVersion(
281 spec.lstrip('==R'))
282 else:
283 self._bare_branches.append(spec)
284
285 def _fits_spec(self, branch):
286 """Check if a branch is deemed OK by this task's branch specs.
287
288 Will return whether a branch 'fits' the specifications stored in this task.
289
290 Examples:
291 Assuming tot=R40
292 t = Task('Name', 'suite', ['factory', '>=tot-1'])
293 t._fits_spec('factory') # True
294 t._fits_spec('40') # True
295 t._fits_spec('38') # False
296 t._fits_spec('firmware') # False
297
298 Args:
299 branch: the branch to check.
300
301 Returns:
302 True if branch 'fits' with stored specs, False otherwise.
303 """
304 if branch in build_lib.BARE_BRANCHES:
305 return branch in self._bare_branches
306
307 if self._numeric_constraint:
308 if self._version_equal_constraint:
309 return version.LooseVersion(branch) == self._numeric_constraint
310 elif self._version_gte_constraint:
311 return version.LooseVersion(branch) >= self._numeric_constraint
312 elif self._version_lte_constraint:
313 return version.LooseVersion(branch) <= self._numeric_constraint
314 else:
315 return version.LooseVersion(branch) >= self._numeric_constraint
316 else:
317 return False
318
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700319 def _get_latest_firmware_build_from_lab_config(self, spec, board,
320 lab_config):
321 """Get latest firmware from lab config file.
322
323 Args:
324 spec: a string build spec for RO or RW firmware, eg. firmware,
325 cros. For RO firmware, the value can also be released_ro_X.
326 board: a string board against which this task will run suite job.
327 lab_config: a config.LabConfig object, to read lab config file.
328
329 Returns:
330 A string latest firmware build.
331
332 Raises:
333 ValueError: if no firmware build list is found in lab config file.
334 """
335 index = int(spec[len(_RELEASE_RO_FIRMWARE_SPEC):])
336 released_ro_builds = lab_config.get_firmware_ro_build_list(
337 'RELEASED_RO_BUILDS_%s' % board).split(',')
338 if len(released_ro_builds) < index:
339 raise ValueError('No %dth ro_builds in the lab_config firmware '
340 'list %r' % (index, released_ro_builds))
341
342 logging.debug('Get ro_build: %s', released_ro_builds[index - 1])
343 return released_ro_builds[index - 1]
344
Xinan Lin028f9582019-12-11 10:55:33 -0800345 def _get_firmware_build(self, spec, board, firmware_build_dict, lab_config):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700346 """Get the firmware build name to test with ChromeOS build.
347
348 Args:
349 spec: a string build spec for RO or RW firmware, eg. firmware,
350 cros. For RO firmware, the value can also be released_ro_X.
351 board: a string board against which this task will run suite job.
Xinan Lin028f9582019-12-11 10:55:33 -0800352 firmware_build_dict: a dict of firmware artifacts, see return value of
353 |base_event.get_firmware_builds|.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700354 lab_config: a config.LabConfig object, to read lab config file.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700355
356 Returns:
357 A string firmware build name.
358
359 Raises:
360 ValueError: if failing to get firmware from lab config file;
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700361 """
362 if not spec or spec == 'stable':
363 # TODO(crbug.com/577316): Query stable RO firmware.
364 logging.debug('%s RO firmware build is not supported.', spec)
365 return None
366
367 try:
368 if spec.startswith(_RELEASE_RO_FIRMWARE_SPEC):
369 # For RO firmware whose value is released_ro_X, where X is the index of
370 # the list defined in lab config file:
371 # CROS/RELEASED_RO_BUILDS_[board].
372 # For example, for spec 'released_ro_2', and lab config file
373 # CROS/RELEASED_RO_BUILDS_veyron_jerry: build1,build2,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600374 # return firmware RO build should be 'build2'.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700375 return self._get_latest_firmware_build_from_lab_config(
376 spec, board, lab_config)
Xinan Lin028f9582019-12-11 10:55:33 -0800377 elif firmware_build_dict:
378 return firmware_build_dict.get((spec, board), None)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700379 else:
Xinan Lin028f9582019-12-11 10:55:33 -0800380 return None
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700381 except ValueError as e:
382 logging.warning('Failed to get firmware from lab config file'
383 'for spec %s, board %s: %s', spec, board, str(e))
384 return None
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700385
C Shapiro7f24a002017-12-05 14:25:09 -0700386 def _push_suite(
387 self,
Xinan Lindf0698a2020-02-05 22:38:11 -0800388 task_id=None,
C Shapiro7f24a002017-12-05 14:25:09 -0700389 board=None,
390 model=None,
391 cros_build=None,
392 firmware_rw_build=None,
393 firmware_ro_build=None,
394 test_source_build=None,
395 launch_control_build=None,
Xixuan Wubb74a372018-08-21 17:37:08 -0700396 run_prod_code=False,
Xixuan Wu028f6732019-04-11 14:47:42 -0700397 is_skylab=False,
398 override_pool='',
399 override_qs_account=''):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700400 """Schedule suite job for the task by pushing suites to SuiteQueue.
401
402 Args:
Xinan Lindf0698a2020-02-05 22:38:11 -0800403 task_id: the id to track this task in exectuion.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700404 board: the board against which this suite job run.
C Shapiro7f24a002017-12-05 14:25:09 -0700405 model: the model name for unibuild.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700406 cros_build: the CrOS build of this suite job.
407 firmware_rw_build: Firmware RW build to run this suite job with.
408 firmware_ro_build: Firmware RO build to run this suite job with.
409 test_source_build: Test source build, used for server-side
410 packaging of this suite job.
411 launch_control_build: the launch control build of this suite job.
412 run_prod_code: If True, the suite will run the test code that lives
413 in prod aka the test code currently on the lab servers. If
414 False, the control files and test code for this suite run will
415 be retrieved from the build artifacts. Default is False.
Xixuan Wubb74a372018-08-21 17:37:08 -0700416 is_skylab: If True, schedule this suite to skylab, otherwise schedule
417 it to AFE. Default is False.
Xixuan Wu028f6732019-04-11 14:47:42 -0700418 override_pool: A string to indicate pool of quota scheduler.
419 override_qs_account: A string of quota scheduler account.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700420 """
421 android_build = None
422 testbed_build = None
423
424 if self.testbed_dut_count:
425 launch_control_build = '%s#%d' % (launch_control_build,
426 self.testbed_dut_count)
427 test_source_build = launch_control_build
428 board = '%s-%d' % (board, self.testbed_dut_count)
429
430 if launch_control_build:
431 if not self.testbed_dut_count:
432 android_build = launch_control_build
433 else:
434 testbed_build = launch_control_build
435
436 suite_job_parameters = {
437 'suite': self.suite,
Xinan Lindf0698a2020-02-05 22:38:11 -0800438 'task_id': task_id,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700439 'board': board,
C Shapiro7f24a002017-12-05 14:25:09 -0700440 'model': model,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700441 build_lib.BuildVersionKey.CROS_VERSION: cros_build,
442 build_lib.BuildVersionKey.FW_RW_VERSION: firmware_rw_build,
443 build_lib.BuildVersionKey.FW_RO_VERSION: firmware_ro_build,
444 build_lib.BuildVersionKey.ANDROID_BUILD_VERSION: android_build,
445 build_lib.BuildVersionKey.TESTBED_BUILD_VERSION: testbed_build,
446 'num': self.num,
447 'pool': self.pool,
448 'priority': self.priority,
449 'timeout': self.timeout,
450 'timeout_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
451 'max_runtime_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
Xixuan Wu2ba72652017-09-15 15:49:42 -0700452 'no_wait_for_results': not self.job_retry,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700453 'test_source_build': test_source_build,
454 'job_retry': self.job_retry,
455 'no_delay': self.no_delay,
Xixuan Wu80531932017-10-12 17:26:51 -0700456 'force': self.force,
Xinan Linc8647112020-02-04 16:45:56 -0800457 'dimensions': self.dimensions,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700458 'run_prod_code': run_prod_code,
Xixuan Wubb74a372018-08-21 17:37:08 -0700459 'is_skylab': is_skylab,
Xinan Lin6e097382019-08-27 18:43:35 -0700460 'is_frontdoor': self.frontdoor,
Xixuan Wu028f6732019-04-11 14:47:42 -0700461 'override_pool': override_pool,
462 'override_qs_account': override_qs_account,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700463 }
464
Xinan Lin9e4917d2019-11-04 10:58:47 -0800465 task_executor.push(task_executor.SUITES_QUEUE,
466 tag=self.suite,
467 **suite_job_parameters)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700468 logging.info('Pushing task %r into taskqueue', suite_job_parameters)
Xixuan Wu5451a662017-10-17 10:57:40 -0700469 self.is_pushed = True
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700470
Xinan Lin028f9582019-12-11 10:55:33 -0800471 def _schedule_cros_builds(self, build_dict, firmware_build_dict, configs):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700472 """Schedule tasks with branch builds.
473
474 Args:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600475 build_dict: the build dict for ChromeOS boards, see return
Xinan Linea1efcb2019-12-30 23:46:42 -0800476 value of |build_lib.get_cros_builds|.
Xinan Lin028f9582019-12-11 10:55:33 -0800477 firmware_build_dict: a dict of firmware artifact, see return value of
478 |base_event.get_firmware_builds|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700479 configs: A config_reader.Configs object.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700480 """
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700481 lab_config = configs.lab_config
C Shapiro7f24a002017-12-05 14:25:09 -0700482 models_by_board = lab_config.get_cros_model_map() if lab_config else {}
C Shapiro09108252019-08-01 14:52:52 -0500483 model_agnostic_cros_builds = set()
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):
Xinan Lindf0698a2020-02-05 22:38:11 -0800502 msg = ("branch_build spec %s doesn't fit this task's "
503 "requirement: %s") % (branch_build_spec,
504 ",".join(self.branch_specs))
505 logging.debug(msg)
506 self.job_section.add_schedule_job(board, passed_model, msg=msg)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700507 continue
508
Xinan Lindf0698a2020-02-05 22:38:11 -0800509 # Record this build as it matches both board and branch specs.
510 if self.only_hwtest_sanity_required:
511 self.job_section.add_matched_relax_build(
512 board, build_type, milestone, manifest)
513 else:
514 self.job_section.add_matched_build(
515 board, build_type, milestone, manifest)
516
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700517 firmware_rw_build = None
518 firmware_ro_build = None
519 if self.firmware_rw_build_spec or self.firmware_ro_build_spec:
520 firmware_rw_build = self._get_firmware_build(
Xinan Lin028f9582019-12-11 10:55:33 -0800521 self.firmware_rw_build_spec, board, firmware_build_dict, lab_config)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700522 firmware_ro_build = self._get_firmware_build(
Xinan Lin028f9582019-12-11 10:55:33 -0800523 self.firmware_ro_build_spec, board, firmware_build_dict, lab_config)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700524
525 if not firmware_ro_build and self.firmware_ro_build_spec:
Xinan Lindf0698a2020-02-05 22:38:11 -0800526 msg = 'No RO firmware ro build to run, skip running'
527 logging.debug(msg)
528 self.job_section.add_schedule_job(board, passed_model, msg=msg)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700529 continue
530
531 if self.test_source == build_lib.BuildType.FIRMWARE_RW:
532 test_source_build = firmware_rw_build
533 else:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700534 # Default test source build to CrOS build if it's not specified.
535 # Past versions chose based on run_prod_code, but we no longer respect
536 # that option and scheduler settings should always set it to False.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700537 test_source_build = cros_build
538
Xinan Lindf0698a2020-02-05 22:38:11 -0800539 # Record the matched firwmare build.
540 if firmware_rw_build:
541 self.job_section.add_matched_fw_build(
542 board,
543 self.firmware_rw_build_spec,
544 firmware_rw_build,
545 read_only=False)
546 if firmware_ro_build:
547 self.job_section.add_matched_fw_build(
548 board,
549 self.firmware_ro_build_spec,
550 firmware_ro_build,
551 read_only=True)
552
Xixuan Wub4b2f412019-05-03 11:22:31 -0700553 hwtest_board = build_lib.reshape_board(board)
Xinan Lin0550f492020-01-21 16:25:53 -0800554
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000555 models = models_by_board.get(board, [None])
C Shapiro7f24a002017-12-05 14:25:09 -0700556
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000557 for model in models:
558 if ((passed_model is not None and model == passed_model) or
559 passed_model is None):
Xixuan Wua41efa22019-05-17 14:28:04 -0700560 full_model_name = '%s_%s' % (board, model)
561 # Respect exclude first.
562 if self.exclude_models and full_model_name in self.exclude_models:
563 logging.debug("Skip model %s as it's in exclude model list %s",
564 model, self.exclude_models)
565 continue
566
567 if self.models and full_model_name not in self.models:
568 logging.debug("Skip model %s as it's not in support model list %s",
569 model, self.models)
570 continue
571
C Shapiro09108252019-08-01 14:52:52 -0500572 explicit_model = model
573
574 if self.any_model:
Xinan Lin3ba18a02019-08-13 15:44:55 -0700575 explicit_model = None
C Shapiro09108252019-08-01 14:52:52 -0500576 unique_build = str(cros_build)
577 if unique_build in model_agnostic_cros_builds:
578 # Skip since we've already run with no explicit model set.
Xinan Lindf0698a2020-02-05 22:38:11 -0800579 msg = "Skip model %s as any_model enabled for this job." % model
580 self.job_section.add_schedule_job(board, model, msg=msg)
C Shapiro09108252019-08-01 14:52:52 -0500581 continue
582 model_agnostic_cros_builds.add(unique_build)
583
Xinan Lindf0698a2020-02-05 22:38:11 -0800584 task_id = str(uuid.uuid1())
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000585 self._push_suite(
Xinan Lindf0698a2020-02-05 22:38:11 -0800586 task_id=task_id,
Xixuan Wub4b2f412019-05-03 11:22:31 -0700587 board=hwtest_board,
C Shapiro09108252019-08-01 14:52:52 -0500588 model=explicit_model,
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000589 cros_build=cros_build,
590 firmware_rw_build=firmware_rw_build,
591 firmware_ro_build=firmware_ro_build,
Xinan Lin0550f492020-01-21 16:25:53 -0800592 test_source_build=test_source_build)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700593
Xinan Lindf0698a2020-02-05 22:38:11 -0800594 self.job_section.add_schedule_job(board, model, task_id=task_id)
595
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700596 def _schedule_launch_control_builds(self, launch_control_builds):
597 """Schedule tasks with launch control builds.
598
599 Args:
600 launch_control_builds: the build dict for Android boards.
601 """
602 for board, launch_control_build in launch_control_builds.iteritems():
603 logging.debug('Running %s on %s', self.name, board)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700604 if self.exclude_boards and board in self.exclude_boards:
605 logging.debug('Board %s is in excluded board list: %s',
606 board, self.exclude_boards)
607 continue
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700608 if self.boards and board not in self.boards:
609 logging.debug('Board %s is not in supported board list: %s',
610 board, self.boards)
611 continue
612
613 for android_build in launch_control_build:
614 if not any([branch in android_build
615 for branch in self.launch_control_branches]):
616 logging.debug('Branch %s is not required to run for task '
617 '%s', android_build, self.name)
618 continue
619
620 self._push_suite(board=board,
621 test_source_build=android_build,
622 launch_control_build=android_build)
623
624
625def _pick_branch(build_type, milestone):
626 """Select branch based on build type.
627
628 If the build_type is a bare branch, return build_type as the build spec.
629 If the build_type is a normal CrOS branch, return milestone as the build
630 spec.
631
632 Args:
633 build_type: a string builder name, like 'release'.
634 milestone: a string milestone, like '55'.
635
636 Returns:
637 A string milestone if build_type represents CrOS build, otherwise
638 return build_type.
639 """
640 return build_type if build_type in build_lib.BARE_BRANCHES else milestone
Xinan Linae7d6372019-09-12 14:42:10 -0700641
642
643def _split_unibuilds(build_dict, configs):
644 """Split the uni-builds to all models under a board.
645
646 Args:
647 build_dict: the build dict for ChromeOS boards, see return
Xinan Linea1efcb2019-12-30 23:46:42 -0800648 value of |build_lib.get_cros_builds|.
Xinan Linae7d6372019-09-12 14:42:10 -0700649 configs: a config_reader.Configs object.
650
651 Returns:
652 A build dict.
653 """
654 models_by_board = configs.lab_config.get_cros_model_map()
655 if not models_by_board:
656 return build_dict
657 all_branch_build_dict = {}
658 for (board, model, config, milestone), platform in build_dict.iteritems():
659 uni_build_models = models_by_board.get(board)
660 if uni_build_models is not None and model is None:
661 for uni_build_model in uni_build_models:
662 model_key = (board, uni_build_model, config, milestone)
663 _add_build_dict(all_branch_build_dict, model_key, platform)
664 continue
665 build_key = (board, model, config, milestone)
666 _add_build_dict(all_branch_build_dict, build_key, platform)
667
668 return all_branch_build_dict
669
670
671def _add_build_dict(build_dict, key, value):
672 """A wrapper to add or update an item in build_dict."""
673 cur_manifest = build_dict.get(key)
674 if cur_manifest is None:
675 build_dict[key] = value
676 return
677 build_dict[key] = max(
678 [cur_manifest, value], key=version.LooseVersion)