xref: /aosp_15_r20/external/autotest/server/cros/watchdog_tester.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
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