| # Copyright 2016 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import logging |
| import socket |
| |
| import common |
| from autotest_lib.client.common_lib import hosts |
| from autotest_lib.server import utils |
| |
| |
| def require_servo(host): |
| """Require a DUT to have a working servo for a repair action.""" |
| if not host.servo: |
| raise hosts.AutoservRepairError( |
| '%s has no working servo.' % host.hostname) |
| |
| |
| class SshVerifier(hosts.Verifier): |
| """ |
| Verifier to test a host's accessibility via `ssh`. |
| |
| This verifier checks whether a given host is reachable over `ssh`. |
| In the event of failure, it distinguishes one of three distinct |
| conditions: |
| * The host can't be found with a DNS lookup. |
| * The host doesn't answer to ping. |
| * The host answers to ping, but not to ssh. |
| """ |
| |
| def verify(self, host): |
| if host.is_up(): |
| return |
| msg = 'No answer to ssh from %s' |
| try: |
| socket.gethostbyname(host.hostname) |
| except Exception as e: |
| logging.exception('DNS lookup failure') |
| msg = 'Unable to look up %%s in DNS: %s' % e |
| else: |
| if utils.ping(host.hostname, tries=1, deadline=1) != 0: |
| msg = 'No answer to ping from %s' |
| raise hosts.AutoservVerifyError(msg % host.hostname) |
| |
| |
| @property |
| def description(self): |
| return 'host is available via ssh' |
| |
| |
| class LegacyHostVerifier(hosts.Verifier): |
| """ |
| Ask a Host instance to perform its own verification. |
| |
| This class exists as a temporary legacy during refactoring to |
| provide access to code that hasn't yet been rewritten to use the new |
| repair and verify framework. |
| """ |
| |
| def verify(self, host): |
| host.verify_software() |
| host.verify_hardware() |
| |
| |
| @property |
| def description(self): |
| return 'Legacy host verification checks' |
| |
| |
| class RebootRepair(hosts.RepairAction): |
| """Repair a target device by rebooting it.""" |
| |
| def repair(self, host): |
| host.reboot() |
| |
| |
| @property |
| def description(self): |
| return 'Reboot the host' |
| |
| |
| class RPMCycleRepair(hosts.RepairAction): |
| """ |
| Cycle AC power using the RPM infrastructure. |
| |
| This is meant to catch two distinct kinds of failure: |
| * If the target has no battery (that is, a chromebox), power |
| cycling it may force it back on. |
| * If the target has a batter that is discharging or even fully |
| drained, power cycling will leave power on, enabling other |
| repair procedures. |
| """ |
| |
| def repair(self, host): |
| if not host.has_power(): |
| raise hosts.AutoservRepairError( |
| '%s has no RPM connection.' % host.hostname) |
| host.power_cycle() |
| if not host.wait_up(timeout=host.BOOT_TIMEOUT): |
| raise hosts.AutoservRepairError( |
| '%s is still offline after powercycling' % |
| host.hostname) |
| |
| |
| @property |
| def description(self): |
| return 'Power cycle the host with RPM' |