blob: 286fbd9d23268c4792f5ccd20e309c3a3b72f3d8 [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
jadmanski96b78072009-05-21 22:21:04 +00004import os, logging
mblighf2c33762008-10-18 14:42:34 +00005from autotest_lib.client.common_lib import error
jadmanski96b78072009-05-21 22:21:04 +00006from autotest_lib.server import utils
mblighf2c33762008-10-18 14:42:34 +00007from 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):
jadmanskid60321a2008-10-28 20:32:05 +000011 """
12 This class represents a remote machine on which you can run
jadmanski0afbb632008-06-06 21:10:57 +000013 programs.
mbligh321b1f52008-04-09 16:23:43 +000014
jadmanski0afbb632008-06-06 21:10:57 +000015 It may be accessed through a network, a serial line, ...
16 It is not the machine autoserv is running on.
mbligh321b1f52008-04-09 16:23:43 +000017
jadmanski0afbb632008-06-06 21:10:57 +000018 Implementation details:
19 This is an abstract class, leaf subclasses must implement the methods
20 listed here and in parent classes which have no implementation. They
21 may reimplement methods which already have an implementation. You
22 must not instantiate this class but should instantiate one of those
jadmanskid60321a2008-10-28 20:32:05 +000023 leaf subclasses.
24 """
mbligh321b1f52008-04-09 16:23:43 +000025
mblighf2c33762008-10-18 14:42:34 +000026 DEFAULT_REBOOT_TIMEOUT = base_classes.Host.DEFAULT_REBOOT_TIMEOUT
27 LAST_BOOT_TAG = object()
28
jadmanskif6562912008-10-21 17:59:01 +000029 def _initialize(self, hostname, autodir=None, *args, **dargs):
30 super(RemoteHost, self)._initialize(*args, **dargs)
mbligh321b1f52008-04-09 16:23:43 +000031
jadmanski1c5e3a12008-08-15 23:08:20 +000032 self.hostname = hostname
mblighf2c33762008-10-18 14:42:34 +000033 self.autodir = autodir
34 self.tmp_dirs = []
jadmanskia2db9412008-08-22 21:47:24 +000035
36
jadmanskiedf33e02009-05-22 16:47:27 +000037 def __repr__(self):
38 return "<remote host: %s>" % self.hostname
39
40
jadmanski53aaf382008-11-17 16:22:31 +000041 def close(self):
42 super(RemoteHost, self).close()
mblighf2c33762008-10-18 14:42:34 +000043 self.stop_loggers()
44
45 if hasattr(self, 'tmp_dirs'):
46 for dir in self.tmp_dirs:
47 try:
48 self.run('rm -rf "%s"' % (utils.sh_escape(dir)))
49 except error.AutoservRunError:
50 pass
51
52
jadmanskid60321a2008-10-28 20:32:05 +000053 def job_start(self):
54 """
55 Abstract method, called the first time a remote host object
56 is created for a specific host after a job starts.
57
58 This method depends on the create_host factory being used to
59 construct your host object. If you directly construct host objects
60 you will need to call this method yourself (and enforce the
61 single-call rule).
62 """
63 pass
64
65
mblighf2c33762008-10-18 14:42:34 +000066 def get_autodir(self):
67 return self.autodir
68
69
70 def set_autodir(self, autodir):
jadmanskid60321a2008-10-28 20:32:05 +000071 """
mblighf2c33762008-10-18 14:42:34 +000072 This method is called to make the host object aware of the
73 where autotest is installed. Called in server/autotest.py
74 after a successful install
jadmanskid60321a2008-10-28 20:32:05 +000075 """
mblighf2c33762008-10-18 14:42:34 +000076 self.autodir = autodir
77
78
79 def sysrq_reboot(self):
80 self.run('echo b > /proc/sysrq-trigger &')
81
82
83 def reboot(self, timeout=DEFAULT_REBOOT_TIMEOUT, label=LAST_BOOT_TAG,
mbligh959ed872009-04-17 22:18:25 +000084 kernel_args=None, wait=True, fastsync=False,
85 reboot_cmd=None, **dargs):
mblighf2c33762008-10-18 14:42:34 +000086 """
87 Reboot the remote host.
88
89 Args:
90 timeout - How long to wait for the reboot.
91 label - The label we should boot into. If None, we will
92 boot into the default kernel. If it's LAST_BOOT_TAG,
93 we'll boot into whichever kernel was .boot'ed last
94 (or the default kernel if we haven't .boot'ed in this
95 job). If it's None, we'll boot into the default kernel.
96 If it's something else, we'll boot into that.
97 wait - Should we wait to see if the machine comes back up.
mbligh2b949772009-02-26 00:59:36 +000098 fastsync - Don't wait for the sync to complete, just start one
99 and move on. This is for cases where rebooting prompty
100 is more important than data integrity and/or the
101 machine may have disks that cause sync to never return.
mbligh959ed872009-04-17 22:18:25 +0000102 reboot_cmd - Reboot command to execute.
mblighf2c33762008-10-18 14:42:34 +0000103 """
104 if self.job:
105 if label == self.LAST_BOOT_TAG:
106 label = self.job.last_boot_tag
107 else:
108 self.job.last_boot_tag = label
109
110 self.reboot_setup(label=label, kernel_args=kernel_args, **dargs)
111
112 if label or kernel_args:
113 self.bootloader.install_boottool()
114 if not label:
115 default = int(self.bootloader.get_default())
116 label = self.bootloader.get_titles()[default]
117 self.bootloader.boot_once(label)
118 if kernel_args:
119 self.bootloader.add_args(label, kernel_args)
120
121 # define a function for the reboot and run it in a group
122 print "Reboot: initiating reboot"
123 def reboot():
124 self.record("GOOD", None, "reboot.start")
125 try:
jadmanskid544a352009-01-14 23:36:28 +0000126 # sync before starting the reboot, so that a long sync during
127 # shutdown isn't timed out by wait_down's short timeout
mbligh2b949772009-02-26 00:59:36 +0000128 if not fastsync:
mbligh959ed872009-04-17 22:18:25 +0000129 self.run('sync; sync', timeout=timeout, ignore_status=True)
jadmanskid544a352009-01-14 23:36:28 +0000130
mbligh959ed872009-04-17 22:18:25 +0000131 if reboot_cmd:
132 self.run(reboot_cmd)
133 else:
134 # Try several methods of rebooting in increasing harshness.
135 self.run('(('
136 ' sync &'
137 ' sleep 5; reboot &'
138 ' sleep 60; reboot -f &'
139 ' sleep 10; reboot -nf &'
140 ' sleep 10; telinit 6 &'
141 ') </dev/null >/dev/null 2>&1 &)')
mblighf2c33762008-10-18 14:42:34 +0000142 except error.AutoservRunError:
143 self.record("ABORT", None, "reboot.start",
144 "reboot command failed")
145 raise
146 if wait:
jadmanskid778ae42009-01-07 15:07:36 +0000147 self.wait_for_restart(timeout, **dargs)
mblighf2c33762008-10-18 14:42:34 +0000148
149 # if this is a full reboot-and-wait, run the reboot inside a group
150 if wait:
151 self.log_reboot(reboot)
152 else:
153 reboot()
154
155
jadmanski4f909252008-12-01 20:47:10 +0000156 def reboot_followup(self, *args, **dargs):
157 super(RemoteHost, self).reboot_followup(*args, **dargs)
158 if self.job:
159 self.job.profilers.handle_reboot(self)
160
161
jadmanskid778ae42009-01-07 15:07:36 +0000162 def wait_for_restart(self, timeout=DEFAULT_REBOOT_TIMEOUT, **dargs):
jadmanskid60321a2008-10-28 20:32:05 +0000163 """
164 Wait for the host to come back from a reboot. This wraps the
165 generic wait_for_restart implementation in a reboot group.
166 """
mblighf2c33762008-10-18 14:42:34 +0000167 def reboot_func():
jadmanskid778ae42009-01-07 15:07:36 +0000168 super(RemoteHost, self).wait_for_restart(timeout=timeout, **dargs)
mblighf2c33762008-10-18 14:42:34 +0000169 self.log_reboot(reboot_func)
170
171
mbligh1264b512008-11-05 22:21:49 +0000172 def cleanup(self):
173 super(RemoteHost, self).cleanup()
174 self.reboot()
175
176
mblighe48bcfb2008-11-11 17:09:44 +0000177 def get_tmp_dir(self, parent='/tmp'):
mblighf2c33762008-10-18 14:42:34 +0000178 """
179 Return the pathname of a directory on the host suitable
180 for temporary file storage.
181
182 The directory and its content will be deleted automatically
183 on the destruction of the Host object that was used to obtain
184 it.
185 """
jadmanski9f7dd112008-11-17 16:40:05 +0000186 self.run("mkdir -p %s" % parent)
mblighe48bcfb2008-11-11 17:09:44 +0000187 template = os.path.join(parent, 'autoserv-XXXXXX')
jadmanski9f7dd112008-11-17 16:40:05 +0000188 dir_name = self.run("mktemp -d %s" % template).stdout.rstrip()
mblighf2c33762008-10-18 14:42:34 +0000189 self.tmp_dirs.append(dir_name)
190 return dir_name
191
192
jadmanskiea455662009-03-25 22:25:39 +0000193 def delete_tmp_dir(self, tmpdir):
194 """
195 Delete the given temporary directory on the remote machine.
196 """
197 self.run('rm -rf "%s"' % utils.sh_escape(tmpdir), ignore_status=True)
198 self.tmp_dirs.remove(tmpdir)
199
200
mblighf2c33762008-10-18 14:42:34 +0000201 def ping(self):
202 """
203 Ping the remote system, and return whether it's available
204 """
205 fpingcmd = "%s -q %s" % ('/usr/bin/fping', self.hostname)
206 rc = utils.system(fpingcmd, ignore_status = 1)
207 return (rc == 0)
208
209
210 def check_uptime(self):
211 """
212 Check that uptime is available and monotonically increasing.
213 """
214 if not self.ping():
215 raise error.AutoservHostError('Client is not pingable')
216 result = self.run("/bin/cat /proc/uptime", 30)
217 return result.stdout.strip().split()[0]
218
219
jadmanskica7da372008-10-21 16:26:52 +0000220 def are_wait_up_processes_up(self):
mblighf2c33762008-10-18 14:42:34 +0000221 """
222 Checks if any HOSTS waitup processes are running yet on the
223 remote host.
224
225 Returns True if any the waitup processes are running, False
226 otherwise.
227 """
228 processes = self.get_wait_up_processes()
229 if len(processes) == 0:
230 return True # wait up processes aren't being used
231 for procname in processes:
232 exit_status = self.run("{ ps -e || ps; } | grep '%s'" % procname,
233 ignore_status=True).exit_status
234 if exit_status == 0:
235 return True
236 return False