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