blob: 6daffddce142346262184f714f4e2c0310a035d8 [file] [log] [blame]
mblighd9911982009-04-08 21:18:35 +00001import os, sys, subprocess, logging
jadmanski1c5e3a12008-08-15 23:08:20 +00002
jadmanskia2db9412008-08-22 21:47:24 +00003from autotest_lib.client.common_lib import utils, error
4from autotest_lib.server import utils as server_utils
mbligh3b02e8b2009-02-17 15:59:54 +00005from autotest_lib.server.hosts import remote
jadmanski1c5e3a12008-08-15 23:08:20 +00006
7
mbligh3b02e8b2009-02-17 15:59:54 +00008SiteHost = utils.import_site_class(
9 __file__, "autotest_lib.server.hosts.site_host", "SiteHost",
10 remote.RemoteHost)
11
12
13class SerialHost(SiteHost):
14 DEFAULT_REBOOT_TIMEOUT = SiteHost.DEFAULT_REBOOT_TIMEOUT
jadmanskia2db9412008-08-22 21:47:24 +000015
jadmanskif6562912008-10-21 17:59:01 +000016 def _initialize(self, conmux_server=None, conmux_attach=None,
17 console_log="console.log", *args, **dargs):
18 super(SerialHost, self)._initialize(*args, **dargs)
jadmanski1c5e3a12008-08-15 23:08:20 +000019
jadmanskic533bd12008-09-03 20:48:51 +000020 self.__logger = None
21 self.__console_log = console_log
22
jadmanski1c5e3a12008-08-15 23:08:20 +000023 self.conmux_server = conmux_server
jadmanskia2db9412008-08-22 21:47:24 +000024 self.conmux_attach = self._get_conmux_attach(conmux_attach)
jadmanski1c5e3a12008-08-15 23:08:20 +000025
jadmanski1c5e3a12008-08-15 23:08:20 +000026
jadmanskia2db9412008-08-22 21:47:24 +000027 @classmethod
28 def _get_conmux_attach(cls, conmux_attach=None):
29 if conmux_attach:
30 return conmux_attach
31
32 # assume we're using the conmux-attach provided with autotest
33 server_dir = server_utils.get_server_dir()
34 path = os.path.join(server_dir, "..", "conmux", "conmux-attach")
35 path = os.path.abspath(path)
36 return path
37
38
39 @staticmethod
40 def _get_conmux_hostname(hostname, conmux_server):
41 if conmux_server:
42 return "%s/%s" % (conmux_server, hostname)
jadmanski1c5e3a12008-08-15 23:08:20 +000043 else:
jadmanskia2db9412008-08-22 21:47:24 +000044 return hostname
45
46
47 def get_conmux_hostname(self):
48 return self._get_conmux_hostname(self.hostname, self.conmux_server)
49
50
51 @classmethod
52 def host_is_supported(cls, hostname, conmux_server=None,
53 conmux_attach=None):
54 """ Returns a boolean indicating if the remote host with "hostname"
55 supports use as a SerialHost """
56 conmux_attach = cls._get_conmux_attach(conmux_attach)
57 conmux_hostname = cls._get_conmux_hostname(hostname, conmux_server)
58 cmd = "%s %s echo 2> /dev/null" % (conmux_attach, conmux_hostname)
mblighd9911982009-04-08 21:18:35 +000059 try:
60 result = utils.run(cmd, ignore_status=True, timeout=10)
61 return result.exit_status == 0
62 except error.CmdError:
63 logging.warning("Timed out while trying to attach to conmux")
64
65 return False
jadmanski1c5e3a12008-08-15 23:08:20 +000066
67
jadmanskic533bd12008-09-03 20:48:51 +000068 def start_loggers(self):
69 super(SerialHost, self).start_loggers()
70
mblighd876f452008-12-03 15:09:17 +000071 if self.__console_log is None:
jadmanski1c5e3a12008-08-15 23:08:20 +000072 return
jadmanskic533bd12008-09-03 20:48:51 +000073
jadmanski1c5e3a12008-08-15 23:08:20 +000074 if not self.conmux_attach or not os.path.exists(self.conmux_attach):
75 return
76
77 r, w = os.pipe()
jadmanski79777f62008-09-09 22:31:38 +000078 script_path = os.path.join(self.monitordir, 'console.py')
jadmanskia2db9412008-08-22 21:47:24 +000079 cmd = [self.conmux_attach, self.get_conmux_hostname(),
jadmanski1c5e3a12008-08-15 23:08:20 +000080 '%s %s %s %d' % (sys.executable, script_path,
jadmanskic533bd12008-09-03 20:48:51 +000081 self.__console_log, w)]
jadmanski1c5e3a12008-08-15 23:08:20 +000082
jadmanskic533bd12008-09-03 20:48:51 +000083 self.__warning_stream = os.fdopen(r, 'r', 0)
jadmanski1c5e3a12008-08-15 23:08:20 +000084 if self.job:
jadmanskic533bd12008-09-03 20:48:51 +000085 self.job.warning_loggers.add(self.__warning_stream)
86
87 stdout = stderr = open(os.devnull, 'w')
88 self.__logger = subprocess.Popen(cmd, stdout=stdout, stderr=stderr)
jadmanski1c5e3a12008-08-15 23:08:20 +000089 os.close(w)
90
91
jadmanskic533bd12008-09-03 20:48:51 +000092 def stop_loggers(self):
93 super(SerialHost, self).stop_loggers()
94
95 if self.__logger:
96 utils.nuke_subprocess(self.__logger)
97 self.__logger = None
jadmanski1c5e3a12008-08-15 23:08:20 +000098 if self.job:
jadmanskic533bd12008-09-03 20:48:51 +000099 self.job.warning_loggers.discard(self.__warning_stream)
100 self.__warning_stream.close()
jadmanski1c5e3a12008-08-15 23:08:20 +0000101
102
103 def run_conmux(self, cmd):
104 """
105 Send a command to the conmux session
106 """
107 if not self.conmux_attach or not os.path.exists(self.conmux_attach):
108 return False
109 cmd = '%s %s echo %s 2> /dev/null' % (self.conmux_attach,
jadmanskia2db9412008-08-22 21:47:24 +0000110 self.get_conmux_hostname(),
jadmanski1c5e3a12008-08-15 23:08:20 +0000111 cmd)
112 result = utils.system(cmd, ignore_status=True)
113 return result == 0
jadmanskia2db9412008-08-22 21:47:24 +0000114
115
116 def hardreset(self, timeout=DEFAULT_REBOOT_TIMEOUT, wait=True,
jadmanski65eb8f52009-07-24 18:34:43 +0000117 conmux_command='hardreset', num_attempts=1):
jadmanskia2db9412008-08-22 21:47:24 +0000118 """
119 Reach out and slap the box in the power switch.
mbligh410fe2e2009-12-02 19:02:50 +0000120 @params conmux_command: The command to run via the conmux interface
121 @params timeout: timelimit in seconds before the machine is
122 considered unreachable
123 @params wait: Whether or not to wait for the machine to reboot
124 @params num_attempts: Number of times to attempt hard reset erroring
125 on the last attempt.
jadmanskia2db9412008-08-22 21:47:24 +0000126 """
127 conmux_command = "'~$%s'" % conmux_command
128 def reboot():
129 if not self.run_conmux(conmux_command):
130 self.record("ABORT", None, "reboot.start",
131 "hard reset unavailable")
132 raise error.AutoservUnsupportedError(
133 'Hard reset unavailable')
134 self.record("GOOD", None, "reboot.start", "hard reset")
135 if wait:
mbligh410fe2e2009-12-02 19:02:50 +0000136 warning_msg = ('Serial console failed to respond to hard reset '
137 'attempt (%s/%s)')
138 for attempt in xrange(num_attempts-1):
jadmanski65eb8f52009-07-24 18:34:43 +0000139 try:
mbligh410fe2e2009-12-02 19:02:50 +0000140 self.wait_for_restart(timeout, log_failure=False)
jadmanski65eb8f52009-07-24 18:34:43 +0000141 except error.AutoservShutdownError:
mbligh410fe2e2009-12-02 19:02:50 +0000142 logging.warning(warning_msg, attempt, num_attempts)
jadmanski65eb8f52009-07-24 18:34:43 +0000143 else:
144 break
145 else:
mbligh410fe2e2009-12-02 19:02:50 +0000146 # Run on num_attempts=1 or last retry
147 try:
148 self.wait_for_restart(timeout)
149 except error.AutoservShutdwonError:
150 logging.warning(warning_msg, num_attempts, num_attempts)
151 msg = "Host did not shutdown"
152 raise error.AutoservShutdownError(msg)
jadmanskia2db9412008-08-22 21:47:24 +0000153
mbligh1189adf2009-05-21 01:42:35 +0000154 if self.job:
155 self.job.disable_warnings("POWER_FAILURE")
156 try:
157 if wait:
158 self.log_reboot(reboot)
159 else:
160 reboot()
161 finally:
162 if self.job:
163 self.job.enable_warnings("POWER_FAILURE")