mirror of
https://git.yoctoproject.org/poky
synced 2026-02-07 09:16:36 +01:00
This adds support for the Qemu Machine Protocol [0] extending the current dump process for Host and Target. The commands are added in the testimage.bbclass. Currently, we setup qemu to stall until qmp gets connected and sends the initialization and continue commands, this works correctly. If the UNIX Socket does not exist, we wait an timeout to ensure to socket file is created. With this version, the monitor_dumper is created in OEQemuTarget but then set in OESSHTarget as that's where we get the SSH failure happens. Python's @property is used to create a setter/getter type of setup in OESSHTarget to get overridden by OEQemuTarget. By default the data is currently dumped to files for each command in TMPDIR/log/runtime-hostdump/<date>_qmp/unknown_<seq>_qemu_monitor as this is the naming convenstion in the dump.py code. We use the qmp.py from qemu, which needs to get installed in the recipe-sysroot-native of the target image. [0] https://github.com/qemu/qemu/blob/master/docs/interop/qmp-spec.txt (From OE-Core rev: 42af4cd2df72fc8ed9deb3fde4312909842fcf91) Signed-off-by: Saul Wold <saul.wold@windriver.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
125 lines
4.0 KiB
Python
125 lines
4.0 KiB
Python
#
|
|
# SPDX-License-Identifier: MIT
|
|
#
|
|
|
|
import os
|
|
import sys
|
|
import json
|
|
import errno
|
|
import datetime
|
|
import itertools
|
|
from .commands import runCmd
|
|
|
|
class BaseDumper(object):
|
|
""" Base class to dump commands from host/target """
|
|
|
|
def __init__(self, cmds, parent_dir):
|
|
self.cmds = []
|
|
# Some testing doesn't inherit testimage, so it is needed
|
|
# to set some defaults.
|
|
self.parent_dir = parent_dir
|
|
dft_cmds = """ top -bn1
|
|
iostat -x -z -N -d -p ALL 20 2
|
|
ps -ef
|
|
free
|
|
df
|
|
memstat
|
|
dmesg
|
|
ip -s link
|
|
netstat -an"""
|
|
if not cmds:
|
|
cmds = dft_cmds
|
|
for cmd in cmds.split('\n'):
|
|
cmd = cmd.lstrip()
|
|
if not cmd or cmd[0] == '#':
|
|
continue
|
|
self.cmds.append(cmd)
|
|
|
|
def create_dir(self, dir_suffix):
|
|
dump_subdir = ("%s_%s" % (
|
|
datetime.datetime.now().strftime('%Y%m%d%H%M'),
|
|
dir_suffix))
|
|
dump_dir = os.path.join(self.parent_dir, dump_subdir)
|
|
try:
|
|
os.makedirs(dump_dir)
|
|
except OSError as err:
|
|
if err.errno != errno.EEXIST:
|
|
raise err
|
|
self.dump_dir = dump_dir
|
|
|
|
def _write_dump(self, command, output):
|
|
if isinstance(self, HostDumper):
|
|
prefix = "host"
|
|
elif isinstance(self, TargetDumper):
|
|
prefix = "target"
|
|
elif isinstance(self, MonitorDumper):
|
|
prefix = "qmp"
|
|
else:
|
|
prefix = "unknown"
|
|
for i in itertools.count():
|
|
filename = "%s_%02d_%s" % (prefix, i, command)
|
|
fullname = os.path.join(self.dump_dir, filename)
|
|
if not os.path.exists(fullname):
|
|
break
|
|
if isinstance(self, MonitorDumper):
|
|
with open(fullname, 'w') as json_file:
|
|
json.dump(output, json_file, indent=4)
|
|
else:
|
|
with open(fullname, 'w') as dump_file:
|
|
dump_file.write(output)
|
|
|
|
class HostDumper(BaseDumper):
|
|
""" Class to get dumps from the host running the tests """
|
|
|
|
def __init__(self, cmds, parent_dir):
|
|
super(HostDumper, self).__init__(cmds, parent_dir)
|
|
|
|
def dump_host(self, dump_dir=""):
|
|
if dump_dir:
|
|
self.dump_dir = dump_dir
|
|
env = os.environ.copy()
|
|
env['PATH'] = '/usr/sbin:/sbin:/usr/bin:/bin'
|
|
env['COLUMNS'] = '9999'
|
|
for cmd in self.cmds:
|
|
result = runCmd(cmd, ignore_status=True, env=env)
|
|
self._write_dump(cmd.split()[0], result.output)
|
|
|
|
class TargetDumper(BaseDumper):
|
|
""" Class to get dumps from target, it only works with QemuRunner """
|
|
|
|
def __init__(self, cmds, parent_dir, runner):
|
|
super(TargetDumper, self).__init__(cmds, parent_dir)
|
|
self.runner = runner
|
|
|
|
def dump_target(self, dump_dir=""):
|
|
if dump_dir:
|
|
self.dump_dir = dump_dir
|
|
for cmd in self.cmds:
|
|
# We can continue with the testing if serial commands fail
|
|
try:
|
|
(status, output) = self.runner.run_serial(cmd)
|
|
self._write_dump(cmd.split()[0], output)
|
|
except:
|
|
print("Tried to dump info from target but "
|
|
"serial console failed")
|
|
print("Failed CMD: %s" % (cmd))
|
|
|
|
class MonitorDumper(BaseDumper):
|
|
""" Class to get dumps via the Qemu Monitor, it only works with QemuRunner """
|
|
|
|
def __init__(self, cmds, parent_dir, runner):
|
|
super(MonitorDumper, self).__init__(cmds, parent_dir)
|
|
self.runner = runner
|
|
|
|
def dump_monitor(self, dump_dir=""):
|
|
if self.runner is None:
|
|
return
|
|
if dump_dir:
|
|
self.dump_dir = dump_dir
|
|
for cmd in self.cmds:
|
|
try:
|
|
output = self.runner.run_monitor(cmd)
|
|
self._write_dump(cmd, output)
|
|
except:
|
|
print("Failed to dump QMP CMD: %s" % (cmd))
|