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