blob: 9254e8d5a3ce4d93fbf032a889b834466fb43e91 [file] [log] [blame]
mbligh321b1f52008-04-09 16:23:43 +00001"""This class defines the Remote host class, mixing in the SiteHost class
2if it is available."""
3
mblighf2c33762008-10-18 14:42:34 +00004import os, time
5from autotest_lib.client.common_lib import error
6from autotest_lib.server import utils
7from autotest_lib.server.hosts import base_classes, bootloader
mbligh321b1f52008-04-09 16:23:43 +00008
9
jadmanski1c5e3a12008-08-15 23:08:20 +000010class RemoteHost(base_classes.Host):
jadmanski0afbb632008-06-06 21:10:57 +000011 """This class represents a remote machine on which you can run
12 programs.
mbligh321b1f52008-04-09 16:23:43 +000013
jadmanski0afbb632008-06-06 21:10:57 +000014 It may be accessed through a network, a serial line, ...
15 It is not the machine autoserv is running on.
mbligh321b1f52008-04-09 16:23:43 +000016
jadmanski0afbb632008-06-06 21:10:57 +000017 Implementation details:
18 This is an abstract class, leaf subclasses must implement the methods
19 listed here and in parent classes which have no implementation. They
20 may reimplement methods which already have an implementation. You
21 must not instantiate this class but should instantiate one of those
22 leaf subclasses."""
mbligh321b1f52008-04-09 16:23:43 +000023
mblighf2c33762008-10-18 14:42:34 +000024 DEFAULT_REBOOT_TIMEOUT = base_classes.Host.DEFAULT_REBOOT_TIMEOUT
25 LAST_BOOT_TAG = object()
26
jadmanskif6562912008-10-21 17:59:01 +000027 def _initialize(self, hostname, autodir=None, *args, **dargs):
28 super(RemoteHost, self)._initialize(*args, **dargs)
mbligh321b1f52008-04-09 16:23:43 +000029
jadmanski1c5e3a12008-08-15 23:08:20 +000030 self.hostname = hostname
mblighf2c33762008-10-18 14:42:34 +000031 self.autodir = autodir
32 self.tmp_dirs = []
jadmanskia2db9412008-08-22 21:47:24 +000033
34
35 def __del__(self):
mblighf2c33762008-10-18 14:42:34 +000036 self.stop_loggers()
37
38 if hasattr(self, 'tmp_dirs'):
39 for dir in self.tmp_dirs:
40 try:
41 self.run('rm -rf "%s"' % (utils.sh_escape(dir)))
42 except error.AutoservRunError:
43 pass
44
45
46 def get_autodir(self):
47 return self.autodir
48
49
50 def set_autodir(self, autodir):
51 '''
52 This method is called to make the host object aware of the
53 where autotest is installed. Called in server/autotest.py
54 after a successful install
55 '''
56 self.autodir = autodir
57
58
59 def sysrq_reboot(self):
60 self.run('echo b > /proc/sysrq-trigger &')
61
62
63 def reboot(self, timeout=DEFAULT_REBOOT_TIMEOUT, label=LAST_BOOT_TAG,
64 kernel_args=None, wait=True, **dargs):
65 """
66 Reboot the remote host.
67
68 Args:
69 timeout - How long to wait for the reboot.
70 label - The label we should boot into. If None, we will
71 boot into the default kernel. If it's LAST_BOOT_TAG,
72 we'll boot into whichever kernel was .boot'ed last
73 (or the default kernel if we haven't .boot'ed in this
74 job). If it's None, we'll boot into the default kernel.
75 If it's something else, we'll boot into that.
76 wait - Should we wait to see if the machine comes back up.
77 """
78 if self.job:
79 if label == self.LAST_BOOT_TAG:
80 label = self.job.last_boot_tag
81 else:
82 self.job.last_boot_tag = label
83
84 self.reboot_setup(label=label, kernel_args=kernel_args, **dargs)
85
86 if label or kernel_args:
87 self.bootloader.install_boottool()
88 if not label:
89 default = int(self.bootloader.get_default())
90 label = self.bootloader.get_titles()[default]
91 self.bootloader.boot_once(label)
92 if kernel_args:
93 self.bootloader.add_args(label, kernel_args)
94
95 # define a function for the reboot and run it in a group
96 print "Reboot: initiating reboot"
97 def reboot():
98 self.record("GOOD", None, "reboot.start")
99 try:
100 self.run('(sleep 5; reboot) '
101 '</dev/null >/dev/null 2>&1 &')
102 except error.AutoservRunError:
103 self.record("ABORT", None, "reboot.start",
104 "reboot command failed")
105 raise
106 if wait:
107 self.wait_for_restart(timeout)
108 self.reboot_followup(**dargs)
109
110 # if this is a full reboot-and-wait, run the reboot inside a group
111 if wait:
112 self.log_reboot(reboot)
113 else:
114 reboot()
115
116
117 def wait_for_restart(self, timeout=DEFAULT_REBOOT_TIMEOUT):
118 """ Wait for the host to come back from a reboot. This wraps the
119 generic wait_for_restart implementation in a reboot group. """
120 def reboot_func():
121 super(RemoteHost, self).wait_for_restart(timeout=timeout)
122 self.log_reboot(reboot_func)
123
124
125 def get_tmp_dir(self):
126 """
127 Return the pathname of a directory on the host suitable
128 for temporary file storage.
129
130 The directory and its content will be deleted automatically
131 on the destruction of the Host object that was used to obtain
132 it.
133 """
134 dir_name= self.run("mktemp -d /tmp/autoserv-XXXXXX").stdout.rstrip()
135 self.tmp_dirs.append(dir_name)
136 return dir_name
137
138
139 def ping(self):
140 """
141 Ping the remote system, and return whether it's available
142 """
143 fpingcmd = "%s -q %s" % ('/usr/bin/fping', self.hostname)
144 rc = utils.system(fpingcmd, ignore_status = 1)
145 return (rc == 0)
146
147
148 def check_uptime(self):
149 """
150 Check that uptime is available and monotonically increasing.
151 """
152 if not self.ping():
153 raise error.AutoservHostError('Client is not pingable')
154 result = self.run("/bin/cat /proc/uptime", 30)
155 return result.stdout.strip().split()[0]
156
157
158 def get_crashinfo(self, test_start_time):
159 print "Collecting crash information..."
160 super(RemoteHost, self).get_crashinfo(test_start_time)
161
162 # wait for four hours, to see if the machine comes back up
163 current_time = time.strftime("%b %d %H:%M:%S", time.localtime())
164 print "Waiting four hours for %s to come up (%s)" % (self.hostname,
165 current_time)
166 if not self.wait_up(timeout=4*60*60):
167 print "%s down, unable to collect crash info" % self.hostname
168 return
169 else:
170 print "%s is back up, collecting crash info" % self.hostname
171
172 # find a directory to put the crashinfo into
173 if self.job:
174 infodir = self.job.resultdir
175 else:
176 infodir = os.path.abspath(os.getcwd())
177 infodir = os.path.join(infodir, "crashinfo.%s" % self.hostname)
178 if not os.path.exists(infodir):
179 os.mkdir(infodir)
180
181 # collect various log files
182 log_files = ["/var/log/messages", "/var/log/monitor-ssh-reboots"]
183 for log in log_files:
184 print "Collecting %s..." % log
185 try:
186 self.get_file(log, infodir)
187 except Exception, e:
188 print "crashinfo collection of %s failed with:\n%s" % (log, e)
189
190 # collect dmesg
191 print "Collecting dmesg..."
192 try:
193 result = self.run("dmesg").stdout
194 file(os.path.join(infodir, "dmesg"), "w").write(result)
195 except Exception, e:
196 print "crashinfo collection of dmesg failed with:\n%s" % e
197
198
jadmanskica7da372008-10-21 16:26:52 +0000199 def are_wait_up_processes_up(self):
mblighf2c33762008-10-18 14:42:34 +0000200 """
201 Checks if any HOSTS waitup processes are running yet on the
202 remote host.
203
204 Returns True if any the waitup processes are running, False
205 otherwise.
206 """
207 processes = self.get_wait_up_processes()
208 if len(processes) == 0:
209 return True # wait up processes aren't being used
210 for procname in processes:
211 exit_status = self.run("{ ps -e || ps; } | grep '%s'" % procname,
212 ignore_status=True).exit_status
213 if exit_status == 0:
214 return True
215 return False