summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMariano Lopez <mariano.lopez@linux.intel.com>2015-09-01 07:36:29 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-09-03 12:43:16 +0100
commit53ab41a5f6d20e911362a9261ae528452bb71bbd (patch)
tree0962c78c4f378c3de0fc25810778a49f0a35d168
parent170b89d9863a1b8560f397d3bb7a1eafd7c61e1e (diff)
downloadpoky-53ab41a5f6d20e911362a9261ae528452bb71bbd.tar.gz
qemurunner: Added host dumps when there are errors
This adds an instance of HostDumper to qemurunner, with this instance now is possible to get dumps from the host when there is an error. This adds dump points in the next cases: - runqemu exits before seeing qemu pid - Fail to get qemu process arguments - Not reach login banner before timeout - qemu pid never appears This also modifies the constructors of BaseDumper, HostDumper and TargetDumper, they don't require the datastore anymore, but the feature to replace datastore variables has been lost (never used) [YOCTO #8118] (From OE-Core rev: b0af40fb76cd5035696e9d8a44f815f64214d23a) Signed-off-by: Mariano Lopez <mariano.lopez@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/lib/oeqa/oetest.py10
-rw-r--r--meta/lib/oeqa/targetcontrol.py9
-rw-r--r--meta/lib/oeqa/utils/dump.py28
-rw-r--r--meta/lib/oeqa/utils/qemurunner.py15
4 files changed, 35 insertions, 27 deletions
diff --git a/meta/lib/oeqa/oetest.py b/meta/lib/oeqa/oetest.py
index f54113626b..4224206546 100644
--- a/meta/lib/oeqa/oetest.py
+++ b/meta/lib/oeqa/oetest.py
@@ -123,14 +123,14 @@ class oeRuntimeTest(oeTest):
123 # If a test fails or there is an exception 123 # If a test fails or there is an exception
124 if not exc_info() == (None, None, None): 124 if not exc_info() == (None, None, None):
125 exc_clear() 125 exc_clear()
126 self.tc.host_dumper.create_dir(self._testMethodName) 126 #Only dump for QemuTarget
127 self.tc.host_dumper.dump_host()
128 #Only QemuTarget has a serial console
129 if (isinstance(self.target, QemuTarget)): 127 if (isinstance(self.target, QemuTarget)):
128 self.tc.host_dumper.create_dir(self._testMethodName)
129 self.tc.host_dumper.dump_host()
130 self.target.target_dumper.dump_target( 130 self.target.target_dumper.dump_target(
131 self.tc.host_dumper.dump_dir) 131 self.tc.host_dumper.dump_dir)
132 print ("%s dump data stored in %s" % (self._testMethodName, 132 print ("%s dump data stored in %s" % (self._testMethodName,
133 self.tc.host_dumper.dump_dir)) 133 self.tc.host_dumper.dump_dir))
134 134
135 #TODO: use package_manager.py to install packages on any type of image 135 #TODO: use package_manager.py to install packages on any type of image
136 def install_packages(self, packagelist): 136 def install_packages(self, packagelist):
diff --git a/meta/lib/oeqa/targetcontrol.py b/meta/lib/oeqa/targetcontrol.py
index 2d58f17ddb..542e259112 100644
--- a/meta/lib/oeqa/targetcontrol.py
+++ b/meta/lib/oeqa/targetcontrol.py
@@ -124,6 +124,9 @@ class QemuTarget(BaseTarget):
124 self.origrootfs = os.path.join(d.getVar("DEPLOY_DIR_IMAGE", True), d.getVar("IMAGE_LINK_NAME", True) + '.' + self.image_fstype) 124 self.origrootfs = os.path.join(d.getVar("DEPLOY_DIR_IMAGE", True), d.getVar("IMAGE_LINK_NAME", True) + '.' + self.image_fstype)
125 self.rootfs = os.path.join(self.testdir, d.getVar("IMAGE_LINK_NAME", True) + '-testimage.' + self.image_fstype) 125 self.rootfs = os.path.join(self.testdir, d.getVar("IMAGE_LINK_NAME", True) + '-testimage.' + self.image_fstype)
126 self.kernel = os.path.join(d.getVar("DEPLOY_DIR_IMAGE", True), d.getVar("KERNEL_IMAGETYPE", False) + '-' + d.getVar('MACHINE', False) + '.bin') 126 self.kernel = os.path.join(d.getVar("DEPLOY_DIR_IMAGE", True), d.getVar("KERNEL_IMAGETYPE", False) + '-' + d.getVar('MACHINE', False) + '.bin')
127 dump_target_cmds = d.getVar("testimage_dump_target", True)
128 dump_host_cmds = d.getVar("testimage_dump_host", True)
129 dump_dir = d.getVar("TESTIMAGE_DUMP_DIR", True)
127 130
128 # Log QemuRunner log output to a file 131 # Log QemuRunner log output to a file
129 import oe.path 132 import oe.path
@@ -151,9 +154,11 @@ class QemuTarget(BaseTarget):
151 deploy_dir_image = d.getVar("DEPLOY_DIR_IMAGE", True), 154 deploy_dir_image = d.getVar("DEPLOY_DIR_IMAGE", True),
152 display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY", True), 155 display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY", True),
153 logfile = self.qemulog, 156 logfile = self.qemulog,
154 boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT", True))) 157 boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT", True)),
158 dump_dir = dump_dir,
159 dump_host_cmds = d.getVar("testimage_dump_host", True))
155 160
156 self.target_dumper = TargetDumper(d, self.runner) 161 self.target_dumper = TargetDumper(dump_target_cmds, dump_dir, self.runner)
157 162
158 def deploy(self): 163 def deploy(self):
159 try: 164 try:
diff --git a/meta/lib/oeqa/utils/dump.py b/meta/lib/oeqa/utils/dump.py
index e71e1cd341..6067438e35 100644
--- a/meta/lib/oeqa/utils/dump.py
+++ b/meta/lib/oeqa/utils/dump.py
@@ -6,30 +6,22 @@ import itertools
6from commands import runCmd 6from commands import runCmd
7 7
8def get_host_dumper(d): 8def get_host_dumper(d):
9 return HostDumper(d) 9 cmds = d.getVar("testimage_dump_host", True)
10 parent_dir = d.getVar("TESTIMAGE_DUMP_DIR", True)
11 return HostDumper(cmds, parent_dir)
10 12
11 13
12class BaseDumper(object): 14class BaseDumper(object):
13 15
14 def __init__(self, d, cmds): 16 def __init__(self, cmds, parent_dir):
15 self.cmds = [] 17 self.cmds = []
16 self.parent_dir = d.getVar("TESTIMAGE_DUMP_DIR", True) 18 self.parent_dir = parent_dir
17 if not cmds: 19 if not cmds:
18 return 20 return
19 for cmd in cmds.split('\n'): 21 for cmd in cmds.split('\n'):
20 cmd = cmd.lstrip() 22 cmd = cmd.lstrip()
21 if not cmd or cmd[0] == '#': 23 if not cmd or cmd[0] == '#':
22 continue 24 continue
23 # Replae variables from the datastore
24 while True:
25 index_start = cmd.find("${")
26 if index_start == -1:
27 break
28 index_start += 2
29 index_end = cmd.find("}", index_start)
30 var = cmd[index_start:index_end]
31 value = d.getVar(var, True)
32 cmd = cmd.replace("${%s}" % var, value)
33 self.cmds.append(cmd) 25 self.cmds.append(cmd)
34 26
35 def create_dir(self, dir_suffix): 27 def create_dir(self, dir_suffix):
@@ -62,9 +54,8 @@ class BaseDumper(object):
62 54
63class HostDumper(BaseDumper): 55class HostDumper(BaseDumper):
64 56
65 def __init__(self, d): 57 def __init__(self, cmds, parent_dir):
66 host_cmds = d.getVar("testimage_dump_host", True) 58 super(HostDumper, self).__init__(cmds, parent_dir)
67 super(HostDumper, self).__init__(d, host_cmds)
68 59
69 def dump_host(self, dump_dir=""): 60 def dump_host(self, dump_dir=""):
70 if dump_dir: 61 if dump_dir:
@@ -76,9 +67,8 @@ class HostDumper(BaseDumper):
76 67
77class TargetDumper(BaseDumper): 68class TargetDumper(BaseDumper):
78 69
79 def __init__(self, d, qemurunner): 70 def __init__(self, cmds, parent_dir, qemurunner):
80 target_cmds = d.getVar("testimage_dump_target", True) 71 super(TargetDumper, self).__init__(cmds, parent_dir)
81 super(TargetDumper, self).__init__(d, target_cmds)
82 self.runner = qemurunner 72 self.runner = qemurunner
83 73
84 def dump_target(self, dump_dir=""): 74 def dump_target(self, dump_dir=""):
diff --git a/meta/lib/oeqa/utils/qemurunner.py b/meta/lib/oeqa/utils/qemurunner.py
index bcdb69b38c..4ce5d9c685 100644
--- a/meta/lib/oeqa/utils/qemurunner.py
+++ b/meta/lib/oeqa/utils/qemurunner.py
@@ -14,13 +14,14 @@ import socket
14import select 14import select
15import errno 15import errno
16import threading 16import threading
17from oeqa.utils.dump import HostDumper
17 18
18import logging 19import logging
19logger = logging.getLogger("BitBake.QemuRunner") 20logger = logging.getLogger("BitBake.QemuRunner")
20 21
21class QemuRunner: 22class QemuRunner:
22 23
23 def __init__(self, machine, rootfs, display, tmpdir, deploy_dir_image, logfile, boottime): 24 def __init__(self, machine, rootfs, display, tmpdir, deploy_dir_image, logfile, boottime, dump_dir, dump_host_cmds):
24 25
25 # Popen object for runqemu 26 # Popen object for runqemu
26 self.runqemu = None 27 self.runqemu = None
@@ -42,6 +43,7 @@ class QemuRunner:
42 self.thread = None 43 self.thread = None
43 44
44 self.runqemutime = 60 45 self.runqemutime = 60
46 self.host_dumper = HostDumper(dump_host_cmds, dump_dir)
45 47
46 def create_socket(self): 48 def create_socket(self):
47 try: 49 try:
@@ -118,6 +120,7 @@ class QemuRunner:
118 if self.runqemu.returncode: 120 if self.runqemu.returncode:
119 # No point waiting any longer 121 # No point waiting any longer
120 logger.info('runqemu exited with code %d' % self.runqemu.returncode) 122 logger.info('runqemu exited with code %d' % self.runqemu.returncode)
123 self._dump_host()
121 self.stop() 124 self.stop()
122 logger.info("Output from runqemu:\n%s" % getOutput(output)) 125 logger.info("Output from runqemu:\n%s" % getOutput(output))
123 return False 126 return False
@@ -137,6 +140,7 @@ class QemuRunner:
137 self.server_ip = ips[1] 140 self.server_ip = ips[1]
138 except IndexError, ValueError: 141 except IndexError, ValueError:
139 logger.info("Couldn't get ip from qemu process arguments! Here is the qemu command line used:\n%s\nand output from runqemu:\n%s" % (cmdline, getOutput(output))) 142 logger.info("Couldn't get ip from qemu process arguments! Here is the qemu command line used:\n%s\nand output from runqemu:\n%s" % (cmdline, getOutput(output)))
143 self._dump_host()
140 self.stop() 144 self.stop()
141 return False 145 return False
142 logger.info("qemu cmdline used:\n{}".format(cmdline)) 146 logger.info("qemu cmdline used:\n{}".format(cmdline))
@@ -189,6 +193,7 @@ class QemuRunner:
189 lines = "\n".join(bootlog.splitlines()[-25:]) 193 lines = "\n".join(bootlog.splitlines()[-25:])
190 logger.info("Last 25 lines of text:\n%s" % lines) 194 logger.info("Last 25 lines of text:\n%s" % lines)
191 logger.info("Check full boot log: %s" % self.logfile) 195 logger.info("Check full boot log: %s" % self.logfile)
196 self._dump_host()
192 self.stop() 197 self.stop()
193 return False 198 return False
194 199
@@ -202,6 +207,7 @@ class QemuRunner:
202 207
203 else: 208 else:
204 logger.info("Qemu pid didn't appeared in %s seconds" % self.runqemutime) 209 logger.info("Qemu pid didn't appeared in %s seconds" % self.runqemutime)
210 self._dump_host()
205 self.stop() 211 self.stop()
206 logger.info("Output from runqemu:\n%s" % getOutput(output)) 212 logger.info("Output from runqemu:\n%s" % getOutput(output))
207 return False 213 return False
@@ -334,6 +340,13 @@ class QemuRunner:
334 status = 1 340 status = 1
335 return (status, str(data)) 341 return (status, str(data))
336 342
343
344 def _dump_host(self):
345 self.host_dumper.create_dir("qemu")
346 logger.error("Qemu ended unexpectedly, dump data from host"
347 " is in %s" % self.host_dumper.dump_dir)
348 self.host_dumper.dump_host()
349
337# This class is for reading data from a socket and passing it to logfunc 350# This class is for reading data from a socket and passing it to logfunc
338# to be processed. It's completely event driven and has a straightforward 351# to be processed. It's completely event driven and has a straightforward
339# event loop. The mechanism for stopping the thread is a simple pipe which 352# event loop. The mechanism for stopping the thread is a simple pipe which