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>
This commit is contained in:
Mariano Lopez
2015-09-01 07:36:29 +00:00
committed by Richard Purdie
parent 170b89d986
commit 53ab41a5f6
4 changed files with 35 additions and 27 deletions

View File

@@ -123,14 +123,14 @@ class oeRuntimeTest(oeTest):
# If a test fails or there is an exception
if not exc_info() == (None, None, None):
exc_clear()
self.tc.host_dumper.create_dir(self._testMethodName)
self.tc.host_dumper.dump_host()
#Only QemuTarget has a serial console
#Only dump for QemuTarget
if (isinstance(self.target, QemuTarget)):
self.tc.host_dumper.create_dir(self._testMethodName)
self.tc.host_dumper.dump_host()
self.target.target_dumper.dump_target(
self.tc.host_dumper.dump_dir)
print ("%s dump data stored in %s" % (self._testMethodName,
self.tc.host_dumper.dump_dir))
print ("%s dump data stored in %s" % (self._testMethodName,
self.tc.host_dumper.dump_dir))
#TODO: use package_manager.py to install packages on any type of image
def install_packages(self, packagelist):

View File

@@ -124,6 +124,9 @@ class QemuTarget(BaseTarget):
self.origrootfs = os.path.join(d.getVar("DEPLOY_DIR_IMAGE", True), d.getVar("IMAGE_LINK_NAME", True) + '.' + self.image_fstype)
self.rootfs = os.path.join(self.testdir, d.getVar("IMAGE_LINK_NAME", True) + '-testimage.' + self.image_fstype)
self.kernel = os.path.join(d.getVar("DEPLOY_DIR_IMAGE", True), d.getVar("KERNEL_IMAGETYPE", False) + '-' + d.getVar('MACHINE', False) + '.bin')
dump_target_cmds = d.getVar("testimage_dump_target", True)
dump_host_cmds = d.getVar("testimage_dump_host", True)
dump_dir = d.getVar("TESTIMAGE_DUMP_DIR", True)
# Log QemuRunner log output to a file
import oe.path
@@ -151,9 +154,11 @@ class QemuTarget(BaseTarget):
deploy_dir_image = d.getVar("DEPLOY_DIR_IMAGE", True),
display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY", True),
logfile = self.qemulog,
boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT", True)))
boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT", True)),
dump_dir = dump_dir,
dump_host_cmds = d.getVar("testimage_dump_host", True))
self.target_dumper = TargetDumper(d, self.runner)
self.target_dumper = TargetDumper(dump_target_cmds, dump_dir, self.runner)
def deploy(self):
try:

View File

@@ -6,30 +6,22 @@ import itertools
from commands import runCmd
def get_host_dumper(d):
return HostDumper(d)
cmds = d.getVar("testimage_dump_host", True)
parent_dir = d.getVar("TESTIMAGE_DUMP_DIR", True)
return HostDumper(cmds, parent_dir)
class BaseDumper(object):
def __init__(self, d, cmds):
def __init__(self, cmds, parent_dir):
self.cmds = []
self.parent_dir = d.getVar("TESTIMAGE_DUMP_DIR", True)
self.parent_dir = parent_dir
if not cmds:
return
for cmd in cmds.split('\n'):
cmd = cmd.lstrip()
if not cmd or cmd[0] == '#':
continue
# Replae variables from the datastore
while True:
index_start = cmd.find("${")
if index_start == -1:
break
index_start += 2
index_end = cmd.find("}", index_start)
var = cmd[index_start:index_end]
value = d.getVar(var, True)
cmd = cmd.replace("${%s}" % var, value)
self.cmds.append(cmd)
def create_dir(self, dir_suffix):
@@ -62,9 +54,8 @@ class BaseDumper(object):
class HostDumper(BaseDumper):
def __init__(self, d):
host_cmds = d.getVar("testimage_dump_host", True)
super(HostDumper, self).__init__(d, host_cmds)
def __init__(self, cmds, parent_dir):
super(HostDumper, self).__init__(cmds, parent_dir)
def dump_host(self, dump_dir=""):
if dump_dir:
@@ -76,9 +67,8 @@ class HostDumper(BaseDumper):
class TargetDumper(BaseDumper):
def __init__(self, d, qemurunner):
target_cmds = d.getVar("testimage_dump_target", True)
super(TargetDumper, self).__init__(d, target_cmds)
def __init__(self, cmds, parent_dir, qemurunner):
super(TargetDumper, self).__init__(cmds, parent_dir)
self.runner = qemurunner
def dump_target(self, dump_dir=""):

View File

@@ -14,13 +14,14 @@ import socket
import select
import errno
import threading
from oeqa.utils.dump import HostDumper
import logging
logger = logging.getLogger("BitBake.QemuRunner")
class QemuRunner:
def __init__(self, machine, rootfs, display, tmpdir, deploy_dir_image, logfile, boottime):
def __init__(self, machine, rootfs, display, tmpdir, deploy_dir_image, logfile, boottime, dump_dir, dump_host_cmds):
# Popen object for runqemu
self.runqemu = None
@@ -42,6 +43,7 @@ class QemuRunner:
self.thread = None
self.runqemutime = 60
self.host_dumper = HostDumper(dump_host_cmds, dump_dir)
def create_socket(self):
try:
@@ -118,6 +120,7 @@ class QemuRunner:
if self.runqemu.returncode:
# No point waiting any longer
logger.info('runqemu exited with code %d' % self.runqemu.returncode)
self._dump_host()
self.stop()
logger.info("Output from runqemu:\n%s" % getOutput(output))
return False
@@ -137,6 +140,7 @@ class QemuRunner:
self.server_ip = ips[1]
except IndexError, ValueError:
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)))
self._dump_host()
self.stop()
return False
logger.info("qemu cmdline used:\n{}".format(cmdline))
@@ -189,6 +193,7 @@ class QemuRunner:
lines = "\n".join(bootlog.splitlines()[-25:])
logger.info("Last 25 lines of text:\n%s" % lines)
logger.info("Check full boot log: %s" % self.logfile)
self._dump_host()
self.stop()
return False
@@ -202,6 +207,7 @@ class QemuRunner:
else:
logger.info("Qemu pid didn't appeared in %s seconds" % self.runqemutime)
self._dump_host()
self.stop()
logger.info("Output from runqemu:\n%s" % getOutput(output))
return False
@@ -334,6 +340,13 @@ class QemuRunner:
status = 1
return (status, str(data))
def _dump_host(self):
self.host_dumper.create_dir("qemu")
logger.error("Qemu ended unexpectedly, dump data from host"
" is in %s" % self.host_dumper.dump_dir)
self.host_dumper.dump_host()
# This class is for reading data from a socket and passing it to logfunc
# to be processed. It's completely event driven and has a straightforward
# event loop. The mechanism for stopping the thread is a simple pipe which