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