Initial refactoring so that I can change the serial console
monitoring. For now, I just pulled all of the console stuff out
into a separate SerialHost class so that it's isolated from the
SSHHost code.
This also adds a create_host factory method into hosts/__init__.py
I'm going to mail another patch later that converts existing code
over to use hosts.create_host(hostname) to get a host object, rather
than using hosts.SSHHost(hostname).
Right now the current structure is rather painful; for example I had
to make SerialHost a parent of SSHHost so that I could make the changes
without breaking existing code. Adding new features will have the same
problem; you have to cram them into SSHHost, or else no existing code
will use them. In the future if we use this factory method it'll be a
lot easier to add new features and expose them to existing tests by
default.
Risk: Medium
Visibility: Changes the internal hierarchy of the server.hosts
classes, but shouldn't affect other code that uses SSHHost.
Signed-off-by: John Admanski <jadmanski@google.com>
git-svn-id: http://test.kernel.org/svn/autotest/trunk@1998 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/server/hosts/serial.py b/server/hosts/serial.py
new file mode 100644
index 0000000..b32e238
--- /dev/null
+++ b/server/hosts/serial.py
@@ -0,0 +1,77 @@
+import os, sys, subprocess
+
+from autotest_lib.client.common_lib import utils
+from autotest_lib.server.hosts import site_host
+
+
+class SerialHost(site_host.SiteHost):
+ def __init__(self, conmux_server=None, conmux_attach=None,
+ conmux_log="console.log", *args, **dargs):
+ super(SerialHost, self).__init__(*args, **dargs)
+
+ self.conmux_server = conmux_server
+ if conmux_attach:
+ self.conmux_attach = conmux_attach
+ else:
+ self.conmux_attach = os.path.abspath(os.path.join(
+ self.serverdir, '..', 'conmux', 'conmux-attach'))
+
+ self.logger_popen = None
+ self.warning_stream = None
+ self.__start_console_log(conmux_log)
+
+
+ def __del__(self):
+ self.__stop_console_log()
+
+
+ def __conmux_hostname(self):
+ if self.conmux_server:
+ return '%s/%s' % (self.conmux_server, self.hostname)
+ else:
+ return self.hostname
+
+
+ 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
+
+ r, w = os.pipe()
+ script_path = os.path.join(self.serverdir,
+ 'warning_monitor.py')
+ cmd = [self.conmux_attach, self.__conmux_hostname(),
+ '%s %s %s %d' % (sys.executable, script_path,
+ logfilename, w)]
+ dev_null = open(os.devnull, 'w')
+
+ self.warning_stream = os.fdopen(r, 'r', 0)
+ if self.job:
+ self.job.warning_loggers.add(self.warning_stream)
+ self.logger_popen = subprocess.Popen(cmd, stderr=dev_null)
+ os.close(w)
+
+
+ def __stop_console_log(self):
+ if getattr(self, 'logger_popen', None):
+ utils.nuke_subprocess(self.logger_popen)
+ if self.job:
+ self.job.warning_loggers.discard(self.warning_stream)
+ self.warning_stream.close()
+
+
+ def run_conmux(self, cmd):
+ """
+ Send a command to the conmux session
+ """
+ if not self.conmux_attach or not os.path.exists(self.conmux_attach):
+ return False
+ cmd = '%s %s echo %s 2> /dev/null' % (self.conmux_attach,
+ self.__conmux_hostname(),
+ cmd)
+ result = utils.system(cmd, ignore_status=True)
+ return result == 0