Merged ConmuxSSHHost with SSHHost. If the remote machine has a serial
console you can now use SSHHost to hard reset the machine and to log
console output to a file. The class still works file when using a
machine without a serial console, with the caveat that hard reset and
console logging will fail silently.
The change also fixes a couple of issues with the original ConmuxSSHHost
implementation, specifically:
- it properly terminates all the console logging subprocesses
- hardreset can wait for the machine to come back up
From: jadmanski@google.com
git-svn-id: http://test.kernel.org/svn/autotest/trunk@811 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/server/hosts/ssh_host.py b/server/hosts/ssh_host.py
index 463546f..9aff6c6 100644
--- a/server/hosts/ssh_host.py
+++ b/server/hosts/ssh_host.py
@@ -18,7 +18,7 @@
"""
-import types, os, time, re
+import types, os, sys, signal, subprocess, time, re
import base_classes, utils, errors, bootloader
@@ -31,12 +31,20 @@
configured for password-less login, for example through public key
authentication.
+ It includes support for controlling the machine through a serial
+ console on which you can run programs. If such a serial console is
+ set up on the machine then capabilities such as hard reset and
+ boot strap monitoring are available. If the machine does not have a
+ serial console available then ordinary SSH-based commands will
+ still be available, but attempts to use extensions such as
+ console logging or hard reset will fail silently.
+
Implementation details:
This is a leaf class in an abstract class hierarchy, it must
implement the unimplemented methods in parent classes.
"""
- def __init__(self, hostname, user="root", port=22, initialize=True):
+ def __init__(self, hostname, user="root", port=22, initialize=True, logfilename=None, conmux_server=None, conmux_attach=None):
"""
Construct a SSHHost object
@@ -52,6 +60,11 @@
self.tmp_dirs= []
self.initialize = initialize
+ self.conmux_server = conmux_server
+ self.conmux_attach = self.__find_console_attach(conmux_attach)
+ self.logger_pid = None
+ self.__start_console_log(logfilename)
+
super(SSHHost, self).__init__()
self.bootloader = bootloader.Bootloader(self)
@@ -65,6 +78,93 @@
self.run('rm -rf "%s"' % (utils.sh_escape(dir)))
except errors.AutoservRunError:
pass
+ if self.logger_pid:
+ try:
+ pgid = os.getpgid(self.logger_pid)
+ os.killpg(pgid, signal.SIGTERM)
+ except OSError:
+ pass
+
+
+ def __wait_for_restart(self, timeout):
+ self.wait_down(60) # Make sure he's dead, Jim
+ self.wait_up(timeout)
+ time.sleep(2) # this is needed for complete reliability
+ self.wait_up(timeout)
+ print "Reboot complete"
+
+
+ def hardreset(self, timeout=600, wait=True):
+ """
+ Reach out and slap the box in the power switch
+ """
+ result = self.__console_run(r"'~$hardreset'")
+ if wait:
+ self.__wait_for_restart(timeout)
+ return result
+
+
+ def __start_console_log(self, logfilename):
+ """
+ Log the output of the console session to a specified file
+ """
+ if logfilename == None:
+ return
+ if not self.conmux_attach or not os.path.exists(self.conmux_attach):
+ return
+ if self.conmux_server:
+ to = '%s/%s' % (self.conmux_server, self.hostname)
+ else:
+ to = self.hostname
+ cmd = [self.conmux_attach, to, 'cat - > %s' % logfilename]
+ logger = subprocess.Popen(cmd,
+ stderr=open('/dev/null', 'w'),
+ preexec_fn=lambda: os.setpgid(0, 0))
+ self.logger_pid = logger.pid
+
+
+ def __find_console_attach(self, conmux_attach):
+ if conmux_attach:
+ return conmux_attach
+ try:
+ res = utils.run('which conmux-attach')
+ if res.exit_status == 0:
+ return res.stdout.strip()
+ except errors.AutoservRunError, e:
+ pass
+ autoserv_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
+ autotest_conmux = os.path.join(autoserv_dir, '..',
+ 'conmux', 'conmux-attach')
+ autotest_conmux_alt = os.path.join(autoserv_dir,
+ '..', 'autotest',
+ 'conmux', 'conmux-attach')
+ locations = [autotest_conmux,
+ autotest_conmux_alt,
+ '/usr/local/conmux/bin/conmux-attach',
+ '/usr/bin/conmux-attach']
+ for l in locations:
+ if os.path.exists(l):
+ return l
+
+ print "WARNING: conmux-attach not found on autoserv server"
+ return None
+
+
+ def __console_run(self, cmd):
+ """
+ Send a command to the conmux session
+ """
+ if not self.conmux_attach or not os.path.exists(self.conmux_attach):
+ return False
+ if self.conmux_server:
+ to = '%s/%s' % (self.conmux_server, self.hostname)
+ else:
+ to = self.hostname
+ cmd = '%s %s echo %s 2> /dev/null' % (self.conmux_attach,
+ to,
+ cmd)
+ result = os.system(cmd)
+ return result == 0
def run(self, command, timeout=None, ignore_status=False):
@@ -113,12 +213,7 @@
print "Reboot: initiating reboot"
self.run('reboot')
if wait:
- self.wait_down(60) # Make sure he's dead, Jim
- print "Reboot: machine has gone down"
- self.wait_up(timeout)
- time.sleep(2) # this is needed for complete reliability
- self.wait_up(timeout)
- print "Reboot complete"
+ self.__wait_for_restart(timeout)
def get_file(self, source, dest):