blob: 5e7608d2af113ac58dd84edbe12cea715d623efc [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
Dan Shi7279a5a2016-04-07 11:04:28 -07006import sys
Alex Miller0516e4c2013-06-03 18:07:48 -07007
8import common
Fang Dengaf30e7c2014-11-15 13:57:03 -08009from autotest_lib.server.cros import provision_actionables as actionables
Alex Miller0516e4c2013-06-03 18:07:48 -070010
11
12### Constants for label prefixes
13CROS_VERSION_PREFIX = 'cros-version'
Simran Basi5ace6f22016-01-06 17:30:44 -080014ANDROID_BUILD_VERSION_PREFIX = 'ab-version'
Kevin Cheng84a71ba2016-07-14 11:03:57 -070015TESTBED_BUILD_VERSION_PREFIX = 'testbed-version'
Dan Shi0723bf52015-06-24 10:52:38 -070016FW_RW_VERSION_PREFIX = 'fwrw-version'
Dan Shi36cfd832014-10-10 13:38:51 -070017FW_RO_VERSION_PREFIX = 'fwro-version'
Alex Miller0516e4c2013-06-03 18:07:48 -070018
Dan Shie44f9c02016-02-18 13:25:05 -080019# Special label to skip provision and run reset instead.
20SKIP_PROVISION = 'skip_provision'
21
Chris Sosae92399e2015-04-24 11:32:59 -070022# Default number of provisions attempts to try if we believe the devserver is
23# flaky.
24FLAKY_DEVSERVER_ATTEMPTS = 2
25
Alex Miller0516e4c2013-06-03 18:07:48 -070026
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000027### Helpers to convert value to label
28def cros_version_to_label(image):
Alex Miller0516e4c2013-06-03 18:07:48 -070029 """
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000030 Returns the proper label name for a ChromeOS build of |image|.
Alex Miller0516e4c2013-06-03 18:07:48 -070031
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000032 @param image: A string of the form 'lumpy-release/R28-3993.0.0'
33 @returns: A string that is the appropriate label name.
Alex Miller0516e4c2013-06-03 18:07:48 -070034
35 """
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000036 return CROS_VERSION_PREFIX + ':' + image
Alex Miller0516e4c2013-06-03 18:07:48 -070037
38
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000039def fwro_version_to_label(image):
Dan Shi9cb0eec2014-06-03 09:04:50 -070040 """
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000041 Returns the proper label name for a RO firmware build of |image|.
Tom Wai-Hong Tam2d00cb22016-01-08 06:40:50 +080042
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000043 @param image: A string of the form 'lumpy-release/R28-3993.0.0'
44 @returns: A string that is the appropriate label name.
Tom Wai-Hong Tam2d00cb22016-01-08 06:40:50 +080045
46 """
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000047 return FW_RO_VERSION_PREFIX + ':' + image
Tom Wai-Hong Tam2d00cb22016-01-08 06:40:50 +080048
49
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000050def fwrw_version_to_label(image):
51 """
52 Returns the proper label name for a RW firmware build of |image|.
Dan Shi9cb0eec2014-06-03 09:04:50 -070053
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000054 @param image: A string of the form 'lumpy-release/R28-3993.0.0'
55 @returns: A string that is the appropriate label name.
Dan Shi9cb0eec2014-06-03 09:04:50 -070056
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000057 """
58 return FW_RW_VERSION_PREFIX + ':' + image
Dan Shi9cb0eec2014-06-03 09:04:50 -070059
60
Alex Miller1968edf2014-02-27 18:11:36 -080061class _SpecialTaskAction(object):
Alex Miller0516e4c2013-06-03 18:07:48 -070062 """
Alex Miller1968edf2014-02-27 18:11:36 -080063 Base class to give a template for mapping labels to tests.
Alex Miller0516e4c2013-06-03 18:07:48 -070064 """
Alex Miller1968edf2014-02-27 18:11:36 -080065
Dan Shi7279a5a2016-04-07 11:04:28 -070066 # A dictionary mapping labels to test names.
67 _actions = {}
Alex Miller0516e4c2013-06-03 18:07:48 -070068
Dan Shi7279a5a2016-04-07 11:04:28 -070069 # The name of this special task to be used in output.
70 name = None;
Alex Miller0516e4c2013-06-03 18:07:48 -070071
Dan Shi7279a5a2016-04-07 11:04:28 -070072 # Some special tasks require to run before others, e.g., ChromeOS image
73 # needs to be updated before firmware provision. List `_priorities` defines
74 # the order of each label prefix. An element with a smaller index has higher
75 # priority. Not listed ones have the lowest priority.
76 # This property should be overriden in subclass to define its own priorities
77 # across available label prefixes.
78 _priorities = []
Alex Miller1968edf2014-02-27 18:11:36 -080079
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000080
Alex Miller1968edf2014-02-27 18:11:36 -080081 @classmethod
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000082 def acts_on(cls, label):
Alex Miller1968edf2014-02-27 18:11:36 -080083 """
84 Returns True if the label is a label that we recognize as something we
85 know how to act on, given our _actions.
86
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000087 @param label: The label as a string.
Alex Miller1968edf2014-02-27 18:11:36 -080088 @returns: True if there exists a test to run for this label.
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000089
Alex Miller1968edf2014-02-27 18:11:36 -080090 """
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +000091 return label.split(':')[0] in cls._actions
92
Alex Miller1968edf2014-02-27 18:11:36 -080093
94 @classmethod
95 def test_for(cls, label):
96 """
97 Returns the test associated with the given (string) label name.
98
99 @param label: The label for which the action is being requested.
100 @returns: The string name of the test that should be run.
101 @raises KeyError: If the name was not recognized as one we care about.
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000102
Alex Miller1968edf2014-02-27 18:11:36 -0800103 """
104 return cls._actions[label]
105
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000106
Alex Milleraa772002014-04-10 17:51:21 -0700107 @classmethod
108 def partition(cls, labels):
109 """
110 Filter a list of labels into two sets: those labels that we know how to
111 act on and those that we don't know how to act on.
112
113 @param labels: A list of strings of labels.
114 @returns: A tuple where the first element is a set of unactionable
115 labels, and the second element is a set of the actionable
116 labels.
117 """
118 capabilities = set()
119 configurations = set()
120
121 for label in labels:
Dan Shie44f9c02016-02-18 13:25:05 -0800122 if label == SKIP_PROVISION:
123 # skip_provision is neither actionable or a capability label.
124 # It doesn't need any handling.
125 continue
126 elif cls.acts_on(label):
Alex Milleraa772002014-04-10 17:51:21 -0700127 configurations.add(label)
128 else:
129 capabilities.add(label)
130
131 return capabilities, configurations
132
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000133
Dan Shi7279a5a2016-04-07 11:04:28 -0700134 @classmethod
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000135 def sort_configurations(cls, configurations):
Dan Shi7279a5a2016-04-07 11:04:28 -0700136 """
137 Sort configurations based on the priority defined in cls._priorities.
138
139 @param configurations: A list of actionable labels.
Dan Shi7279a5a2016-04-07 11:04:28 -0700140
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000141 @return: A sorted list of tuple of (label_prefix, value), the tuples are
142 sorted based on the label_prefix's index in cls._priorities.
Allen Lifda3e232016-10-17 14:54:12 -0700143 """
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000144 # Split a list of labels into a dict mapping name to value. All labels
145 # must be provisionable labels, or else a ValueError
146 # For example, label 'cros-version:lumpy-release/R28-3993.0.0' is split
147 # to {'cros-version': 'lumpy-release/R28-3993.0.0'}
148 split_configurations = dict()
149 for label in configurations:
150 name, _, value = label.partition(':')
151 split_configurations[name] = value
Allen Lifda3e232016-10-17 14:54:12 -0700152
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000153 sort_key = (lambda config:
154 (cls._priorities.index(config[0])
155 if (config[0] in cls._priorities) else sys.maxint))
156 return sorted(split_configurations.items(), key=sort_key)
Dan Shi7279a5a2016-04-07 11:04:28 -0700157
158
Alex Miller1968edf2014-02-27 18:11:36 -0800159class Verify(_SpecialTaskAction):
Alex Miller0516e4c2013-06-03 18:07:48 -0700160 """
Alex Miller1968edf2014-02-27 18:11:36 -0800161 Tests to verify that the DUT is in a sane, known good state that we can run
162 tests on. Failure to verify leads to running Repair.
Alex Miller0516e4c2013-06-03 18:07:48 -0700163 """
Alex Miller1968edf2014-02-27 18:11:36 -0800164
165 _actions = {
Fang Dengaf30e7c2014-11-15 13:57:03 -0800166 'modem_repair': actionables.TestActionable('cellular_StaleModemReboot'),
Don Garrett6f7e8002015-07-23 22:45:37 +0000167 # TODO(crbug.com/404421): set rpm action to power_RPMTest after the RPM
168 # is stable in lab (destiny). The power_RPMTest failure led to reset job
169 # failure and that left dut in Repair Failed. Since the test will fail
170 # anyway due to the destiny lab issue, and test retry will retry the
171 # test in another DUT.
172 # This change temporarily disable the RPM check in reset job.
173 # Another way to do this is to remove rpm dependency from tests' control
174 # file. That will involve changes on multiple control files. This one
175 # line change here is a simple temporary fix.
176 'rpm': actionables.TestActionable('dummy_PassServer'),
Alex Miller1968edf2014-02-27 18:11:36 -0800177 }
178
179 name = 'verify'
180
181
182class Provision(_SpecialTaskAction):
183 """
184 Provisioning runs to change the configuration of the DUT from one state to
185 another. It will only be run on verified DUTs.
186 """
187
Dan Shi7279a5a2016-04-07 11:04:28 -0700188 # ChromeOS update must happen before firmware install, so the dut has the
189 # correct ChromeOS version label when firmware install occurs. The ChromeOS
190 # version label is used for firmware update to stage desired ChromeOS image
191 # on to the servo USB stick.
192 _priorities = [CROS_VERSION_PREFIX,
193 FW_RO_VERSION_PREFIX,
194 FW_RW_VERSION_PREFIX]
195
Alex Miller1968edf2014-02-27 18:11:36 -0800196 # TODO(milleral): http://crbug.com/249555
197 # Create some way to discover and register provisioning tests so that we
198 # don't need to hand-maintain a list of all of them.
199 _actions = {
Fang Deng9d548742015-02-03 11:35:02 -0800200 CROS_VERSION_PREFIX: actionables.TestActionable(
201 'provision_AutoUpdate',
202 extra_kwargs={'disable_sysinfo': False,
203 'disable_before_test_sysinfo': False,
204 'disable_before_iteration_sysinfo': True,
205 'disable_after_test_sysinfo': True,
206 'disable_after_iteration_sysinfo': True}),
Tom Wai-Hong Tam9a237612016-01-08 03:41:46 +0800207 FW_RO_VERSION_PREFIX: actionables.TestActionable(
Fang Dengaf30e7c2014-11-15 13:57:03 -0800208 'provision_FirmwareUpdate'),
Tom Wai-Hong Tam9a237612016-01-08 03:41:46 +0800209 FW_RW_VERSION_PREFIX: actionables.TestActionable(
210 'provision_FirmwareUpdate',
Dan Shi61e407c2016-04-08 14:21:07 -0700211 extra_kwargs={'rw_only': True,
212 'tag': 'rw_only'}),
Simran Basi5ace6f22016-01-06 17:30:44 -0800213 ANDROID_BUILD_VERSION_PREFIX : actionables.TestActionable(
214 'provision_AndroidUpdate'),
Simran Basiadf31312016-06-28 14:23:05 -0700215 TESTBED_BUILD_VERSION_PREFIX : actionables.TestActionable(
216 'provision_TestbedUpdate'),
Alex Miller1968edf2014-02-27 18:11:36 -0800217 }
218
219 name = 'provision'
220
221
222class Cleanup(_SpecialTaskAction):
223 """
224 Cleanup runs after a test fails to try and remove artifacts of tests and
225 ensure the DUT will be in a sane state for the next test run.
226 """
227
228 _actions = {
Fang Dengaf30e7c2014-11-15 13:57:03 -0800229 'cleanup-reboot': actionables.RebootActionable(),
Alex Miller1968edf2014-02-27 18:11:36 -0800230 }
231
232 name = 'cleanup'
233
234
235class Repair(_SpecialTaskAction):
236 """
237 Repair runs when one of the other special tasks fails. It should be able
238 to take a component of the DUT that's in an unknown state and restore it to
239 a good state.
240 """
241
242 _actions = {
243 }
244
245 name = 'repair'
246
247
Alex Milleraa772002014-04-10 17:51:21 -0700248# TODO(milleral): crbug.com/364273
249# Label doesn't really mean label in this context. We're putting things into
250# DEPENDENCIES that really aren't DEPENDENCIES, and we should probably stop
251# doing that.
252def is_for_special_action(label):
253 """
254 If any special task handles the label specially, then we're using the label
255 to communicate that we want an action, and not as an actual dependency that
256 the test has.
257
258 @param label: A string label name.
259 @return True if any special task handles this label specially,
260 False if no special task handles this label.
261 """
262 return (Verify.acts_on(label) or
263 Provision.acts_on(label) or
264 Cleanup.acts_on(label) or
Dan Shie44f9c02016-02-18 13:25:05 -0800265 Repair.acts_on(label) or
266 label == SKIP_PROVISION)
Alex Miller0516e4c2013-06-03 18:07:48 -0700267
268
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000269def join(provision_type, provision_value):
270 """
271 Combine the provision type and value into the label name.
272
273 @param provision_type: One of the constants that are the label prefixes.
274 @param provision_value: A string of the value for this provision type.
275 @returns: A string that is the label name for this (type, value) pair.
276
277 >>> join(CROS_VERSION_PREFIX, 'lumpy-release/R27-3773.0.0')
278 'cros-version:lumpy-release/R27-3773.0.0'
279
280 """
281 return '%s:%s' % (provision_type, provision_value)
282
283
Alex Miller667b5f22014-02-28 15:33:39 -0800284class SpecialTaskActionException(Exception):
285 """
286 Exception raised when a special task fails to successfully run a test that
287 is required.
288
289 This is also a literally meaningless exception. It's always just discarded.
290 """
291
292
293def run_special_task_actions(job, host, labels, task):
294 """
295 Iterate through all `label`s and run any tests on `host` that `task` has
296 corresponding to the passed in labels.
297
298 Emits status lines for each run test, and INFO lines for each skipped label.
299
300 @param job: A job object from a control file.
301 @param host: The host to run actions on.
302 @param labels: The list of job labels to work on.
303 @param task: An instance of _SpecialTaskAction.
304 @returns: None
305 @raises: SpecialTaskActionException if a test fails.
306
307 """
Dan Shi7279a5a2016-04-07 11:04:28 -0700308 capabilities, configurations = task.partition(labels)
Alex Miller667b5f22014-02-28 15:33:39 -0800309
310 for label in capabilities:
Dan Shi7279a5a2016-04-07 11:04:28 -0700311 job.record('INFO', None, task.name,
312 "Can't %s label '%s'." % (task.name, label))
Alex Miller667b5f22014-02-28 15:33:39 -0800313
Dan Shi7279a5a2016-04-07 11:04:28 -0700314 # Sort the configuration labels based on `task._priorities`.
Prathmesh Prabhu2c7471d2016-11-15 20:19:57 +0000315 sorted_configurations = task.sort_configurations(configurations)
316 for name, value in sorted_configurations:
Dan Shi7279a5a2016-04-07 11:04:28 -0700317 action_item = task.test_for(name)
318 success = action_item.execute(job=job, host=host, value=value)
319 if not success:
320 raise SpecialTaskActionException()