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 5from __future__ import print_function 6 7import logging, re 8 9# http://docs.python.org/2/library/errno.html 10import errno 11 12from autotest_lib.client.common_lib import error 13 14class WatchdogTester(object): 15 """Helper class to perform various watchdog tests.""" 16 17 WD_DEV = '/dev/watchdog' 18 DAISYDOG_PATH='/usr/sbin/daisydog' 19 def _exists_on_client(self): 20 return self._client.run('test -c "%s"' % self.WD_DEV, 21 ignore_status=True).exit_status == 0 and \ 22 self._client.run('test -x "%s"' % self.DAISYDOG_PATH, 23 ignore_status=True).exit_status == 0 24 # If daisydog is running, stop it so we can use /dev/watchdog 25 def _stop_daemon(self): 26 """If running, stop daisydog so we can use /dev/watchdog.""" 27 self._client.run('stop daisydog', ignore_status=True) 28 29 def _start_daemon(self): 30 self._client.run('start daisydog', ignore_status=True) 31 32 def _query_hw_interval(self): 33 """Check how long the hardware interval is.""" 34 output = self._client.run('daisydog -c').stdout 35 secs = re.findall(r'HW watchdog interval is (\d*) seconds', output)[0] 36 return int(secs) 37 38 def __init__(self, client): 39 self._client = client 40 self._supported = self._exists_on_client() 41 42 def is_supported(self): 43 return self._supported 44 45 def __enter__(self): 46 self._stop_daemon() 47 self._hw_interval = self._query_hw_interval() 48 49 def trigger_watchdog(self, timeout=60): 50 """ 51 Trigger a watchdog reset by opening the watchdog device but not petting 52 it. Will ensure the device goes down and comes back up again. 53 """ 54 55 try: 56 self._client.run('echo "z" > %s' % self.WD_DEV) 57 except error.AutoservRunError as e: 58 raise error.TestError('write to %s failed (%s)' % 59 (self.WD_DEV, errno.errorcode[e.errno])) 60 61 logging.info("WatchdogHelper: tickled watchdog on %s (%ds to reboot)", 62 self._client.hostname, self._hw_interval) 63 64 # machine should became unpingable after lockup 65 # ...give 5 seconds slack... 66 wait_down = self._hw_interval + 5 67 if not self._client.wait_down(timeout=wait_down): 68 raise error.TestError('machine should be unpingable ' 69 'within %d seconds' % wait_down) 70 71 # make sure the machine comes back, 72 # DHCP can take up to 45 seconds in odd cases. 73 if not self._client.wait_up(timeout=timeout): 74 raise error.TestError('machine did not reboot/ping within ' 75 '%d seconds of HW reset' % timeout) 76 77 def __exit__(self, exception, value, traceback): 78 self._start_daemon() 79