blob: 7f23939ccaf98687b2c8f2cdfa2b9b5af0d2b05e [file] [log] [blame]
Alex Miller0516e4c2013-06-03 18:07:48 -07001# Copyright (c) 2013 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
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +00005
Richard Barnette6c2b70a2017-01-26 13:40:51 -08006import re
Dan Shi7279a5a2016-04-07 11:04:28 -07007import sys
Alex Miller0516e4c2013-06-03 18:07:48 -07008
9import common
Fang Dengaf30e7c2014-11-15 13:57:03 -080010from autotest_lib.server.cros import provision_actionables as actionables
Allen Li89711f72017-02-21 18:21:52 -080011from autotest_lib.utils import labellib
12from autotest_lib.utils.labellib import Key
Alex Miller0516e4c2013-06-03 18:07:48 -070013
14
15### Constants for label prefixes
Allen Li89711f72017-02-21 18:21:52 -080016CROS_VERSION_PREFIX = Key.CROS_VERSION
17ANDROID_BUILD_VERSION_PREFIX = Key.ANDROID_BUILD_VERSION
18TESTBED_BUILD_VERSION_PREFIX = Key.TESTBED_VERSION
19FW_RW_VERSION_PREFIX = Key.FIRMWARE_RW_VERSION
20FW_RO_VERSION_PREFIX = Key.FIRMWARE_RO_VERSION
Alex Miller0516e4c2013-06-03 18:07:48 -070021
Richard Barnette6c2b70a2017-01-26 13:40:51 -080022_ANDROID_BUILD_REGEX = r'.+/.+/P?([0-9]+|LATEST)'
23_ANDROID_TESTBED_BUILD_REGEX = _ANDROID_BUILD_REGEX + '(,|(#[0-9]+))'
24
Dan Shie44f9c02016-02-18 13:25:05 -080025# Special label to skip provision and run reset instead.
26SKIP_PROVISION = 'skip_provision'
27
Chris Sosae92399e2015-04-24 11:32:59 -070028# Default number of provisions attempts to try if we believe the devserver is
29# flaky.
30FLAKY_DEVSERVER_ATTEMPTS = 2
31
Alex Miller0516e4c2013-06-03 18:07:48 -070032
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000033### Helpers to convert value to label
Richard Barnette6c2b70a2017-01-26 13:40:51 -080034def get_version_label_prefix(image):
35 """
36 Determine a version label prefix from a given image name.
37
38 Parses `image` to determine what kind of image it refers
39 to, and returns the corresponding version label prefix.
40
41 Known version label prefixes are:
42 * `CROS_VERSION_PREFIX` for Chrome OS version strings.
43 These images have names like `cave-release/R57-9030.0.0`.
44 * `ANDROID_BUILD_VERSION_PREFIX` for Android build versions
45 These images have names like
46 `git_mnc-release/shamu-userdebug/2457013`.
47 * `TESTBED_BUILD_VERSION_PREFIX` for Android testbed version
48 specifications. These are either comma separated lists of
49 Android versions, or an Android version with a suffix like
50 '#2', indicating two devices running the given build.
51
52 @param image: The image name to be parsed.
53 @returns: A string that is the prefix of version labels for the type
54 of image identified by `image`.
55
56 """
57 if re.match(_ANDROID_TESTBED_BUILD_REGEX, image, re.I):
58 return TESTBED_BUILD_VERSION_PREFIX
59 elif re.match(_ANDROID_BUILD_REGEX, image, re.I):
60 return ANDROID_BUILD_VERSION_PREFIX
61 else:
62 return CROS_VERSION_PREFIX
63
64
65def image_version_to_label(image):
66 """
67 Return a version label appropriate to the given image name.
68
69 The type of version label is as determined described for
70 `get_version_label_prefix()`, meaning the label will identify a
71 CrOS, Android, or Testbed version.
72
73 @param image: The image name to be parsed.
74 @returns: A string that is the appropriate label name.
75
76 """
77 return get_version_label_prefix(image) + ':' + image
78
79
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000080def cros_version_to_label(image):
Alex Miller0516e4c2013-06-03 18:07:48 -070081 """
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000082 Returns the proper label name for a ChromeOS build of |image|.
Alex Miller0516e4c2013-06-03 18:07:48 -070083
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000084 @param image: A string of the form 'lumpy-release/R28-3993.0.0'
85 @returns: A string that is the appropriate label name.
Alex Miller0516e4c2013-06-03 18:07:48 -070086
87 """
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000088 return CROS_VERSION_PREFIX + ':' + image
Alex Miller0516e4c2013-06-03 18:07:48 -070089
90
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000091def fwro_version_to_label(image):
Dan Shi9cb0eec2014-06-03 09:04:50 -070092 """
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000093 Returns the proper label name for a RO firmware build of |image|.
Tom Wai-Hong Tam2d00cb22016-01-08 06:40:50 +080094
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000095 @param image: A string of the form 'lumpy-release/R28-3993.0.0'
96 @returns: A string that is the appropriate label name.
Tom Wai-Hong Tam2d00cb22016-01-08 06:40:50 +080097
98 """
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000099 return FW_RO_VERSION_PREFIX + ':' + image
Tom Wai-Hong Tam2d00cb22016-01-08 06:40:50 +0800100
101
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000102def fwrw_version_to_label(image):
103 """
104 Returns the proper label name for a RW firmware build of |image|.
Dan Shi9cb0eec2014-06-03 09:04:50 -0700105
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000106 @param image: A string of the form 'lumpy-release/R28-3993.0.0'
107 @returns: A string that is the appropriate label name.
Dan Shi9cb0eec2014-06-03 09:04:50 -0700108
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000109 """
110 return FW_RW_VERSION_PREFIX + ':' + image
Dan Shi9cb0eec2014-06-03 09:04:50 -0700111
112
Alex Miller1968edf2014-02-27 18:11:36 -0800113class _SpecialTaskAction(object):
Alex Miller0516e4c2013-06-03 18:07:48 -0700114 """
Alex Miller1968edf2014-02-27 18:11:36 -0800115 Base class to give a template for mapping labels to tests.
Alex Miller0516e4c2013-06-03 18:07:48 -0700116 """
Alex Miller1968edf2014-02-27 18:11:36 -0800117
Dan Shi7279a5a2016-04-07 11:04:28 -0700118 # A dictionary mapping labels to test names.
119 _actions = {}
Alex Miller0516e4c2013-06-03 18:07:48 -0700120
Dan Shi7279a5a2016-04-07 11:04:28 -0700121 # The name of this special task to be used in output.
122 name = None;
Alex Miller0516e4c2013-06-03 18:07:48 -0700123
Dan Shi7279a5a2016-04-07 11:04:28 -0700124 # Some special tasks require to run before others, e.g., ChromeOS image
125 # needs to be updated before firmware provision. List `_priorities` defines
126 # the order of each label prefix. An element with a smaller index has higher
127 # priority. Not listed ones have the lowest priority.
128 # This property should be overriden in subclass to define its own priorities
129 # across available label prefixes.
130 _priorities = []
Alex Miller1968edf2014-02-27 18:11:36 -0800131
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000132
Alex Miller1968edf2014-02-27 18:11:36 -0800133 @classmethod
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000134 def acts_on(cls, label):
Alex Miller1968edf2014-02-27 18:11:36 -0800135 """
136 Returns True if the label is a label that we recognize as something we
137 know how to act on, given our _actions.
138
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000139 @param label: The label as a string.
Alex Miller1968edf2014-02-27 18:11:36 -0800140 @returns: True if there exists a test to run for this label.
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000141
Alex Miller1968edf2014-02-27 18:11:36 -0800142 """
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000143 return label.split(':')[0] in cls._actions
144
Alex Miller1968edf2014-02-27 18:11:36 -0800145
146 @classmethod
147 def test_for(cls, label):
148 """
149 Returns the test associated with the given (string) label name.
150
151 @param label: The label for which the action is being requested.
152 @returns: The string name of the test that should be run.
153 @raises KeyError: If the name was not recognized as one we care about.
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000154
Alex Miller1968edf2014-02-27 18:11:36 -0800155 """
156 return cls._actions[label]
157
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000158
Alex Milleraa772002014-04-10 17:51:21 -0700159 @classmethod
160 def partition(cls, labels):
161 """
162 Filter a list of labels into two sets: those labels that we know how to
163 act on and those that we don't know how to act on.
164
165 @param labels: A list of strings of labels.
166 @returns: A tuple where the first element is a set of unactionable
167 labels, and the second element is a set of the actionable
168 labels.
169 """
170 capabilities = set()
171 configurations = set()
172
173 for label in labels:
Dan Shie44f9c02016-02-18 13:25:05 -0800174 if label == SKIP_PROVISION:
175 # skip_provision is neither actionable or a capability label.
176 # It doesn't need any handling.
177 continue
178 elif cls.acts_on(label):
Alex Milleraa772002014-04-10 17:51:21 -0700179 configurations.add(label)
180 else:
181 capabilities.add(label)
182
183 return capabilities, configurations
184
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000185
Dan Shi7279a5a2016-04-07 11:04:28 -0700186 @classmethod
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000187 def sort_configurations(cls, configurations):
Dan Shi7279a5a2016-04-07 11:04:28 -0700188 """
189 Sort configurations based on the priority defined in cls._priorities.
190
191 @param configurations: A list of actionable labels.
Dan Shi7279a5a2016-04-07 11:04:28 -0700192
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000193 @return: A sorted list of tuple of (label_prefix, value), the tuples are
194 sorted based on the label_prefix's index in cls._priorities.
Allen Lifda3e232016-10-17 14:54:12 -0700195 """
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000196 # Split a list of labels into a dict mapping name to value. All labels
197 # must be provisionable labels, or else a ValueError
198 # For example, label 'cros-version:lumpy-release/R28-3993.0.0' is split
199 # to {'cros-version': 'lumpy-release/R28-3993.0.0'}
200 split_configurations = dict()
201 for label in configurations:
202 name, _, value = label.partition(':')
203 split_configurations[name] = value
Allen Lifda3e232016-10-17 14:54:12 -0700204
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000205 sort_key = (lambda config:
206 (cls._priorities.index(config[0])
207 if (config[0] in cls._priorities) else sys.maxint))
208 return sorted(split_configurations.items(), key=sort_key)
Dan Shi7279a5a2016-04-07 11:04:28 -0700209
210
Alex Miller1968edf2014-02-27 18:11:36 -0800211class Verify(_SpecialTaskAction):
Alex Miller0516e4c2013-06-03 18:07:48 -0700212 """
Alex Miller1968edf2014-02-27 18:11:36 -0800213 Tests to verify that the DUT is in a sane, known good state that we can run
214 tests on. Failure to verify leads to running Repair.
Alex Miller0516e4c2013-06-03 18:07:48 -0700215 """
Alex Miller1968edf2014-02-27 18:11:36 -0800216
217 _actions = {
Fang Dengaf30e7c2014-11-15 13:57:03 -0800218 'modem_repair': actionables.TestActionable('cellular_StaleModemReboot'),
Don Garrett6f7e8002015-07-23 22:45:37 +0000219 # TODO(crbug.com/404421): set rpm action to power_RPMTest after the RPM
220 # is stable in lab (destiny). The power_RPMTest failure led to reset job
221 # failure and that left dut in Repair Failed. Since the test will fail
222 # anyway due to the destiny lab issue, and test retry will retry the
223 # test in another DUT.
224 # This change temporarily disable the RPM check in reset job.
225 # Another way to do this is to remove rpm dependency from tests' control
226 # file. That will involve changes on multiple control files. This one
227 # line change here is a simple temporary fix.
228 'rpm': actionables.TestActionable('dummy_PassServer'),
Alex Miller1968edf2014-02-27 18:11:36 -0800229 }
230
231 name = 'verify'
232
233
234class Provision(_SpecialTaskAction):
235 """
236 Provisioning runs to change the configuration of the DUT from one state to
237 another. It will only be run on verified DUTs.
238 """
239
Dan Shi7279a5a2016-04-07 11:04:28 -0700240 # ChromeOS update must happen before firmware install, so the dut has the
241 # correct ChromeOS version label when firmware install occurs. The ChromeOS
242 # version label is used for firmware update to stage desired ChromeOS image
243 # on to the servo USB stick.
244 _priorities = [CROS_VERSION_PREFIX,
245 FW_RO_VERSION_PREFIX,
246 FW_RW_VERSION_PREFIX]
247
Alex Miller1968edf2014-02-27 18:11:36 -0800248 # TODO(milleral): http://crbug.com/249555
249 # Create some way to discover and register provisioning tests so that we
250 # don't need to hand-maintain a list of all of them.
251 _actions = {
Fang Deng9d548742015-02-03 11:35:02 -0800252 CROS_VERSION_PREFIX: actionables.TestActionable(
253 'provision_AutoUpdate',
254 extra_kwargs={'disable_sysinfo': False,
255 'disable_before_test_sysinfo': False,
256 'disable_before_iteration_sysinfo': True,
257 'disable_after_test_sysinfo': True,
258 'disable_after_iteration_sysinfo': True}),
Tom Wai-Hong Tam9a237612016-01-08 03:41:46 +0800259 FW_RO_VERSION_PREFIX: actionables.TestActionable(
Fang Dengaf30e7c2014-11-15 13:57:03 -0800260 'provision_FirmwareUpdate'),
Tom Wai-Hong Tam9a237612016-01-08 03:41:46 +0800261 FW_RW_VERSION_PREFIX: actionables.TestActionable(
262 'provision_FirmwareUpdate',
Dan Shi61e407c2016-04-08 14:21:07 -0700263 extra_kwargs={'rw_only': True,
264 'tag': 'rw_only'}),
Simran Basi5ace6f22016-01-06 17:30:44 -0800265 ANDROID_BUILD_VERSION_PREFIX : actionables.TestActionable(
266 'provision_AndroidUpdate'),
Simran Basiadf31312016-06-28 14:23:05 -0700267 TESTBED_BUILD_VERSION_PREFIX : actionables.TestActionable(
268 'provision_TestbedUpdate'),
Alex Miller1968edf2014-02-27 18:11:36 -0800269 }
270
271 name = 'provision'
272
273
274class Cleanup(_SpecialTaskAction):
275 """
276 Cleanup runs after a test fails to try and remove artifacts of tests and
277 ensure the DUT will be in a sane state for the next test run.
278 """
279
280 _actions = {
Fang Dengaf30e7c2014-11-15 13:57:03 -0800281 'cleanup-reboot': actionables.RebootActionable(),
Alex Miller1968edf2014-02-27 18:11:36 -0800282 }
283
284 name = 'cleanup'
285
286
287class Repair(_SpecialTaskAction):
288 """
289 Repair runs when one of the other special tasks fails. It should be able
290 to take a component of the DUT that's in an unknown state and restore it to
291 a good state.
292 """
293
294 _actions = {
295 }
296
297 name = 'repair'
298
299
Alex Milleraa772002014-04-10 17:51:21 -0700300# TODO(milleral): crbug.com/364273
301# Label doesn't really mean label in this context. We're putting things into
302# DEPENDENCIES that really aren't DEPENDENCIES, and we should probably stop
303# doing that.
304def is_for_special_action(label):
305 """
306 If any special task handles the label specially, then we're using the label
307 to communicate that we want an action, and not as an actual dependency that
308 the test has.
309
310 @param label: A string label name.
311 @return True if any special task handles this label specially,
312 False if no special task handles this label.
313 """
314 return (Verify.acts_on(label) or
315 Provision.acts_on(label) or
316 Cleanup.acts_on(label) or
Dan Shie44f9c02016-02-18 13:25:05 -0800317 Repair.acts_on(label) or
318 label == SKIP_PROVISION)
Alex Miller0516e4c2013-06-03 18:07:48 -0700319
320
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000321def join(provision_type, provision_value):
322 """
323 Combine the provision type and value into the label name.
324
325 @param provision_type: One of the constants that are the label prefixes.
326 @param provision_value: A string of the value for this provision type.
327 @returns: A string that is the label name for this (type, value) pair.
328
329 >>> join(CROS_VERSION_PREFIX, 'lumpy-release/R27-3773.0.0')
330 'cros-version:lumpy-release/R27-3773.0.0'
331
332 """
333 return '%s:%s' % (provision_type, provision_value)
334
335
Alex Miller667b5f22014-02-28 15:33:39 -0800336class SpecialTaskActionException(Exception):
337 """
338 Exception raised when a special task fails to successfully run a test that
339 is required.
340
341 This is also a literally meaningless exception. It's always just discarded.
342 """
343
344
345def run_special_task_actions(job, host, labels, task):
346 """
347 Iterate through all `label`s and run any tests on `host` that `task` has
348 corresponding to the passed in labels.
349
350 Emits status lines for each run test, and INFO lines for each skipped label.
351
352 @param job: A job object from a control file.
353 @param host: The host to run actions on.
354 @param labels: The list of job labels to work on.
355 @param task: An instance of _SpecialTaskAction.
356 @returns: None
357 @raises: SpecialTaskActionException if a test fails.
358
359 """
Dan Shi7279a5a2016-04-07 11:04:28 -0700360 capabilities, configurations = task.partition(labels)
Alex Miller667b5f22014-02-28 15:33:39 -0800361
362 for label in capabilities:
Dan Shi7279a5a2016-04-07 11:04:28 -0700363 job.record('INFO', None, task.name,
364 "Can't %s label '%s'." % (task.name, label))
Alex Miller667b5f22014-02-28 15:33:39 -0800365
Dan Shi7279a5a2016-04-07 11:04:28 -0700366 # Sort the configuration labels based on `task._priorities`.
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000367 sorted_configurations = task.sort_configurations(configurations)
368 for name, value in sorted_configurations:
Dan Shi7279a5a2016-04-07 11:04:28 -0700369 action_item = task.test_for(name)
370 success = action_item.execute(job=job, host=host, value=value)
371 if not success:
372 raise SpecialTaskActionException()