# 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 from autotest_lib.server.hosts import servo_constants from autotest_lib.server.hosts import cros_constants from chromite.lib import timeout_util def require_servo(host, ignore_state=False): """Require a DUT to have a working servo for a repair action. @param host Host object that require servo. @param ignore_state Ignore servo state as long as the we still have servo connection. Some non-critical verifier failures may not cause servo connection been disconnected. """ servo_initialized = host.servo is not None servo_working = (host.get_servo_state() == servo_constants.SERVO_STATE_WORKING or ignore_state) if not (servo_initialized and servo_working): raise hosts.AutoservRepairError( '%s has no working servo.' % host.hostname, 'no_working_servo') logging.info('Servo dependence is available for the RepairAction/test.') 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. """ @timeout_util.TimeoutDecorator(cros_constants.VERIFY_TIMEOUT_SEC) 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 PingVerifier(hosts.Verifier): """ Verifier to test a host's accessibility via `ping`. This verifier checks whether a given host is reachable over `ping`. The device is pingable as soon as booted to level when network driver can respond. In the event of failure, it distinguishes one of distinct conditions: * The host can't be found with a DNS lookup. * The host doesn't booted with network drivers. """ @timeout_util.TimeoutDecorator(cros_constants.VERIFY_TIMEOUT_SEC) def verify(self, host): if host.is_up_fast(count=10): return msg = 'No answer to ping to %s' ip_address = None try: ip_address = socket.gethostbyname(host.hostname) except Exception as e: logging.exception('DNS lookup failure') msg = 'Unable to look up %s in DNS: %s' % (host.hostname, str(e)) raise hosts.AutoservVerifyError(msg) if not ip_address: msg = 'Hostname: %s not present in DNS' % host.hostname raise hosts.AutoservVerifyError(msg) @property def description(self): return 'host is available via ping' 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. """ @timeout_util.TimeoutDecorator(cros_constants.VERIFY_TIMEOUT_SEC) 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.""" # Timeout of this action should defined in child class. 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. """ @timeout_util.TimeoutDecorator(cros_constants.REPAIR_TIMEOUT_SEC) def repair(self, host): if not host.has_power(): raise hosts.AutoservRepairError( '%s has no RPM connection.' % host.hostname, 'no_working_rpm') host.power_cycle() @property def description(self): return 'Power cycle the host with RPM'