From: Eduardo Habkost <ehabkost@redhat.com>
To: qemu-devel@nongnu.org, Markus Armbruster <armbru@redhat.com>,
Marcel Apfelbaum <marcel@redhat.com>,
"Michael S. Tsirkin" <mst@redhat.com>
Cc: libvir-list@redhat.com, Laine Stump <laine@redhat.com>
Subject: [Qemu-devel] [RFC 08/15] qmp: Add 'supported-device-types' field to 'query-machines'
Date: Mon, 21 Nov 2016 23:12:06 -0200 [thread overview]
Message-ID: <1479777133-23567-9-git-send-email-ehabkost@redhat.com> (raw)
In-Reply-To: <1479777133-23567-1-git-send-email-ehabkost@redhat.com>
The new field will return a list of device type names that are
compatible with the default bus configuration of the
machine-type. The list can be easily built using the
MachineClass::default_bus_types and
BusClass::supported_device_type fields.
The returned types can be used as the 'implements' parameter to
'qom-list-types', to find the list of devices that can be plugged
on the machine.
Note that some machine options may enable or disable some bus
types and affect the set of compatible device types.
Introspection of those options is out of the scope of this patch.
Includes a qtest test case that will validate the returned by
actually running each machine-type and checking the list of
available buses.
Cc: libvir-list@redhat.com
Cc: Laine Stump <laine@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
qapi-schema.json | 9 ++-
tests/Makefile.include | 2 +
tests/qmp-machine-info.py | 138 ++++++++++++++++++++++++++++++++++++++++++++++
vl.c | 11 ++++
4 files changed, 159 insertions(+), 1 deletion(-)
create mode 100755 tests/qmp-machine-info.py
diff --git a/qapi-schema.json b/qapi-schema.json
index f3e9bfc..6db397d 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3178,12 +3178,19 @@
#
# @hotpluggable-cpus: cpu hotplug via -device is supported (since 2.7.0)
#
+# @supported-device-types: List of QOM type names of devices that
+# can be plugged on the machine by default.
+# Note that some machine options may enable
+# or disable some bus types and affect the
+# set of compatible device types. (since 2.9)
+#
# Since: 1.2.0
##
{ 'struct': 'MachineInfo',
'data': { 'name': 'str', '*alias': 'str',
'*is-default': 'bool', 'cpu-max': 'int',
- 'hotpluggable-cpus': 'bool'} }
+ 'hotpluggable-cpus': 'bool',
+ 'supported-device-types': [ 'str' ] } }
##
# @query-machines:
diff --git a/tests/Makefile.include b/tests/Makefile.include
index eb1031b..7016737 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -315,6 +315,8 @@ check-qtest-s390x-y = tests/boot-serial-test$(EXESUF)
check-qtest-generic-y += tests/qom-test$(EXESUF)
+check-simpleqtest-generic-y += $(SRC_PATH)/tests/qmp-machine-info.py
+
qapi-schema += alternate-any.json
qapi-schema += alternate-array.json
qapi-schema += alternate-base.json
diff --git a/tests/qmp-machine-info.py b/tests/qmp-machine-info.py
new file mode 100755
index 0000000..5258434
--- /dev/null
+++ b/tests/qmp-machine-info.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+import sys, os
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'scripts'))
+import qtest
+import unittest
+import logging
+import argparse
+
+logger = logging.getLogger('qemu.tests.machineinfo')
+
+# machines that we can't easily test because they can't run on all hosts:
+BLACKLIST = set(['xenpv', 'xenfv'])
+
+# architectures where machines are expected to report all available buses:
+STRICT_ARCHES = set()
+
+class QueryMachinesTest(unittest.TestCase):
+ def walkQOMTree(self, vm, path):
+ """Walk QOM tree recusrively, starting at path"""
+ children = vm.qmp('qom-list', path=path)['return']
+ for c in children:
+ logging.debug('walking %s. child: %s', path, c)
+ if not c['type'].startswith('child<'):
+ continue
+
+ cp = '%s/%s' % (path, c['name'])
+ yield cp
+
+ for gc in self.walkQOMTree(vm, cp):
+ yield gc
+
+ def findAllBuses(self, vm):
+ """Find all bus objects in the QOM tree"""
+ r = vm.qmp('qom-list-types', implements='bus')
+ bus_types = set([b['name'] for b in r['return']])
+ for cp in self.walkQOMTree(vm, '/machine'):
+ t = vm.qmp('qom-get', path=cp, property='type')['return']
+ if t in bus_types:
+ dt = vm.qmp('qom-get', path=cp, property='device-type')['return']
+ yield dict(path=cp, type=t, device_type=dt)
+
+ def validateSupportedDeviceTypes(self, machine):
+ """Validate 'supported-device-types' on 'query-machines'"""
+ if machine['name'] in BLACKLIST:
+ return
+
+ vm = qtest.QEMUQtestMachine(args=['-S', '-machine', machine['name']], logging=False)
+ vm.launch()
+ try:
+ buses = list(self.findAllBuses(vm))
+ bus_types = set([b['type'] for b in buses])
+ device_types = set([b['device_type'] for b in buses])
+ logger.debug("buses for machine %s: %s", machine['name'],
+ ' '.join(bus_types))
+ logger.debug("device-type for machine %s: %s", machine['name'],
+ ' '.join(device_types))
+ reported_types = set(machine['supported-device-types'])
+ extra_types = reported_types.difference(device_types)
+ missing_types = device_types.difference(reported_types)
+ # the machine MUST NOT report any types if the bus is not available
+ # by default (in other words, extra_types should be empty)
+ self.assertEquals(extra_types, set())
+ # missing_types, on the other hand, may be empty. sometimes
+ # a bus is available but the machine doesn't report it yet
+ if missing_types:
+ logger.info("extra device types present on machine %s: %s",
+ machine['name'], ' '.join(missing_types))
+ if vm.qmp('query-target')['return']['arch'] in STRICT_ARCHES:
+ self.fail("extra device types: %s" % (' '.join(missing_types)))
+ finally:
+ vm.shutdown()
+
+ @classmethod
+ def addMachineTest(klass, method, machine):
+ """Dynamically add a testMachine_<name>_<machine> method to the class"""
+ def testMachine(self):
+ return method(self, machine)
+ machine_name = machine['name'].replace('-', '_').replace('.', '_')
+ method_name = 'testMachine_%s_%s' % (method.__name__, machine_name)
+ setattr(klass, method_name, testMachine)
+
+ @classmethod
+ def discoverMachines(klass):
+ """Run query-machines
+
+ This method is run before test cases are started, so we
+ can dynamically add test cases for each machine supported
+ by the binary.
+ """
+ vm = qtest.QEMUQtestMachine(args=['-S', '-machine', 'none'], logging=False)
+ vm.launch()
+ try:
+ machines = vm.qmp('query-machines')['return']
+ finally:
+ vm.shutdown()
+ return machines
+
+ @classmethod
+ def addMachineTestCases(klass):
+ """Dynamically add test methods for each machine-type"""
+ machines = klass.discoverMachines()
+ for m in machines:
+ klass.addMachineTest(klass.validateSupportedDeviceTypes, m)
+
+def load_tests(loader, tests=None, pattern=None):
+ QueryMachinesTest.addMachineTestCases()
+ ts = unittest.TestSuite()
+ tests = loader.loadTestsFromTestCase(QueryMachinesTest)
+ ts.addTests(tests)
+ return ts
+
+def main(argv):
+ # we don't use unittest.main() because:
+ # 1) it doesn't configure logging level
+ # 2) it doesn't let us disable all output
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--verbosity', help='Set verbosity',
+ default=1, type=int)
+ parser.add_argument('--quiet', '-q', help='Run tests quietly',
+ action='store_const', dest='verbosity', const=0)
+ parser.add_argument('--verbose', '-v', help='Run tests verbosely',
+ action='store_const', dest='verbosity', const=2)
+ parser.add_argument('--debug', '-d', help='Debug output',
+ action='store_const', dest='verbosity', const=4)
+ args = parser.parse_args(argv[1:])
+ if args.verbosity == 0:
+ output = open('/dev/null', 'w')
+ else:
+ output = sys.stderr
+ if args.verbosity >= 4:
+ logging.basicConfig(level=logging.DEBUG)
+ elif args.verbosity >= 2:
+ logging.basicConfig(level=logging.INFO)
+ tests = load_tests(unittest.TestLoader(), None, None)
+ unittest.TextTestRunner(stream=output, verbosity=args.verbosity).run(tests)
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/vl.c b/vl.c
index d77dd86..af862db 100644
--- a/vl.c
+++ b/vl.c
@@ -1541,6 +1541,8 @@ MachineInfoList *qmp_query_machines(Error **errp)
MachineClass *mc = el->data;
MachineInfoList *entry;
MachineInfo *info;
+ GList *bus;
+ strList **next_dev;
info = g_malloc0(sizeof(*info));
if (mc->is_default) {
@@ -1557,6 +1559,15 @@ MachineInfoList *qmp_query_machines(Error **errp)
info->cpu_max = !mc->max_cpus ? 1 : mc->max_cpus;
info->hotpluggable_cpus = !!mc->query_hotpluggable_cpus;
+ next_dev = &info->supported_device_types;
+ for (bus = mc->default_buses; bus; bus = bus->next) {
+ BusClass *bc = BUS_CLASS(object_class_by_name(bus->data));
+ strList *new = g_new0(strList, 1);
+ new->value = g_strdup(bc->device_type);
+ *next_dev = new;
+ next_dev = &new->next;
+ }
+
entry = g_malloc0(sizeof(*entry));
entry->value = info;
entry->next = mach_list;
--
2.7.4
next prev parent reply other threads:[~2016-11-22 1:13 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-11-22 1:11 [Qemu-devel] [RFC 00/15] qmp: Report supported device types on 'query-machines' Eduardo Habkost
2016-11-22 1:11 ` [Qemu-devel] [RFC 01/15] qemu.py: Make logging optional Eduardo Habkost
2016-11-22 1:12 ` [Qemu-devel] [RFC 02/15] qtest.py: Support QTEST_LOG environment variable Eduardo Habkost
2016-11-22 1:12 ` [Qemu-devel] [RFC 03/15] qtest.py: make logging optional Eduardo Habkost
2016-11-22 1:12 ` [Qemu-devel] [RFC 04/15] qtest.py: Make 'binary' parameter optional Eduardo Habkost
2016-11-22 1:12 ` [Qemu-devel] [RFC 05/15] tests: Add rules to non-gtester qtest test cases Eduardo Habkost
2016-11-22 13:34 ` Eduardo Habkost
2016-11-22 1:12 ` [Qemu-devel] [RFC 06/15] qdev: Add device_type field to BusClass Eduardo Habkost
2016-11-24 16:48 ` Cornelia Huck
2016-11-24 17:37 ` Eduardo Habkost
2016-11-22 1:12 ` [Qemu-devel] [RFC 07/15] machine: Add MachineClass::default_buses field Eduardo Habkost
2016-11-22 1:12 ` Eduardo Habkost [this message]
2016-11-22 1:12 ` [Qemu-devel] [RFC 09/15] pci: Introduce INTERFACE_PCIE_DEVICE interface name Eduardo Habkost
2016-11-22 1:12 ` [Qemu-devel] [RFC 10/15] pc: Initialize default bus lists Eduardo Habkost
2016-11-22 1:12 ` [Qemu-devel] [RFC 11/15] s390x: " Eduardo Habkost
2016-12-05 15:24 ` David Hildenbrand
2016-12-05 16:03 ` Cornelia Huck
2016-12-05 16:38 ` Eduardo Habkost
2016-11-22 1:12 ` [Qemu-devel] [RFC 12/15] arm: " Eduardo Habkost
2016-11-22 1:12 ` [Qemu-devel] [RFC 13/15] mips: " Eduardo Habkost
2016-11-22 1:12 ` [Qemu-devel] [RFC 14/15] ppc: " Eduardo Habkost
2016-11-23 3:42 ` Alexey Kardashevskiy
2016-11-22 1:12 ` [Qemu-devel] [RFC 15/15] qdev: Add device_class_set_bus_type() function Eduardo Habkost
2016-11-22 1:34 ` [Qemu-devel] [RFC 00/15] qmp: Report supported device types on 'query-machines' no-reply
2016-11-22 1:36 ` no-reply
2016-11-22 8:18 ` David Hildenbrand
2016-11-22 13:09 ` Eduardo Habkost
2016-11-22 22:34 ` Eduardo Habkost
2016-11-23 17:10 ` [Qemu-devel] -nodefaults and available buses (was Re: [RFC 00/15] qmp: Report supported device types on 'query-machines') Eduardo Habkost
2016-11-24 1:51 ` David Gibson
2016-11-24 16:30 ` Cornelia Huck
2016-11-24 17:42 ` Eduardo Habkost
2016-11-24 13:39 ` Markus Armbruster
2016-11-23 16:43 ` [Qemu-devel] [RFC 00/15] qmp: Report supported device types on 'query-machines' Marcel Apfelbaum
2016-11-23 17:35 ` Eduardo Habkost
2016-11-24 9:34 ` Marcel Apfelbaum
2016-11-24 13:34 ` Markus Armbruster
2016-11-24 14:12 ` Eduardo Habkost
2016-11-24 14:55 ` Markus Armbruster
2016-11-24 14:22 ` Marcel Apfelbaum
2016-11-24 15:41 ` Markus Armbruster
2016-11-24 16:31 ` Marcel Apfelbaum
2016-11-25 8:03 ` Markus Armbruster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1479777133-23567-9-git-send-email-ehabkost@redhat.com \
--to=ehabkost@redhat.com \
--cc=armbru@redhat.com \
--cc=laine@redhat.com \
--cc=libvir-list@redhat.com \
--cc=marcel@redhat.com \
--cc=mst@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).