diff options
author | Mariano Lopez <mariano.lopez@linux.intel.com> | 2015-09-01 07:36:29 +0000 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2015-09-03 12:43:16 +0100 |
commit | 53ab41a5f6d20e911362a9261ae528452bb71bbd (patch) | |
tree | 0962c78c4f378c3de0fc25810778a49f0a35d168 | |
parent | 170b89d9863a1b8560f397d3bb7a1eafd7c61e1e (diff) | |
download | poky-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.py | 10 | ||||
-rw-r--r-- | meta/lib/oeqa/targetcontrol.py | 9 | ||||
-rw-r--r-- | meta/lib/oeqa/utils/dump.py | 28 | ||||
-rw-r--r-- | meta/lib/oeqa/utils/qemurunner.py | 15 |
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 | |||
6 | from commands import runCmd | 6 | from commands import runCmd |
7 | 7 | ||
8 | def get_host_dumper(d): | 8 | def 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 | ||
12 | class BaseDumper(object): | 14 | class 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 | ||
63 | class HostDumper(BaseDumper): | 55 | class 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 | ||
77 | class TargetDumper(BaseDumper): | 68 | class 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 | |||
14 | import select | 14 | import select |
15 | import errno | 15 | import errno |
16 | import threading | 16 | import threading |
17 | from oeqa.utils.dump import HostDumper | ||
17 | 18 | ||
18 | import logging | 19 | import logging |
19 | logger = logging.getLogger("BitBake.QemuRunner") | 20 | logger = logging.getLogger("BitBake.QemuRunner") |
20 | 21 | ||
21 | class QemuRunner: | 22 | class 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 |