blob: 5f8cffff3cd1275cf6509b2e0b75d0332c8121e3 [file] [log] [blame]
J. Richard Barnettec542c432016-02-12 11:29:34 -08001# Copyright 2016 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"""
J. Richard Barnette55228612016-02-16 17:38:06 -08006Framework for host verification and repair in Autotest.
J. Richard Barnettec542c432016-02-12 11:29:34 -08007
J. Richard Barnette55228612016-02-16 17:38:06 -08008The framework provides implementation code in support of `Host.verify()`
9and `Host.repair()` used in Verify and Repair special tasks.
J. Richard Barnettec542c432016-02-12 11:29:34 -080010
11The framework consists of these classes:
12 * `Verifier`: A class representing a single verification check.
J. Richard Barnette55228612016-02-16 17:38:06 -080013 * `RepairAction`: A class representing a repair operation that can fix
14 a failed verification check.
15 * `RepairStrategy`: A class for organizing a collection of `Verifier`
16 and `RepairAction` instances, and invoking them in order.
J. Richard Barnettec542c432016-02-12 11:29:34 -080017
J. Richard Barnette55228612016-02-16 17:38:06 -080018Individual operations during verification and repair are handled by
19instances of `Verifier` and `RepairAction`. `Verifier` objects are
20meant to test for specific conditions that may cause tests to fail.
21`RepairAction` objects provide operations designed to fix one or
22more failures identified by a `Verifier` object.
J. Richard Barnettec542c432016-02-12 11:29:34 -080023"""
24
25import logging
26
27import common
28from autotest_lib.client.common_lib import error
29
30
J. Richard Barnettecfe6b0d2016-03-17 11:39:12 -070031class AutoservVerifyError(error.AutoservError):
J. Richard Barnettec542c432016-02-12 11:29:34 -080032 """
33 Generic Exception for failures from `Verifier` objects.
34
35 Instances of this exception can be raised when a `verify()`
36 method fails, if no more specific exception is available.
37 """
38 pass
39
40
J. Richard Barnettecfe6b0d2016-03-17 11:39:12 -070041class AutoservVerifyDependencyError(error.AutoservError):
J. Richard Barnettec542c432016-02-12 11:29:34 -080042 """
43 Exception raised for failures in dependencies.
44
45 This exception is used to distinguish an original failure from a
46 failure being passed back from a verification dependency. That is,
47 if 'B' depends on 'A', and 'A' fails, 'B' will raise this exception
48 to signal that the original failure is further down the dependency
49 chain.
50
51 Each argument to the constructor for this class should be the string
52 description of one failed dependency.
53
54 `Verifier._verify_host()` recognizes and handles this exception
55 specially.
56 """
57 pass
58
59
J. Richard Barnette55228612016-02-16 17:38:06 -080060class AutoservRepairError(error.AutoservError):
J. Richard Barnettec542c432016-02-12 11:29:34 -080061 """
J. Richard Barnette55228612016-02-16 17:38:06 -080062 Generic Exception for failures from `RepairAction` objects.
J. Richard Barnettec542c432016-02-12 11:29:34 -080063
J. Richard Barnette55228612016-02-16 17:38:06 -080064 Instances of this exception can be raised when a `repair()`
65 method fails, if no more specific exception is available.
66 """
67 pass
J. Richard Barnettec542c432016-02-12 11:29:34 -080068
J. Richard Barnettec542c432016-02-12 11:29:34 -080069
J. Richard Barnette55228612016-02-16 17:38:06 -080070class _DependencyNode(object):
71 """
72 An object that can depend on verifiers.
J. Richard Barnettec542c432016-02-12 11:29:34 -080073
J. Richard Barnette55228612016-02-16 17:38:06 -080074 Both repair and verify operations have the notion of dependencies
75 that must pass before the operation proceeds. This class captures
76 the shared behaviors required by both classes.
J. Richard Barnettec542c432016-02-12 11:29:34 -080077
78 @property tag Short identifier to be used in logging.
J. Richard Barnette55228612016-02-16 17:38:06 -080079 @property description Text summary of this node's action, to be
80 used in debug logs.
J. Richard Barnettec542c432016-02-12 11:29:34 -080081 @property _dependency_list Dependency pre-requisites.
82 """
83
J. Richard Barnettea4784062016-03-04 14:14:10 -080084 def __init__(self, tag, dependencies):
J. Richard Barnettec542c432016-02-12 11:29:34 -080085 self._dependency_list = dependencies
J. Richard Barnettea4784062016-03-04 14:14:10 -080086 self._tag = tag
J. Richard Barnettec542c432016-02-12 11:29:34 -080087
88
J. Richard Barnette55228612016-02-16 17:38:06 -080089 @staticmethod
90 def _verify_list(host, verifiers):
J. Richard Barnettec542c432016-02-12 11:29:34 -080091 """
92 Test a list of verifiers against a given host.
93
94 This invokes `_verify_host()` on every verifier in the given
95 list. If any verifier in the transitive closure of dependencies
J. Richard Barnettecfe6b0d2016-03-17 11:39:12 -070096 in the list fails, an `AutoservVerifyDependencyError` is raised
J. Richard Barnettec542c432016-02-12 11:29:34 -080097 containing the description of each failed verifier. Only
98 original failures are reported; verifiers that don't run due
99 to a failed dependency are omitted.
100
101 By design, original failures are logged once in `_verify_host()`
102 when `verify()` originally fails. The additional data gathered
103 here is for the debug logs to indicate why a subsequent
104 operation never ran.
105
106 @param host The host to be tested against the verifiers.
107 @param verifiers List of verifiers to be checked.
108
J. Richard Barnettecfe6b0d2016-03-17 11:39:12 -0700109 @raises AutoservVerifyDependencyError Raised when at least
J. Richard Barnettec542c432016-02-12 11:29:34 -0800110 one verifier in the list has failed.
111 """
J. Richard Barnette2654c552016-03-01 17:26:35 -0800112 failures = set()
J. Richard Barnettec542c432016-02-12 11:29:34 -0800113 for v in verifiers:
114 try:
115 v._verify_host(host)
J. Richard Barnettecfe6b0d2016-03-17 11:39:12 -0700116 except AutoservVerifyDependencyError as e:
J. Richard Barnette2654c552016-03-01 17:26:35 -0800117 failures.update(e.args)
J. Richard Barnettec542c432016-02-12 11:29:34 -0800118 except Exception as e:
J. Richard Barnette2654c552016-03-01 17:26:35 -0800119 failures.add(v.description)
J. Richard Barnettec542c432016-02-12 11:29:34 -0800120 if failures:
J. Richard Barnettecfe6b0d2016-03-17 11:39:12 -0700121 raise AutoservVerifyDependencyError(*list(failures))
J. Richard Barnettec542c432016-02-12 11:29:34 -0800122
123
J. Richard Barnette55228612016-02-16 17:38:06 -0800124 def _log_dependency_error(self, message, exc):
125 """
126 Log an `AutoservVerifyDependencyError`.
127
128 This writes a short summary of the failures in the exception's
129 arguments, using standard Python logging. The logging consists
130 of two parts. The first part is an initial INFO level message.
131 The message should have one `%s` format argument, which will be
132 filled in with `self.description`. The second part is to write
133 each argument of the exception at DEBUG level, with indentation
134 to make the arguments visible.
135
136 @param message Message describing the event, to be formatted
137 with `self.description`.
138 @param exc An instance of `AutoservVerifyDependencyError`.
139 """
140 logging.info('%s: %s', message, self.description)
141 for description in exc.args:
142 logging.debug(' %s', description)
143
144
145 def _verify_dependencies(self, host):
146 """
147 Verify that all of this node's dependencies pass for a host.
148
149 @param host The host to be verified.
150 """
151 try:
152 self._verify_list(host, self._dependency_list)
153 except AutoservVerifyDependencyError as e:
154 self._log_dependency_error(
155 'Dependencies failed; '
156 'skipping this operation', e)
157 raise
158
159
160 @property
161 def tag(self):
162 """
163 Tag for use in logging status records.
164
165 This is a property with a short string used to identify the node
166 in the 'status.log' file and during node construction. The tag
167 should contain only letters, digits, and '_' characters. This
168 tag is not used alone, but is combined with other identifiers,
169 based on the operation being logged.
170
171 @return A short identifier-like string.
172 """
173 return self._tag
174
175
176 @property
177 def description(self):
178 """
179 Text description of this node for log messages.
180
181 This string will be logged with failures, and should describe
182 the condition required for success.
183
184 N.B. Subclasses are required to override this method, but we
185 _don't_ raise NotImplementedError here. Various methods fail in
186 inscrutable ways if this method raises any exception, so for
187 debugging purposes, it's better to return a default value.
188
189 @return A descriptive string.
190 """
191 return ('Class %s fails to implement description().' %
192 type(self).__name__)
193
194
195class Verifier(_DependencyNode):
196 """
197 Abstract class embodying one verification check.
198
199 A concrete subclass of `Verifier` provides a simple check that can
200 determine a host's fitness for testing. Failure indicates that the
201 check found a problem that can cause at least one test to fail.
202
203 `Verifier` objects are organized in a DAG identifying dependencies
204 among operations. The DAG controls ordering and prevents wasted
205 effort: If verification operation V2 requires that verification
206 operation V1 pass, then a) V1 will run before V2, and b) if V1
207 fails, V2 won't run at all. The `_verify_host()` method ensures
208 that all dependencies run and pass before invoking the `verify()`
209 method.
210
211 A `Verifier` object caches its result the first time it calls
212 `verify()`. Subsequent calls return the cached result, without
213 re-running the check code. The `_reverify()` method clears the
214 cached result in the current node, and in all dependencies.
215
216 Subclasses must supply these properties and methods:
217 * `verify()`: This is the method to perform the actual
218 verification check.
219 * `description`: A one-line summary of the verification check for
220 debug log messages.
221
222 Subclasses must override all of the above attributes; subclasses
223 should not override or extend any other attributes of this class.
224
225 The description string should be a simple sentence explaining what
226 must be true for the verifier to pass. Do not include a terminating
227 period. For example:
228
229 Host is available via ssh
230
231 The base class manages the following private data:
232 * `_result`: The cached result of verification.
233 * `_dependency_list`: The list of dependencies.
234 Subclasses should not use these attributes.
235
236 @property _result Cached result of verification.
237 """
238
239 def __init__(self, tag, dependencies):
240 super(Verifier, self).__init__(tag, dependencies)
241 self._result = None
242 self._verify_tag = 'verify.' + self.tag
243
244
J. Richard Barnettec542c432016-02-12 11:29:34 -0800245 def _reverify(self):
246 """
247 Discard cached verification results.
248
249 Reset the cached verification result for this node, and for the
250 transitive closure of all dependencies.
251 """
252 if self._result is not None:
253 self._result = None
254 for v in self._dependency_list:
255 v._reverify()
256
257
258 def _verify_host(self, host):
259 """
260 Determine the result of verification, and log results.
261
262 If this verifier does not have a cached verification result,
263 check dependencies, and if they pass, run `verify()`. Log
264 informational messages regarding failed dependencies. If we
265 call `verify()`, log the result in `status.log`.
266
267 If we already have a cached result, return that result without
268 logging any message.
269
270 @param host The host to be tested for a problem.
271 """
272 if self._result is not None:
273 if isinstance(self._result, Exception):
274 raise self._result # cached failure
275 elif self._result:
276 return # cached success
277 self._result = False
J. Richard Barnette55228612016-02-16 17:38:06 -0800278 self._verify_dependencies(host)
J. Richard Barnettec542c432016-02-12 11:29:34 -0800279 logging.info('Verifying this condition: %s', self.description)
280 try:
281 self.verify(host)
J. Richard Barnette55228612016-02-16 17:38:06 -0800282 host.record('GOOD', None, self._verify_tag)
J. Richard Barnettec542c432016-02-12 11:29:34 -0800283 except Exception as e:
284 logging.exception('Failed: %s', self.description)
285 self._result = e
J. Richard Barnette55228612016-02-16 17:38:06 -0800286 host.record('FAIL', None, self._verify_tag, str(e))
J. Richard Barnettec542c432016-02-12 11:29:34 -0800287 raise
288 self._result = True
289
290
291 def verify(self, host):
292 """
293 Unconditionally perform a verification check.
294
295 This method is responsible for testing for a single problem on a
296 host. Implementations should follow these guidelines:
297 * The check should find a problem that will cause testing to
298 fail.
299 * Verification checks on a working system should run quickly
300 and should be optimized for success; a check that passes
301 should finish within seconds.
302 * Verification checks are not expected have side effects, but
303 may apply trivial fixes if they will finish within the time
304 constraints above.
305
306 A verification check should normally trigger a single set of
307 repair actions. If two different failures can require two
308 different repairs, ideally they should use two different
309 subclasses of `Verifier`.
310
311 Implementations indicate failure by raising an exception. The
312 exception text should be a short, 1-line summary of the error.
313 The text should be concise and diagnostic, as it will appear in
314 `status.log` files.
315
316 If this method finds no problems, it returns without raising any
317 exception.
318
319 Implementations should avoid most logging actions, but can log
320 DEBUG level messages if they provide significant information for
321 diagnosing failures.
322
323 @param host The host to be tested for a problem.
324 """
325 raise NotImplementedError('Class %s does not implement '
326 'verify()' % type(self).__name__)
327
328
J. Richard Barnette55228612016-02-16 17:38:06 -0800329class RepairAction(_DependencyNode):
330 """
331 Abstract class embodying one repair procedure.
332
333 A `RepairAction` is responsible for fixing one or more failed
334 `Verifier` checks, in order to make those checks pass.
335
336 Each repair action includes one or more verifier triggers that
337 determine when the repair action should run. A repair action
338 will call its `repair()` method if one or more of its triggers
339 fails. A repair action is successful if all of its triggers pass
340 after calling `repair()`.
341
342 A `RepairAction` is a subclass of `_DependencyNode`; if any of a
343 repair action's dependencies fail, the action does not check its
344 triggers, and doesn't call `repair()`.
345
346 Subclasses must supply these attributes:
347 * `repair()`: This is the method to perform the necessary
348 repair. The method should avoid most logging actions, but
349 can log DEBUG level messages if they provide significant
350 information for diagnosing failures.
351 * `description`: A one-line summary of the repair action for
352 debug log messages.
353
354 Subclasses must override both of the above attributes and should
355 not override any other attributes of this class.
356
357 The description string should be a simple sentence explaining the
358 operation that will be performed. Do not include a terminating
359 period. For example:
360
361 Re-install the stable build via AU
362
363 @property _trigger_list List of verification checks that will
364 trigger this repair when they fail.
365 """
366
367 def __init__(self, tag, dependencies, triggers):
368 super(RepairAction, self).__init__(tag, dependencies)
369 self._trigger_list = triggers
370 self._repair_tag = 'repair.' + self.tag
371
372
373 def _repair_host(self, host):
J. Richard Barnettec542c432016-02-12 11:29:34 -0800374 """
J. Richard Barnette55228612016-02-16 17:38:06 -0800375 Apply this repair action if any triggers fail.
J. Richard Barnettec542c432016-02-12 11:29:34 -0800376
J. Richard Barnette55228612016-02-16 17:38:06 -0800377 Repair is triggered when all dependencies are successful, and at
378 least one trigger fails.
J. Richard Barnettec542c432016-02-12 11:29:34 -0800379
J. Richard Barnette55228612016-02-16 17:38:06 -0800380 If the `repair()` method triggers, the success or failure of
381 this operation is logged in `status.log` bracketed by 'START'
382 and 'END' records. Details of whether or why `repair()`
383 triggered are written to the debug logs. If repair doesn't
384 trigger, nothing is logged to `status.log`.
385
386 @param host The host to be repaired.
J. Richard Barnettec542c432016-02-12 11:29:34 -0800387 """
J. Richard Barnette55228612016-02-16 17:38:06 -0800388 self._verify_dependencies(host)
389 try:
390 self._verify_list(host, self._trigger_list)
391 except AutoservVerifyDependencyError as e:
392 self._log_dependency_error('Repair action triggered', e)
393 host.record('START', None, self._repair_tag)
394 try:
395 self.repair(host)
396 except Exception as e:
397 logging.exception('Repair failed: %s', self.description)
398 host.record('FAIL', None, self._repair_tag, str(e))
399 host.record('END FAIL', None, self._repair_tag)
400 raise
401 try:
402 for v in self._trigger_list:
403 v._reverify()
404 self._verify_list(host, self._trigger_list)
405 host.record('END GOOD', None, self._repair_tag)
406 except AutoservVerifyDependencyError as e:
407 self._log_dependency_error(
408 'Repair passed but triggers still fail', e)
409 host.record('END FAIL', None, self._repair_tag)
410 raise AutoservRepairError(
411 'Some verification checks still fail')
412 except Exception:
413 # The specification for `self._verify_list()` says
414 # that this can't happen; this is a defensive
415 # precaution.
416 host.record('END FAIL', None, self._repair_tag,
417 'Internal error in repair')
418 raise
419 else:
420 logging.info('No failed triggers, skipping repair: %s',
421 self.description)
J. Richard Barnettec542c432016-02-12 11:29:34 -0800422
423
J. Richard Barnette55228612016-02-16 17:38:06 -0800424 def repair(self, host):
J. Richard Barnettec542c432016-02-12 11:29:34 -0800425 """
J. Richard Barnette55228612016-02-16 17:38:06 -0800426 Apply this repair action to the given host.
J. Richard Barnettec542c432016-02-12 11:29:34 -0800427
J. Richard Barnette55228612016-02-16 17:38:06 -0800428 This method is responsible for applying changes to fix failures
429 in one or more verification checks. The repair is considered
430 successful if the DUT passes the specific checks after this
431 method completes.
J. Richard Barnettec542c432016-02-12 11:29:34 -0800432
J. Richard Barnette55228612016-02-16 17:38:06 -0800433 Implementations indicate failure by raising an exception. The
434 exception text should be a short, 1-line summary of the error.
435 The text should be concise and diagnostic, as it will appear in
436 `status.log` files.
J. Richard Barnettec542c432016-02-12 11:29:34 -0800437
J. Richard Barnette55228612016-02-16 17:38:06 -0800438 If this method completes successfully, it returns without
439 raising any exception.
440
441 Implementations should avoid most logging actions, but can log
442 DEBUG level messages if they provide significant information for
443 diagnosing failures.
444
445 @param host The host to be repaired.
J. Richard Barnettec542c432016-02-12 11:29:34 -0800446 """
J. Richard Barnette55228612016-02-16 17:38:06 -0800447 raise NotImplementedError('Class %s does not implement '
448 'repair()' % type(self).__name__)
J. Richard Barnettec542c432016-02-12 11:29:34 -0800449
450
451class _RootVerifier(Verifier):
452 """
453 Utility class used by `RepairStrategy`.
454
455 A node of this class by itself does nothing; it always passes (if it
456 can run). This class exists merely to be the root of a DAG of
457 dependencies in an instance of `RepairStrategy`.
458 """
459
J. Richard Barnettec542c432016-02-12 11:29:34 -0800460 def verify(self, host):
461 pass
462
463
464 @property
J. Richard Barnettec542c432016-02-12 11:29:34 -0800465 def description(self):
466 return 'All host verification checks pass'
467
468
469
470class RepairStrategy(object):
471 """
J. Richard Barnette55228612016-02-16 17:38:06 -0800472 A class for organizing `Verifier` and `RepairAction` objects.
J. Richard Barnettec542c432016-02-12 11:29:34 -0800473
J. Richard Barnette2654c552016-03-01 17:26:35 -0800474 An instance of `RepairStrategy` is organized as a DAG of `Verifier`
J. Richard Barnette55228612016-02-16 17:38:06 -0800475 objects, plus a list of `RepairAction` objects. The class provides
476 methods for invoking those objects in the required order, when
477 needed:
478 * The `verify()` method walks the verifier DAG in dependency
479 order.
480 * The `repair()` method invokes the repair actions in list order.
481 Each repair action will invoke its dependencies and triggers as
482 needed.
J. Richard Barnette2654c552016-03-01 17:26:35 -0800483
J. Richard Barnette55228612016-02-16 17:38:06 -0800484 # The Verifier DAG
485 The verifier DAG is constructed from the first argument passed to
486 the passed to the `RepairStrategy` constructor. That argument is an
487 iterable consisting of three-element tuples in the form
488 `(constructor, tag, deps)`:
J. Richard Barnette2654c552016-03-01 17:26:35 -0800489 * The `constructor` value is a callable that creates a `Verifier`
J. Richard Barnette55228612016-02-16 17:38:06 -0800490 as for the interface of the class constructor. For classes
J. Richard Barnette2654c552016-03-01 17:26:35 -0800491 that inherit the default constructor from `Verifier`, this can
492 be the class itself.
J. Richard Barnettea4784062016-03-04 14:14:10 -0800493 * The `tag` value is the tag to be associated with the constructed
494 verifier.
J. Richard Barnette2654c552016-03-01 17:26:35 -0800495 * The `deps` value is an iterable (e.g. list or tuple) of strings.
496 Each string corresponds to the `tag` member of a `Verifier`
497 dependency.
498
499 The tag names of verifiers in the constructed DAG must all be
J. Richard Barnette55228612016-02-16 17:38:06 -0800500 unique. The tag name defined by `RepairStrategy.ROOT_TAG` is
501 reserved and may not be used by any verifier.
J. Richard Barnette2654c552016-03-01 17:26:35 -0800502
503 In the input data for the constructor, dependencies must appear
J. Richard Barnettea4784062016-03-04 14:14:10 -0800504 before the nodes that depend on them. Thus:
J. Richard Barnette2654c552016-03-01 17:26:35 -0800505
J. Richard Barnettea4784062016-03-04 14:14:10 -0800506 ((A, 'a', ()), (B, 'b', ('a',))) # This is valid
507 ((B, 'b', ('a',)), (A, 'a', ())) # This will fail!
J. Richard Barnette2654c552016-03-01 17:26:35 -0800508
509 Internally, the DAG of verifiers is given unique root node. So,
510 given this input:
511
J. Richard Barnettea4784062016-03-04 14:14:10 -0800512 ((C, 'c', ()),
513 (A, 'a', ('c',)),
514 (B, 'b', ('c',)))
J. Richard Barnette2654c552016-03-01 17:26:35 -0800515
516 The following DAG is constructed:
517
518 Root
519 / \
520 A B
521 \ /
522 C
523
524 Since nothing depends on `A` or `B`, the root node guarantees that
525 these two verifiers will both be called and properly logged.
526
J. Richard Barnette55228612016-02-16 17:38:06 -0800527 The root node is not directly accessible; however repair actions can
528 trigger on it by using `RepairStrategy.ROOT_TAG`. Additionally, the
529 node will be logged in `status.log` whenever `verify()` succeeds.
530
531 # The Repair Actions List
532 The list of repair actions is constructed from the second argument
533 passed to the passed to the `RepairStrategy` constructor. That
534 argument is an iterable consisting of four-element tuples in the
535 form `(constructor, tag, deps, triggers)`:
536 * The `constructor` value is a callable that creates a
537 `RepairAction` as for the interface of the class constructor.
538 For classes that inherit the default constructor from
539 `RepairAction`, this can be the class itself.
540 * The `tag` value is the tag to be associated with the constructed
541 repair action.
542 * The `deps` value is an iterable (e.g. list or tuple) of strings.
543 Each string corresponds to the `tag` member of a `Verifier` that
544 the repair action depends on.
545 * The `triggers` value is an iterable (e.g. list or tuple) of
546 strings. Each string corresponds to the `tag` member of a
547 `Verifier` that can trigger the repair action.
548
549 `RepairStrategy` deps and triggers can only refer to verifiers,
550 not to other repair actions.
J. Richard Barnettec542c432016-02-12 11:29:34 -0800551 """
552
J. Richard Barnettea4784062016-03-04 14:14:10 -0800553 # This name is reserved; clients may not use it.
J. Richard Barnette55228612016-02-16 17:38:06 -0800554 ROOT_TAG = 'PASS'
J. Richard Barnette2654c552016-03-01 17:26:35 -0800555
J. Richard Barnette55228612016-02-16 17:38:06 -0800556 @staticmethod
557 def _add_verifier(verifiers, constructor, tag, dep_tags):
558 """
559 Construct and remember a verifier.
560
561 Create a `Verifier` using `constructor` and `tag`. Dependencies
562 for construction are found by looking up `dep_tags` in the
563 `verifiers` dictionary.
564
565 After construction, the new verifier is added to `verifiers`.
566
567 @param verifiers Dictionary of verifiers, indexed by tag.
568 @param constructor Verifier construction function.
569 @param tag Tag parameter for the construction function.
570 @param dep_tags Tags of dependencies for the constructor, to
571 be found in `verifiers`.
572 """
573 assert tag not in verifiers
574 deps = [verifiers[d] for d in dep_tags]
575 verifiers[tag] = constructor(tag, deps)
576
577
578 def __init__(self, verifier_data, repair_data):
J. Richard Barnettec542c432016-02-12 11:29:34 -0800579 """
580 Construct a `RepairStrategy` from simplified DAG data.
581
582 The input `verifier_data` object describes how to construct
583 verify nodes and the dependencies that relate them, as detailed
J. Richard Barnette2654c552016-03-01 17:26:35 -0800584 above.
J. Richard Barnettec542c432016-02-12 11:29:34 -0800585
J. Richard Barnette55228612016-02-16 17:38:06 -0800586 The input `repair_data` object describes how to construct repair
587 actions and their dependencies and triggers, as detailed above.
588
J. Richard Barnettec542c432016-02-12 11:29:34 -0800589 @param verifier_data Iterable value with constructors for the
590 elements of the verification DAG and their
591 dependencies.
J. Richard Barnette55228612016-02-16 17:38:06 -0800592 @param repair_data Iterable value with constructors for the
593 elements of the repair action list, and
594 their dependencies and triggers.
J. Richard Barnettec542c432016-02-12 11:29:34 -0800595 """
J. Richard Barnette2654c552016-03-01 17:26:35 -0800596 # We use the `all_verifiers` list to guarantee that our root
597 # verifier will execute its dependencies in the order provided
598 # to us by our caller.
J. Richard Barnettec542c432016-02-12 11:29:34 -0800599 verifier_map = {}
J. Richard Barnette55228612016-02-16 17:38:06 -0800600 all_tags = []
J. Richard Barnette2654c552016-03-01 17:26:35 -0800601 dependencies = set()
J. Richard Barnette55228612016-02-16 17:38:06 -0800602 for constructor, tag, deps in verifier_data:
603 self._add_verifier(verifier_map, constructor, tag, deps)
J. Richard Barnette2654c552016-03-01 17:26:35 -0800604 dependencies.update(deps)
J. Richard Barnette55228612016-02-16 17:38:06 -0800605 all_tags.append(tag)
J. Richard Barnette2654c552016-03-01 17:26:35 -0800606 # Capture all the verifiers that have nothing depending on them.
J. Richard Barnette55228612016-02-16 17:38:06 -0800607 root_tags = [t for t in all_tags if t not in dependencies]
608 self._add_verifier(verifier_map, _RootVerifier,
609 self.ROOT_TAG, root_tags)
610 self._verify_root = verifier_map[self.ROOT_TAG]
611 self._repair_actions = []
612 for constructor, tag, deps, triggers in repair_data:
613 r = constructor(tag,
614 [verifier_map[d] for d in deps],
615 [verifier_map[t] for t in triggers])
616 self._repair_actions.append(r)
J. Richard Barnettec542c432016-02-12 11:29:34 -0800617
618
619 def verify(self, host):
620 """
621 Run the verifier DAG on the given host.
622
623 @param host The target to be verified.
624 """
625 self._verify_root._reverify()
626 self._verify_root._verify_host(host)
J. Richard Barnette55228612016-02-16 17:38:06 -0800627
628
629 def repair(self, host):
630 """
631 Run the repair DAG on the given host.
632
633 @param host The target to be repaired.
634 """
635 self._verify_root._reverify()
636 for ra in self._repair_actions:
637 try:
638 ra._repair_host(host)
639 except Exception as e:
640 # all logging and exception handling was done at
641 # lower levels
642 pass
643 self._verify_root._verify_host(host)