[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [XTF PATCH v3] xtf-runner: support two modes for getting output



We need two modes for getting output:

1. Use console directly with newer (>=4.8) Xen
2. Use log files for older Xen

This patch implements both. The default behaviour is to use the console
mode.

Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx>
---
v3:
1. use os module for opening log file
2. poll up to 1 second for final output in logfile mode

v2: delete auto selection mode, squash all patches into one.
---
 xtf-runner | 119 +++++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 97 insertions(+), 22 deletions(-)

diff --git a/xtf-runner b/xtf-runner
index c063699..96a5ba0 100755
--- a/xtf-runner
+++ b/xtf-runner
@@ -7,7 +7,7 @@
 Currently assumes the presence and availability of the `xl` toolstack.
 """
 
-import sys, os, os.path as path
+import sys, os, os.path as path, signal
 
 from optparse import OptionParser
 from subprocess import Popen, PIPE, call as subproc_call, check_output
@@ -425,30 +425,19 @@ def list_tests(opts):
     for sel in opts.selection:
         print sel
 
+def run_test_console(opts, test):
+    """ Run a specific test via xenconsole"""
 
-def run_test(test):
-    """ Run a specific test """
-
-    cmd = ['xl', 'create', '-p', test.cfg_path()]
-    print "Executing '%s'" % (" ".join(cmd), )
-    rc = subproc_call(cmd)
-    if rc:
-        raise RunnerError("Failed to create VM")
-
-    cmd = ['xl', 'console', test.vm_name()]
+    cmd = ['xl', 'create', '-Fc', test.cfg_path()]
     print "Executing '%s'" % (" ".join(cmd), )
-    console = Popen(cmd, stdout = PIPE)
+    guest = Popen(cmd, stdout = PIPE, stderr = PIPE)
 
-    cmd = ['xl', 'unpause', test.vm_name()]
-    print "Executing '%s'" % (" ".join(cmd), )
-    rc = subproc_call(cmd)
-    if rc:
-        raise RunnerError("Failed to unpause VM")
+    # stdout is console output, stderr is xl output
+    stdout, stderr = guest.communicate()
 
-    stdout, _ = console.communicate()
-
-    if console.returncode:
-        raise RunnerError("Failed to obtain VM console")
+    if guest.returncode:
+        print stderr
+        raise RunnerError("Failed to communicate with guest")
 
     lines = stdout.splitlines()
 
@@ -470,6 +459,59 @@ def run_test(test):
     return "ERROR"
 
 
+should_exit = False
+def sigalrm_handler(signum, frame):
+    """Signal handler for SIGALRM"""
+
+    global should_exit
+    should_exit = True
+
+def run_test_logfile(opts, test):
+    """ Run a specific test via grepping log file"""
+
+    global should_exit
+    fn = opts.logfile_dir + (opts.logfile_pattern % test)
+
+    print "Using %s" % fn
+
+    fd = os.open(fn, os.O_CREAT|os.O_RDONLY, 0644)
+    logfile = os.fdopen(fd)
+    logfile.seek(0, os.SEEK_END)
+
+    cmd = ['xl', 'create', '-F', test.cfg_path()]
+    print "Executing '%s'" % (" ".join(cmd), )
+    rc = subproc_call(cmd)
+    if rc:
+        raise RunnerError("Failed to run test")
+
+    signal.signal(signal.SIGALRM, sigalrm_handler)
+
+    lines = []
+    should_exit = False
+    signal.alarm(1)
+    while not should_exit:
+        line = logfile.readline()
+        lines.append(line)
+        if "Test result:" in line:
+            should_exit = True
+    signal.alarm(0)
+
+    logfile.close()
+
+    print "".join(lines)
+
+    test_result = lines[-1]
+    if not "Test result:" in test_result:
+        return "ERROR"
+
+    for res in all_results:
+
+        if res in test_result:
+            return res
+
+    return "ERROR"
+
+
 def run_tests(opts):
     """ Run tests """
 
@@ -477,12 +519,21 @@ def run_tests(opts):
     if not len(tests):
         raise RunnerError("No tests to run")
 
+    if opts.mode == "console":
+        run_test = run_test_console
+    elif opts.mode == "logfile":
+        print "Using logfile mode, please make sure the log \
+files are not rotated!"
+        run_test = run_test_logfile
+    else:
+        raise RunnerError("Unrecognised mode")
+
     rc = all_results.index('SUCCESS')
     results = []
 
     for test in tests:
 
-        res = run_test(test)
+        res = run_test(opts, test)
         res_idx = all_results.index(res)
         if res_idx > rc:
             rc = res_idx
@@ -519,6 +570,17 @@ def main():
                   "  all tests in the selection, printing a summary of their\n"
                   "  results at the end.\n"
                   "\n"
+                  "  To determine how runner should get output from Xen, use\n"
+                  "  --mode option. The default value is \"console\", which\n"
+                  "  means using xenconsole program to extract output.\n"
+                  "  The other supported value is \"logfile\", which\n"
+                  "  means to get output from log file.\n"
+                  "\n"
+                  "  The \"logfile\" mode requires users to configure\n"
+                  "  xenconsoled to log guest console output. This mode\n"
+                  "  is useful for Xen version < 4.8. Also see --logfile-dir\n"
+                  "  and --logfile-pattern options.\n"
+                  "\n"
                   "Selections:\n"
                   "  A selection is zero or more of any of the following\n"
                   "  parameters: Categories, Environments and Tests.\n"
@@ -596,6 +658,19 @@ def main():
                       dest = "host", help = "Restrict selection to applicable"
                       " tests for the current host",
                       )
+    parser.add_option("-m", "--mode", action = "store",
+                      dest = "mode", default = "console", type = "string",
+                      help = "Instruct how runner gets its output (see below)")
+    parser.add_option("--logfile-dir", action = "store",
+                      dest = "logfile_dir", default = "/var/log/xen/console/",
+                      type = "string",
+                      help = 'Specify the directory to look for console logs, \
+defaults to "/var/log/xen/console/"')
+    parser.add_option("--logfile-pattern", action = "store",
+                      dest = "logfile_pattern", default = "guest-%s.log",
+                      type = "string",
+                      help = 'Specify the log file name pattern, \
+defaults to "guest-%s.log"')
 
     opts, args = parser.parse_args()
     opts.args = args
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.