blob: afd875c77b36ad76098f52e968c41523b72a32f4 [file] [log] [blame]
jadmanski1c5e3a12008-08-15 23:08:20 +00001import os, sys, subprocess
2
jadmanskia2db9412008-08-22 21:47:24 +00003from autotest_lib.client.common_lib import utils, error
4from autotest_lib.server import utils as server_utils
jadmanski1c5e3a12008-08-15 23:08:20 +00005from autotest_lib.server.hosts import site_host
6
7
8class SerialHost(site_host.SiteHost):
jadmanskia2db9412008-08-22 21:47:24 +00009 DEFAULT_REBOOT_TIMEOUT = site_host.SiteHost.DEFAULT_REBOOT_TIMEOUT
10
jadmanski1c5e3a12008-08-15 23:08:20 +000011 def __init__(self, conmux_server=None, conmux_attach=None,
12 conmux_log="console.log", *args, **dargs):
13 super(SerialHost, self).__init__(*args, **dargs)
14
15 self.conmux_server = conmux_server
jadmanskia2db9412008-08-22 21:47:24 +000016 self.conmux_attach = self._get_conmux_attach(conmux_attach)
jadmanski1c5e3a12008-08-15 23:08:20 +000017
18 self.logger_popen = None
19 self.warning_stream = None
20 self.__start_console_log(conmux_log)
21
22
23 def __del__(self):
jadmanskia2db9412008-08-22 21:47:24 +000024 super(SerialHost, self).__del__()
jadmanski1c5e3a12008-08-15 23:08:20 +000025 self.__stop_console_log()
26
27
jadmanskia2db9412008-08-22 21:47:24 +000028 @classmethod
29 def _get_conmux_attach(cls, conmux_attach=None):
30 if conmux_attach:
31 return conmux_attach
32
33 # assume we're using the conmux-attach provided with autotest
34 server_dir = server_utils.get_server_dir()
35 path = os.path.join(server_dir, "..", "conmux", "conmux-attach")
36 path = os.path.abspath(path)
37 return path
38
39
40 @staticmethod
41 def _get_conmux_hostname(hostname, conmux_server):
42 if conmux_server:
43 return "%s/%s" % (conmux_server, hostname)
jadmanski1c5e3a12008-08-15 23:08:20 +000044 else:
jadmanskia2db9412008-08-22 21:47:24 +000045 return hostname
46
47
48 def get_conmux_hostname(self):
49 return self._get_conmux_hostname(self.hostname, self.conmux_server)
50
51
52 @classmethod
53 def host_is_supported(cls, hostname, conmux_server=None,
54 conmux_attach=None):
55 """ Returns a boolean indicating if the remote host with "hostname"
56 supports use as a SerialHost """
57 conmux_attach = cls._get_conmux_attach(conmux_attach)
58 conmux_hostname = cls._get_conmux_hostname(hostname, conmux_server)
59 cmd = "%s %s echo 2> /dev/null" % (conmux_attach, conmux_hostname)
60 result = utils.run(cmd)
61 return result.exit_status == 0
jadmanski1c5e3a12008-08-15 23:08:20 +000062
63
64 def __start_console_log(self, logfilename):
65 """
66 Log the output of the console session to a specified file
67 """
68 if logfilename == None:
69 return
70 if not self.conmux_attach or not os.path.exists(self.conmux_attach):
71 return
72
73 r, w = os.pipe()
74 script_path = os.path.join(self.serverdir,
75 'warning_monitor.py')
jadmanskia2db9412008-08-22 21:47:24 +000076 cmd = [self.conmux_attach, self.get_conmux_hostname(),
jadmanski1c5e3a12008-08-15 23:08:20 +000077 '%s %s %s %d' % (sys.executable, script_path,
78 logfilename, w)]
79 dev_null = open(os.devnull, 'w')
80
81 self.warning_stream = os.fdopen(r, 'r', 0)
82 if self.job:
83 self.job.warning_loggers.add(self.warning_stream)
84 self.logger_popen = subprocess.Popen(cmd, stderr=dev_null)
85 os.close(w)
86
87
88 def __stop_console_log(self):
89 if getattr(self, 'logger_popen', None):
90 utils.nuke_subprocess(self.logger_popen)
91 if self.job:
92 self.job.warning_loggers.discard(self.warning_stream)
93 self.warning_stream.close()
94
95
96 def run_conmux(self, cmd):
97 """
98 Send a command to the conmux session
99 """
100 if not self.conmux_attach or not os.path.exists(self.conmux_attach):
101 return False
102 cmd = '%s %s echo %s 2> /dev/null' % (self.conmux_attach,
jadmanskia2db9412008-08-22 21:47:24 +0000103 self.get_conmux_hostname(),
jadmanski1c5e3a12008-08-15 23:08:20 +0000104 cmd)
105 result = utils.system(cmd, ignore_status=True)
106 return result == 0
jadmanskia2db9412008-08-22 21:47:24 +0000107
108
109 def hardreset(self, timeout=DEFAULT_REBOOT_TIMEOUT, wait=True,
110 conmux_command='hardreset'):
111 """
112 Reach out and slap the box in the power switch.
113 Args:
114 conmux_command: The command to run via the conmux interface
115 timeout: timelimit in seconds before the machine is
116 considered unreachable
117 wait: Whether or not to wait for the machine to reboot
118
119 """
120 conmux_command = "'~$%s'" % conmux_command
121 def reboot():
122 if not self.run_conmux(conmux_command):
123 self.record("ABORT", None, "reboot.start",
124 "hard reset unavailable")
125 raise error.AutoservUnsupportedError(
126 'Hard reset unavailable')
127 self.record("GOOD", None, "reboot.start", "hard reset")
128 if wait:
129 self.wait_for_restart(timeout)
130
131 if wait:
132 self.log_reboot(reboot)
133 else:
134 reboot()