Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
scripts/qemu.py: Add arch parameter and automatic arch guessing
The binary parameter is mandatory, and central to QEMUMachine usage.
Some information, such as the intended architecture, can either be
given explicitly, or can be extracted from the binary itself.

This change provides a generic function, qmp_execute(), that executes
a QEMU binary with the sole purpose of retrieving information from
a binary.  This function is then applied to query the target name
from the given binary and use it as the architecture on QEMUMachine.

Given that many tests depend on the current behavior, and for the sake
of clarity, the automatic setting of the archicture is not done by
default, it requires the "automatic_devices=True" to be given as a
parameter to QEMUMachine.

Signed-off-by: Cleber Rosa <crosa@redhat.com>
  • Loading branch information
clebergnu committed May 14, 2018
1 parent ad2906e commit b769b3d
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 1 deletion.
61 changes: 60 additions & 1 deletion scripts/qemu.py
Expand Up @@ -43,6 +43,54 @@ def __init__(self, reply):
self.reply = reply


def qmp_execute(binary_path, qmp_command):
"""
Executes a QMP command on a given QEMU binary
Useful for one-off execution of QEMU binaries to get runtime
information.
@param binary_path: path to a QEMU binary
@param qmp_command: the QMP command
@note: passing arguments to the QMP command is not supported at
this time.
"""
try:
tempdir = tempfile.mkdtemp()
monitor_socket = os.path.join(tempdir, 'monitor.sock')
args = [binary_path, '-nodefaults', '-machine', 'none',
'-nographic', '-S', '-qmp', 'unix:%s' % monitor_socket]
monitor = qmp.qmp.QEMUMonitorProtocol(monitor_socket, True)
try:
qemu_proc = subprocess.Popen(args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=None,
universal_newlines=True)
except OSError:
return None
monitor.accept()
res = monitor.cmd(qmp_command)
monitor.cmd("quit")
qemu_proc.wait()
monitor.close()
return res.get("return", None)
finally:
shutil.rmtree(tempdir)


def qemu_bin_arch(binary_path):
"""
Probes the architecture from the QEMU binary
@returns: either the probed arch or None
@rtype: str or None
"""
res = qmp_execute(binary_path, "query-target")
if res is not None:
return res.get("arch", None)


class QEMUMachine(object):
'''A QEMU VM
Expand All @@ -55,7 +103,7 @@ class QEMUMachine(object):

def __init__(self, binary, args=None, wrapper=None, name=None,
test_dir="/var/tmp", monitor_address=None,
socket_scm_helper=None):
socket_scm_helper=None, arch=None, automatic_devices=False):
'''
Initialize a QEMUMachine
Expand All @@ -66,6 +114,14 @@ def __init__(self, binary, args=None, wrapper=None, name=None,
@param test_dir: where to create socket and log file
@param monitor_address: address for QMP monitor
@param socket_scm_helper: helper program, required for send_fd_scm()"
@param arch: the intended architecture, which can influence the
behavior of methods that add architecture specific
options. If not set, and automatic_devices options is
True, it will be guessed from the queried from the qemu
binary itself.
@param automatic_devices: wether to automatically set some attributes
and command line arguments based on
environment and probes.
@note: Qemu process is not started until launch() is used.
'''
if args is None:
Expand All @@ -91,6 +147,9 @@ def __init__(self, binary, args=None, wrapper=None, name=None,
self._test_dir = test_dir
self._temp_dir = None
self._launched = False
if arch is None and automatic_devices:
arch = qemu_bin_arch(binary)
self._arch = arch

# just in case logging wasn't configured by the main script:
logging.basicConfig()
Expand Down
38 changes: 38 additions & 0 deletions scripts/test_qemu.py
@@ -0,0 +1,38 @@
import sys
import os
import glob
import unittest

from qemu import qemu_bin_arch


def get_built_qemu_binaries(src_root=None):
if src_root is None:
src_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
binaries = glob.glob(os.path.join(src_root, '*-softmmu/qemu-system-*'))
if 'win' in sys.platform:
bin_filter = lambda x: x.endswith(".exe")
else:
bin_filter = lambda x: not x.endswith(".exe")
return [_ for _ in binaries if bin_filter(_)]


class QEMU(unittest.TestCase):

@unittest.skipUnless(get_built_qemu_binaries(),
"Could not find any QEMU binaries built to use on "
"arch check")
def test_qemu_bin_arch(self):
"""
Checks that the qemu_bin_arch returns the expected architecture name
To avoid duplication of information, we assume the archicture matches
the last part of the binary name.
"""
for binary in get_built_qemu_binaries():
self.assertEqual(qemu_bin_arch(binary),
binary.split('-')[-1].split(".exe")[0])


if __name__ == '__main__':
unittest.main()

0 comments on commit b769b3d

Please sign in to comment.