1# 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 5import logging 6import socket 7 8import common 9from autotest_lib.client.common_lib import hosts 10from autotest_lib.server import utils 11from autotest_lib.server.hosts import servo_constants 12from autotest_lib.server.hosts import cros_constants 13 14from chromite.lib import timeout_util 15 16 17def require_servo(host, ignore_state=False): 18 """Require a DUT to have a working servo for a repair action. 19 20 @param host Host object that require servo. 21 @param ignore_state Ignore servo state as long as the we still have 22 servo connection. Some non-critical verifier 23 failures may not cause servo connection been 24 disconnected. 25 """ 26 servo_initialized = host.servo is not None 27 servo_working = (host.get_servo_state() == 28 servo_constants.SERVO_STATE_WORKING or ignore_state) 29 30 if not (servo_initialized and servo_working): 31 raise hosts.AutoservRepairError( 32 '%s has no working servo.' % host.hostname, 'no_working_servo') 33 logging.info('Servo dependence is available for the RepairAction/test.') 34 35 36class SshVerifier(hosts.Verifier): 37 """ 38 Verifier to test a host's accessibility via `ssh`. 39 40 This verifier checks whether a given host is reachable over `ssh`. 41 In the event of failure, it distinguishes one of three distinct 42 conditions: 43 * The host can't be found with a DNS lookup. 44 * The host doesn't answer to ping. 45 * The host answers to ping, but not to ssh. 46 """ 47 48 @timeout_util.TimeoutDecorator(cros_constants.VERIFY_TIMEOUT_SEC) 49 def verify(self, host): 50 if host.is_up(): 51 return 52 msg = 'No answer to ssh from %s' 53 try: 54 socket.gethostbyname(host.hostname) 55 except Exception as e: 56 logging.exception('DNS lookup failure') 57 msg = 'Unable to look up %%s in DNS: %s' % e 58 else: 59 if utils.ping(host.hostname, tries=1, deadline=1) != 0: 60 msg = 'No answer to ping from %s' 61 raise hosts.AutoservVerifyError(msg % host.hostname) 62 63 @property 64 def description(self): 65 return 'host is available via ssh' 66 67 68class PingVerifier(hosts.Verifier): 69 """ 70 Verifier to test a host's accessibility via `ping`. 71 72 This verifier checks whether a given host is reachable over `ping`. 73 The device is pingable as soon as booted to level when network driver 74 can respond. 75 In the event of failure, it distinguishes one of distinct conditions: 76 * The host can't be found with a DNS lookup. 77 * The host doesn't booted with network drivers. 78 """ 79 80 @timeout_util.TimeoutDecorator(cros_constants.VERIFY_TIMEOUT_SEC) 81 def verify(self, host): 82 if host.is_up_fast(count=10): 83 return 84 msg = 'No answer to ping to %s' 85 ip_address = None 86 try: 87 ip_address = socket.gethostbyname(host.hostname) 88 except Exception as e: 89 logging.exception('DNS lookup failure') 90 msg = 'Unable to look up %s in DNS: %s' % (host.hostname, str(e)) 91 raise hosts.AutoservVerifyError(msg) 92 if not ip_address: 93 msg = 'Hostname: %s not present in DNS' % host.hostname 94 raise hosts.AutoservVerifyError(msg) 95 96 @property 97 def description(self): 98 return 'host is available via ping' 99 100 101class LegacyHostVerifier(hosts.Verifier): 102 """ 103 Ask a Host instance to perform its own verification. 104 105 This class exists as a temporary legacy during refactoring to 106 provide access to code that hasn't yet been rewritten to use the new 107 repair and verify framework. 108 """ 109 110 @timeout_util.TimeoutDecorator(cros_constants.VERIFY_TIMEOUT_SEC) 111 def verify(self, host): 112 host.verify_software() 113 host.verify_hardware() 114 115 @property 116 def description(self): 117 return 'Legacy host verification checks' 118 119 120class RebootRepair(hosts.RepairAction): 121 """Repair a target device by rebooting it.""" 122 123 # Timeout of this action should defined in child class. 124 def repair(self, host): 125 host.reboot() 126 127 @property 128 def description(self): 129 return 'Reboot the host' 130 131 132class RPMCycleRepair(hosts.RepairAction): 133 """ 134 Cycle AC power using the RPM infrastructure. 135 136 This is meant to catch two distinct kinds of failure: 137 * If the target has no battery (that is, a chromebox), power 138 cycling it may force it back on. 139 * If the target has a batter that is discharging or even fully 140 drained, power cycling will leave power on, enabling other 141 repair procedures. 142 """ 143 144 @timeout_util.TimeoutDecorator(cros_constants.REPAIR_TIMEOUT_SEC) 145 def repair(self, host): 146 if not host.has_power(): 147 raise hosts.AutoservRepairError( 148 '%s has no RPM connection.' % host.hostname, 149 'no_working_rpm') 150 host.power_cycle() 151 152 153 @property 154 def description(self): 155 return 'Power cycle the host with RPM' 156