blob: 8dd0df4d0ce8db07447adb410ad8913395235edc [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
jadmanski4900b3b2009-07-02 22:12:08 +000029 VAR_LOG_MESSAGES_COPY_PATH = "/var/log/messages.autotest_start"
30
jadmanskif6562912008-10-21 17:59:01 +000031 def _initialize(self, hostname, autodir=None, *args, **dargs):
32 super(RemoteHost, self)._initialize(*args, **dargs)
mbligh321b1f52008-04-09 16:23:43 +000033
jadmanski1c5e3a12008-08-15 23:08:20 +000034 self.hostname = hostname
mblighf2c33762008-10-18 14:42:34 +000035 self.autodir = autodir
36 self.tmp_dirs = []
jadmanskia2db9412008-08-22 21:47:24 +000037
38
jadmanskiedf33e02009-05-22 16:47:27 +000039 def __repr__(self):
40 return "<remote host: %s>" % self.hostname
41
42
jadmanski53aaf382008-11-17 16:22:31 +000043 def close(self):
44 super(RemoteHost, self).close()
mblighf2c33762008-10-18 14:42:34 +000045 self.stop_loggers()
46
47 if hasattr(self, 'tmp_dirs'):
48 for dir in self.tmp_dirs:
49 try:
50 self.run('rm -rf "%s"' % (utils.sh_escape(dir)))
51 except error.AutoservRunError:
52 pass
53
54
jadmanskid60321a2008-10-28 20:32:05 +000055 def job_start(self):
56 """
57 Abstract method, called the first time a remote host object
58 is created for a specific host after a job starts.
59
60 This method depends on the create_host factory being used to
61 construct your host object. If you directly construct host objects
62 you will need to call this method yourself (and enforce the
63 single-call rule).
64 """
jadmanski4900b3b2009-07-02 22:12:08 +000065 try:
66 self.run('rm -f %s' % self.VAR_LOG_MESSAGES_COPY_PATH)
67 self.run('cp /var/log/messages %s' %
68 self.VAR_LOG_MESSAGES_COPY_PATH)
69 except Exception, e:
70 # Non-fatal error
71 logging.info('Failed to copy /var/log/messages at startup: %s', e)
jadmanskid60321a2008-10-28 20:32:05 +000072
73
mblighf2c33762008-10-18 14:42:34 +000074 def get_autodir(self):
75 return self.autodir
76
77
78 def set_autodir(self, autodir):
jadmanskid60321a2008-10-28 20:32:05 +000079 """
mblighf2c33762008-10-18 14:42:34 +000080 This method is called to make the host object aware of the
81 where autotest is installed. Called in server/autotest.py
82 after a successful install
jadmanskid60321a2008-10-28 20:32:05 +000083 """
mblighf2c33762008-10-18 14:42:34 +000084 self.autodir = autodir
85
86
87 def sysrq_reboot(self):
88 self.run('echo b > /proc/sysrq-trigger &')
89
90
91 def reboot(self, timeout=DEFAULT_REBOOT_TIMEOUT, label=LAST_BOOT_TAG,
mbligh959ed872009-04-17 22:18:25 +000092 kernel_args=None, wait=True, fastsync=False,
93 reboot_cmd=None, **dargs):
mblighf2c33762008-10-18 14:42:34 +000094 """
95 Reboot the remote host.
96
97 Args:
98 timeout - How long to wait for the reboot.
99 label - The label we should boot into. If None, we will
100 boot into the default kernel. If it's LAST_BOOT_TAG,
101 we'll boot into whichever kernel was .boot'ed last
102 (or the default kernel if we haven't .boot'ed in this
103 job). If it's None, we'll boot into the default kernel.
104 If it's something else, we'll boot into that.
105 wait - Should we wait to see if the machine comes back up.
mbligh2b949772009-02-26 00:59:36 +0000106 fastsync - Don't wait for the sync to complete, just start one
107 and move on. This is for cases where rebooting prompty
108 is more important than data integrity and/or the
109 machine may have disks that cause sync to never return.
mbligh959ed872009-04-17 22:18:25 +0000110 reboot_cmd - Reboot command to execute.
mblighf2c33762008-10-18 14:42:34 +0000111 """
112 if self.job:
113 if label == self.LAST_BOOT_TAG:
114 label = self.job.last_boot_tag
115 else:
116 self.job.last_boot_tag = label
117
118 self.reboot_setup(label=label, kernel_args=kernel_args, **dargs)
119
120 if label or kernel_args:
mblighf2c33762008-10-18 14:42:34 +0000121 if not label:
mblighc2ebea02009-10-02 00:02:33 +0000122 label = self.bootloader.get_default_title()
mblighf2c33762008-10-18 14:42:34 +0000123 self.bootloader.boot_once(label)
124 if kernel_args:
125 self.bootloader.add_args(label, kernel_args)
126
127 # define a function for the reboot and run it in a group
128 print "Reboot: initiating reboot"
129 def reboot():
130 self.record("GOOD", None, "reboot.start")
131 try:
jadmanskic0354912010-01-12 15:57:29 +0000132 current_boot_id = self.get_boot_id()
133
jadmanskid544a352009-01-14 23:36:28 +0000134 # sync before starting the reboot, so that a long sync during
135 # shutdown isn't timed out by wait_down's short timeout
mbligh2b949772009-02-26 00:59:36 +0000136 if not fastsync:
mbligh959ed872009-04-17 22:18:25 +0000137 self.run('sync; sync', timeout=timeout, ignore_status=True)
jadmanskid544a352009-01-14 23:36:28 +0000138
mbligh959ed872009-04-17 22:18:25 +0000139 if reboot_cmd:
140 self.run(reboot_cmd)
141 else:
142 # Try several methods of rebooting in increasing harshness.
143 self.run('(('
144 ' sync &'
145 ' sleep 5; reboot &'
146 ' sleep 60; reboot -f &'
147 ' sleep 10; reboot -nf &'
148 ' sleep 10; telinit 6 &'
149 ') </dev/null >/dev/null 2>&1 &)')
mblighf2c33762008-10-18 14:42:34 +0000150 except error.AutoservRunError:
151 self.record("ABORT", None, "reboot.start",
152 "reboot command failed")
153 raise
154 if wait:
jadmanskic0354912010-01-12 15:57:29 +0000155 self.wait_for_restart(timeout, old_boot_id=current_boot_id,
156 **dargs)
mblighf2c33762008-10-18 14:42:34 +0000157
158 # if this is a full reboot-and-wait, run the reboot inside a group
159 if wait:
160 self.log_reboot(reboot)
161 else:
162 reboot()
163
164
jadmanski4f909252008-12-01 20:47:10 +0000165 def reboot_followup(self, *args, **dargs):
166 super(RemoteHost, self).reboot_followup(*args, **dargs)
167 if self.job:
168 self.job.profilers.handle_reboot(self)
169
170
jadmanskid778ae42009-01-07 15:07:36 +0000171 def wait_for_restart(self, timeout=DEFAULT_REBOOT_TIMEOUT, **dargs):
jadmanskid60321a2008-10-28 20:32:05 +0000172 """
173 Wait for the host to come back from a reboot. This wraps the
174 generic wait_for_restart implementation in a reboot group.
175 """
mblighf2c33762008-10-18 14:42:34 +0000176 def reboot_func():
jadmanskid778ae42009-01-07 15:07:36 +0000177 super(RemoteHost, self).wait_for_restart(timeout=timeout, **dargs)
mblighf2c33762008-10-18 14:42:34 +0000178 self.log_reboot(reboot_func)
179
180
mbligh1264b512008-11-05 22:21:49 +0000181 def cleanup(self):
182 super(RemoteHost, self).cleanup()
183 self.reboot()
184
185
mblighe48bcfb2008-11-11 17:09:44 +0000186 def get_tmp_dir(self, parent='/tmp'):
mblighf2c33762008-10-18 14:42:34 +0000187 """
188 Return the pathname of a directory on the host suitable
189 for temporary file storage.
190
191 The directory and its content will be deleted automatically
192 on the destruction of the Host object that was used to obtain
193 it.
194 """
jadmanski9f7dd112008-11-17 16:40:05 +0000195 self.run("mkdir -p %s" % parent)
mblighe48bcfb2008-11-11 17:09:44 +0000196 template = os.path.join(parent, 'autoserv-XXXXXX')
jadmanski9f7dd112008-11-17 16:40:05 +0000197 dir_name = self.run("mktemp -d %s" % template).stdout.rstrip()
mblighf2c33762008-10-18 14:42:34 +0000198 self.tmp_dirs.append(dir_name)
199 return dir_name
200
201
jadmanskiea455662009-03-25 22:25:39 +0000202 def delete_tmp_dir(self, tmpdir):
203 """
204 Delete the given temporary directory on the remote machine.
205 """
206 self.run('rm -rf "%s"' % utils.sh_escape(tmpdir), ignore_status=True)
207 self.tmp_dirs.remove(tmpdir)
208
209
mblighf2c33762008-10-18 14:42:34 +0000210 def check_uptime(self):
211 """
212 Check that uptime is available and monotonically increasing.
213 """
mbligha43f6d22009-08-24 22:09:44 +0000214 if not self.is_up():
215 raise error.AutoservHostError('Client does not appear to be up')
mblighf2c33762008-10-18 14:42:34 +0000216 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