blob: 33d73354e13a66500087f05f316228c396dbdf6a [file] [log] [blame]
# 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
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.
"""
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,
'no_working_rpm')
host.power_cycle()
if not host.wait_up(timeout=host.BOOT_TIMEOUT):
raise hosts.AutoservRepairError(
'%s is still offline after powercycling' %
host.hostname, 'failed_to_boot_after_rpm_power_cycle')
@property
def description(self):
return 'Power cycle the host with RPM'