[libvirt] qemu-namespace handling?

Hello, some time ago I hand to manipulate the domain XML description using Pythons Elemtree XML implementation, which had problems generating the right format for libvirt: elemtree just supports adding Qname elements (that is "{http://libvirt.org/schemas/domain/qemu/1.0}commandline") which internally would create a temporary binding of this namespace to the "ns0" Prefix. My work-around for Elemtree was the add the name-space mapping for "qemu" to "http://libvirt.org/schemas/domain/qemu/1.0" to ETs internal mapping table and add an "xmlns:qemu" attribute by hand: ET._namespace_map[QEMU_URI] = 'qemu' domain.attrib['xmlns:qemu'] = QEMU_URI libvirt on the other hand expects the prefix to be "qemu" and only checks, that this prefix is bound to the URI mentioned above at the root node). The following examples would be XML valid, but are not accepted by libvirt: <domain>... <qemu:commandline xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> ...</qemu:commandline> </domain> <domain xmlns:ns0="http://libvirt.org/schemas/domain/qemu/1.0">... <ns0:commandline> ...</ns0:commandline> </domain> The following (esoteric) example might be wrongly accepted by libvirt (untested): <domain xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> <qemu:commandline xmlns:qemu="urn:foo"> ...</qemu:commandline> </domain> I don't know if this is worth fixing, but I still encountered the first two problems myself and had to spend some time to detecting what I did wrong. So at least I want to share my finding with others, so they don't do the same mistake. Sincerely Philipp Hahn -- Philipp Hahn Open Source Software Engineer hahn@univention.de Univention GmbH Linux for Your Business fon: +49 421 22 232- 0 Mary-Somerville-Str.1 D-28359 Bremen fax: +49 421 22 232-99 http://www.univention.de/

On Tue, Apr 12, 2011 at 09:29:15AM +0200, Philipp Hahn wrote:
Hello,
some time ago I hand to manipulate the domain XML description using Pythons Elemtree XML implementation, which had problems generating the right format for libvirt: elemtree just supports adding Qname elements (that is "{http://libvirt.org/schemas/domain/qemu/1.0}commandline") which internally would create a temporary binding of this namespace to the "ns0" Prefix.
My work-around for Elemtree was the add the name-space mapping for "qemu" to "http://libvirt.org/schemas/domain/qemu/1.0" to ETs internal mapping table and add an "xmlns:qemu" attribute by hand: ET._namespace_map[QEMU_URI] = 'qemu' domain.attrib['xmlns:qemu'] = QEMU_URI
libvirt on the other hand expects the prefix to be "qemu" and only checks, that this prefix is bound to the URI mentioned above at the root node).
This is definitely a libvirt bug we should fix. The namespace prefix should not be used as anything other than a key to match to a corresponding namespace URI. So libvirt should not look for "qemu", it should allow anything which ultimately maps to "http://libvirt.org/schemas/domain/qemu/1.0"
The following examples would be XML valid, but are not accepted by libvirt:
<domain>... <qemu:commandline xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> ...</qemu:commandline> </domain>
<domain xmlns:ns0="http://libvirt.org/schemas/domain/qemu/1.0">... <ns0:commandline> ...</ns0:commandline> </domain>
Yes, we should fix our code to accept both of those.
The following (esoteric) example might be wrongly accepted by libvirt (untested):
<domain xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> <qemu:commandline xmlns:qemu="urn:foo"> ...</qemu:commandline> </domain>
Eww, nasty.
I don't know if this is worth fixing, but I still encountered the first two problems myself and had to spend some time to detecting what I did wrong. So at least I want to share my finding with others, so they don't do the same mistake.
Thanks for pointing this out. We really want to fix this, because when building up an XML doc via an API, it is all too easy to skip over the addition of the fixed prefix<->URI mapping, and just let your XML API auto-generate a prefix. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

The XML parser for the qemu specific extensions expects the qemu name-space to be bound to the 'qemu' prefix. This is too strict, since the name of the name-space-prefix is only mend as an internal lookup key. Only the associated URI is relevant. <domain>... <qemu:commandline xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> ...</qemu:commandline> </domain> <domain xmlns:ns0="http://libvirt.org/schemas/domain/qemu/1.0">... <ns0:commandline> ...</ns0:commandline> </domain> <domain xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> <qemu:commandline xmlns:qemu="urn:foo"> ...</qemu:commandline> </domain> Remove the test for checking the name-space binding on the top-level <domain> element. Registering the name-space with XPath is enough. Signed-off-by: Philipp Hahn <hahn@univention.de> --- src/qemu/qemu_domain.c | 30 ++++++++++++------------------ 1 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 5abc900..b202ba7 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -484,31 +484,20 @@ qemuDomainDefNamespaceFree(void *nsdata) } static int -qemuDomainDefNamespaceParse(xmlDocPtr xml, - xmlNodePtr root, +qemuDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED, + xmlNodePtr root ATTRIBUTE_UNUSED, xmlXPathContextPtr ctxt, void **data) { qemuDomainCmdlineDefPtr cmd = NULL; - xmlNsPtr ns; + bool uses_qemu_ns = false; xmlNodePtr *nodes = NULL; int n, i; - ns = xmlSearchNs(xml, root, BAD_CAST "qemu"); - if (!ns) - /* this is fine; it just means there was no qemu namespace listed */ - return 0; - - if (STRNEQ((const char *)ns->href, QEMU_NAMESPACE_HREF)) { + if (xmlXPathRegisterNs(ctxt, BAD_CAST "qemu", BAD_CAST QEMU_NAMESPACE_HREF) < 0) { qemuReportError(VIR_ERR_INTERNAL_ERROR, - _("Found namespace '%s' doesn't match expected '%s'"), - ns->href, QEMU_NAMESPACE_HREF); - return -1; - } - - if (xmlXPathRegisterNs(ctxt, ns->prefix, ns->href) < 0) { - qemuReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to register xml namespace '%s'"), ns->href); + _("Failed to register xml namespace '%s'"), + QEMU_NAMESPACE_HREF); return -1; } @@ -521,6 +510,7 @@ qemuDomainDefNamespaceParse(xmlDocPtr xml, n = virXPathNodeSet("./qemu:commandline/qemu:arg", ctxt, &nodes); if (n < 0) goto error; + uses_qemu_ns |= n > 0; if (n && VIR_ALLOC_N(cmd->args, n) < 0) goto no_memory; @@ -541,6 +531,7 @@ qemuDomainDefNamespaceParse(xmlDocPtr xml, n = virXPathNodeSet("./qemu:commandline/qemu:env", ctxt, &nodes); if (n < 0) goto error; + uses_qemu_ns |= n > 0; if (n && VIR_ALLOC_N(cmd->env_name, n) < 0) goto no_memory; @@ -582,7 +573,10 @@ qemuDomainDefNamespaceParse(xmlDocPtr xml, VIR_FREE(nodes); - *data = cmd; + if (uses_qemu_ns) + *data = cmd; + else + VIR_FREE(cmd); return 0; -- 1.7.1

Add test cases for parsing the qemu-name-space. This is based on qemuxml2argv{test,data/}, but can not reside in qemuxml2argv{test,data/} because ... 1. qemuxmlns-qemu-ns-domain.xml is not schema-valid and breaks domainschematest. The test is still important to detect xmlns:qemu bindings to a name-space other than http://libvirt.org/schemas/domain/qemu/1.0 2. they break qemuxml2xml, because the xmlns:qemu binding is moved to the top-level <domain> element when converting from argv to xml. Signed-off-by: Philipp Hahn <hahn@univention.de> --- tests/Makefile.am | 12 +- .../qemuxmlns-qemu-ns-commandline-ns0.args | 4 + .../qemuxmlns-qemu-ns-commandline-ns0.xml | 27 ++ .../qemuxmlns-qemu-ns-commandline-ns1.args | 4 + .../qemuxmlns-qemu-ns-commandline-ns1.xml | 27 ++ .../qemuxmlns-qemu-ns-commandline.args | 4 + .../qemuxmlns-qemu-ns-commandline.xml | 27 ++ .../qemuxmlns-qemu-ns-domain-commandline-ns0.args | 4 + .../qemuxmlns-qemu-ns-domain-commandline-ns0.xml | 27 ++ .../qemuxmlns-qemu-ns-domain-commandline.args | 4 + .../qemuxmlns-qemu-ns-domain-commandline.xml | 27 ++ .../qemuxmlns-qemu-ns-domain-ns0.args | 4 + .../qemuxmlnsdata/qemuxmlns-qemu-ns-domain-ns0.xml | 27 ++ tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.args | 4 + tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.xml | 27 ++ tests/qemuxmlnstest.c | 290 ++++++++++++++++++++ 16 files changed, 516 insertions(+), 3 deletions(-) create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns0.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns0.xml create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns1.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns1.xml create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline.xml create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline-ns0.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline-ns0.xml create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline.xml create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-ns0.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-ns0.xml create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.xml create mode 100644 tests/qemuxmlnstest.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 7c540e5..b522118 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -75,6 +75,7 @@ EXTRA_DIST = \ qemuhelpdata \ qemuxml2argvdata \ qemuxml2xmloutdata \ + qemuxmlnsdata \ schematestutils.sh \ sexpr2xmldata \ storagepoolschematest \ @@ -108,7 +109,7 @@ check_PROGRAMS += xml2sexprtest sexpr2xmltest \ xmconfigtest xencapstest statstest reconnect endif if WITH_QEMU -check_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest qemuhelptest +check_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest qemuargv2xmltest qemuhelptest endif if WITH_OPENVZ @@ -233,7 +234,7 @@ TESTS += xml2sexprtest \ endif if WITH_QEMU -TESTS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest qemuhelptest +TESTS += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest qemuargv2xmltest qemuhelptest TESTS += nwfilterxml2xmltest endif @@ -349,6 +350,11 @@ qemuxml2xmltest_SOURCES = \ testutils.c testutils.h qemuxml2xmltest_LDADD = $(qemu_LDADDS) $(LDADDS) +qemuxmlnstest_SOURCES = \ + qemuxmlnstest.c testutilsqemu.c testutilsqemu.h \ + testutils.c testutils.h +qemuxmlnstest_LDADD = $(qemu_LDADDS) $(LDADDS) + qemuargv2xmltest_SOURCES = \ qemuargv2xmltest.c testutilsqemu.c testutilsqemu.h \ testutils.c testutils.h @@ -357,7 +363,7 @@ qemuargv2xmltest_LDADD = $(qemu_LDADDS) $(LDADDS) qemuhelptest_SOURCES = qemuhelptest.c testutils.c testutils.h qemuhelptest_LDADD = $(qemu_LDADDS) $(LDADDS) else -EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuargv2xmltest.c qemuhelptest.c testutilsqemu.c testutilsqemu.h +EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuxmlnstest.c qemuargv2xmltest.c qemuhelptest.c testutilsqemu.c testutilsqemu.h endif if WITH_OPENVZ diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns0.args b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns0.args new file mode 100644 index 0000000..35b0e54 --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns0.args @@ -0,0 +1,4 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \ +/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda \ +/dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb ARGUMENT diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns0.xml b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns0.xml new file mode 100644 index 0000000..efa2c25 --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns0.xml @@ -0,0 +1,27 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219136</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + </devices> + <ns0:commandline xmlns:ns0='http://libvirt.org/schemas/domain/qemu/1.0'> + <ns0:arg value='ARGUMENT'/> + </ns0:commandline> +</domain> diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns1.args b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns1.args new file mode 100644 index 0000000..35b0e54 --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns1.args @@ -0,0 +1,4 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \ +/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda \ +/dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb ARGUMENT diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns1.xml b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns1.xml new file mode 100644 index 0000000..0217d1c --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns1.xml @@ -0,0 +1,27 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219136</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + </devices> + <ns0:commandline xmlns:ns0='http://libvirt.org/schemas/domain/qemu/1.0'> + <ns1:arg value='ARGUMENT' xmlns:ns1='http://libvirt.org/schemas/domain/qemu/1.0'/> + </ns0:commandline> +</domain> diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline.args b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline.args new file mode 100644 index 0000000..35b0e54 --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline.args @@ -0,0 +1,4 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \ +/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda \ +/dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb ARGUMENT diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline.xml b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline.xml new file mode 100644 index 0000000..626c07d --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline.xml @@ -0,0 +1,27 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219136</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + </devices> + <qemu:commandline xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'> + <qemu:arg value='ARGUMENT'/> + </qemu:commandline> +</domain> diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline-ns0.args b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline-ns0.args new file mode 100644 index 0000000..35b0e54 --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline-ns0.args @@ -0,0 +1,4 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \ +/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda \ +/dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb ARGUMENT diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline-ns0.xml b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline-ns0.xml new file mode 100644 index 0000000..93989b1 --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline-ns0.xml @@ -0,0 +1,27 @@ +<domain type='qemu' xmlns:qemu='urn:dummy'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219136</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + </devices> + <ns0:commandline xmlns:ns0='http://libvirt.org/schemas/domain/qemu/1.0'> + <ns0:arg value='ARGUMENT'/> + </ns0:commandline> +</domain> diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline.args b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline.args new file mode 100644 index 0000000..35b0e54 --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline.args @@ -0,0 +1,4 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \ +/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda \ +/dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb ARGUMENT diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline.xml b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline.xml new file mode 100644 index 0000000..987bd8d --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline.xml @@ -0,0 +1,27 @@ +<domain type='qemu' xmlns:qemu='urn:dummy'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219136</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + </devices> + <qemu:commandline xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'> + <qemu:arg value='ARGUMENT'/> + </qemu:commandline> +</domain> diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-ns0.args b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-ns0.args new file mode 100644 index 0000000..35b0e54 --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-ns0.args @@ -0,0 +1,4 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \ +/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda \ +/dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb ARGUMENT diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-ns0.xml b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-ns0.xml new file mode 100644 index 0000000..d9413cd --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-ns0.xml @@ -0,0 +1,27 @@ +<domain type='qemu' xmlns:ns0='http://libvirt.org/schemas/domain/qemu/1.0'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219136</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + </devices> + <ns0:commandline> + <ns0:arg value='ARGUMENT'/> + </ns0:commandline> +</domain> diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.args b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.args new file mode 100644 index 0000000..b70e63e --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.args @@ -0,0 +1,4 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \ +/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda \ +/dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb diff --git a/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.xml b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.xml new file mode 100644 index 0000000..3afa5b7 --- /dev/null +++ b/tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.xml @@ -0,0 +1,27 @@ +<domain type='qemu' xmlns:qemu='urn:dummy'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219136</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + </devices> + <qemu:commandline> + <qemu:arg value='ARGUMENT'/> + </qemu:commandline> +</domain> diff --git a/tests/qemuxmlnstest.c b/tests/qemuxmlnstest.c new file mode 100644 index 0000000..03d5b03 --- /dev/null +++ b/tests/qemuxmlnstest.c @@ -0,0 +1,290 @@ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <sys/types.h> +#include <fcntl.h> + +#ifdef WITH_QEMU + +# include "internal.h" +# include "testutils.h" +# include "qemu/qemu_capabilities.h" +# include "qemu/qemu_command.h" +# include "qemu/qemu_domain.h" +# include "datatypes.h" +# include "cpu/cpu_map.h" + +# include "testutilsqemu.h" + +static const char *abs_top_srcdir; +static struct qemud_driver driver; + +static int testCompareXMLToArgvFiles(const char *xml, + const char *cmdline, + virBitmapPtr extraFlags, + const char *migrateFrom, + int migrateFd, + bool json, + bool expectError) +{ + char *expectargv = NULL; + int len; + char *actualargv = NULL; + int ret = -1; + virDomainDefPtr vmdef = NULL; + virDomainChrSourceDef monitor_chr; + virConnectPtr conn; + char *log = NULL; + char *emulator = NULL; + virCommandPtr cmd = NULL; + + if (!(conn = virGetConnect())) + goto fail; + + len = virtTestLoadFile(cmdline, &expectargv); + if (len < 0) + goto fail; + if (len && expectargv[len - 1] == '\n') + expectargv[len - 1] = '\0'; + + if (!(vmdef = virDomainDefParseFile(driver.caps, xml, + QEMU_EXPECTED_VIRT_TYPES, + VIR_DOMAIN_XML_INACTIVE))) + goto fail; + + /* + * For test purposes, we may want to fake emulator's output by providing + * our own script instead of a real emulator. For this to work we need to + * specify a relative path in <emulator/> element, which, however, is not + * allowed by RelaxNG schema for domain XML. To work around it we add an + * extra '/' at the beginning of relative emulator path so that it looks + * like, e.g., "/./qemu.sh" or "/../emulator/qemu.sh" instead of + * "./qemu.sh" or "../emulator/qemu.sh" respectively. The following code + * detects such paths, strips the extra '/' and makes the path absolute. + */ + if (vmdef->emulator && STRPREFIX(vmdef->emulator, "/.")) { + if (!(emulator = strdup(vmdef->emulator + 1))) + goto fail; + free(vmdef->emulator); + vmdef->emulator = NULL; + if (virAsprintf(&vmdef->emulator, "%s/qemuxml2argvdata/%s", + abs_srcdir, emulator) < 0) + goto fail; + } + + if (qemuCapsGet(extraFlags, QEMU_CAPS_DOMID)) + vmdef->id = 6; + else + vmdef->id = -1; + + memset(&monitor_chr, 0, sizeof(monitor_chr)); + monitor_chr.type = VIR_DOMAIN_CHR_TYPE_UNIX; + monitor_chr.data.nix.path = (char *)"/tmp/test-monitor"; + monitor_chr.data.nix.listen = true; + + qemuCapsSetList(extraFlags, + QEMU_CAPS_VNC_COLON, + QEMU_CAPS_NO_REBOOT, + QEMU_CAPS_LAST); + + if (qemudCanonicalizeMachine(&driver, vmdef) < 0) + goto fail; + + if (qemuCapsGet(extraFlags, QEMU_CAPS_DEVICE)) { + qemuDomainPCIAddressSetPtr pciaddrs; + if (!(pciaddrs = qemuDomainPCIAddressSetCreate(vmdef))) + goto fail; + + if (qemuAssignDevicePCISlots(vmdef, pciaddrs) < 0) + goto fail; + + qemuDomainPCIAddressSetFree(pciaddrs); + } + + + free(virtTestLogContentAndReset()); + virResetLastError(); + + /* We do not call qemuCapsExtractVersionInfo() before calling + * qemuBuildCommandLine(), so we should set QEMU_CAPS_PCI_MULTIBUS for + * x86_64 and i686 architectures here. + */ + if (STREQLEN(vmdef->os.arch, "x86_64", 6) || + STREQLEN(vmdef->os.arch, "i686", 4)) { + qemuCapsSet(extraFlags, QEMU_CAPS_PCI_MULTIBUS); + } + + if (!(cmd = qemuBuildCommandLine(conn, &driver, + vmdef, &monitor_chr, json, extraFlags, + migrateFrom, migrateFd, NULL, + VIR_VM_OP_NO_OP))) + goto fail; + + if (!!virGetLastError() != expectError) { + if (virTestGetDebug() && (log = virtTestLogContentAndReset())) + fprintf(stderr, "\n%s", log); + goto fail; + } + + if (expectError) { + /* need to suppress the errors */ + virResetLastError(); + } + + if (!(actualargv = virCommandToString(cmd))) + goto fail; + + if (emulator) { + /* Skip the abs_srcdir portion of replacement emulator. */ + char *start_skip = strstr(actualargv, abs_srcdir); + char *end_skip = strstr(actualargv, emulator); + if (!start_skip || !end_skip) + goto fail; + memmove(start_skip, end_skip, strlen(end_skip) + 1); + } + + if (STRNEQ(expectargv, actualargv)) { + virtTestDifference(stderr, expectargv, actualargv); + goto fail; + } + + ret = 0; + + fail: + free(log); + free(emulator); + free(expectargv); + free(actualargv); + virCommandFree(cmd); + virDomainDefFree(vmdef); + virUnrefConnect(conn); + return ret; +} + + +struct testInfo { + const char *name; + virBitmapPtr extraFlags; + const char *migrateFrom; + int migrateFd; + bool json; + bool expectError; +}; + +static int +testCompareXMLToArgvHelper(const void *data) +{ + int result = -1; + const struct testInfo *info = data; + char *xml = NULL; + char *args = NULL; + + if (virAsprintf(&xml, "%s/qemuxmlnsdata/qemuxmlns-%s.xml", + abs_srcdir, info->name) < 0 || + virAsprintf(&args, "%s/qemuxmlnsdata/qemuxmlns-%s.args", + abs_srcdir, info->name) < 0) + goto cleanup; + + result = testCompareXMLToArgvFiles(xml, args, info->extraFlags, + info->migrateFrom, info->migrateFd, + info->json, info->expectError); + +cleanup: + free(xml); + free(args); + return result; +} + + + +static int +mymain(void) +{ + int ret = 0; + char *map = NULL; + bool json = false; + + abs_top_srcdir = getenv("abs_top_srcdir"); + if (!abs_top_srcdir) + abs_top_srcdir = ".."; + + if ((driver.caps = testQemuCapsInit()) == NULL) + return EXIT_FAILURE; + if ((driver.stateDir = strdup("/nowhere")) == NULL) + return EXIT_FAILURE; + if ((driver.hugetlbfs_mount = strdup("/dev/hugepages")) == NULL) + return EXIT_FAILURE; + if ((driver.hugepage_path = strdup("/dev/hugepages/libvirt/qemu")) == NULL) + return EXIT_FAILURE; + driver.spiceTLS = 1; + if (!(driver.spiceTLSx509certdir = strdup("/etc/pki/libvirt-spice"))) + return EXIT_FAILURE; + if (!(driver.spicePassword = strdup("123456"))) + return EXIT_FAILURE; + if (virAsprintf(&map, "%s/src/cpu/cpu_map.xml", abs_top_srcdir) < 0 || + cpuMapOverride(map) < 0) { + free(map); + return EXIT_FAILURE; + } + +# define DO_TEST_FULL(name, migrateFrom, migrateFd, expectError, ...) \ + do { \ + struct testInfo info = { \ + name, NULL, migrateFrom, migrateFd, json, expectError \ + }; \ + if (!(info.extraFlags = qemuCapsNew())) \ + return EXIT_FAILURE; \ + qemuCapsSetList(info.extraFlags, __VA_ARGS__, QEMU_CAPS_LAST); \ + if (virtTestRun("QEMU XML-2-ARGV " name, \ + 1, testCompareXMLToArgvHelper, &info) < 0) \ + ret = -1; \ + qemuCapsFree(info.extraFlags); \ + } while (0) + +# define DO_TEST(name, expectError, ...) \ + DO_TEST_FULL(name, NULL, -1, expectError, __VA_ARGS__) + +# define NONE QEMU_CAPS_LAST + + /* Unset or set all envvars here that are copied in qemudBuildCommandLine + * using ADD_ENV_COPY, otherwise these tests may fail due to unexpected + * values for these envvars */ + setenv("PATH", "/bin", 1); + setenv("USER", "test", 1); + setenv("LOGNAME", "test", 1); + setenv("HOME", "/home/test", 1); + unsetenv("TMPDIR"); + unsetenv("LD_PRELOAD"); + unsetenv("LD_LIBRARY_PATH"); + unsetenv("QEMU_AUDIO_DRV"); + unsetenv("SDL_AUDIODRIVER"); + + DO_TEST("qemu-ns-domain", false, NONE); + DO_TEST("qemu-ns-domain-ns0", false, NONE); + DO_TEST("qemu-ns-domain-commandline", false, NONE); + DO_TEST("qemu-ns-domain-commandline-ns0", false, NONE); + DO_TEST("qemu-ns-commandline", false, NONE); + DO_TEST("qemu-ns-commandline-ns0", false, NONE); + DO_TEST("qemu-ns-commandline-ns1", false, NONE); + + free(driver.stateDir); + virCapabilitiesFree(driver.caps); + free(map); + + return(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +VIRT_TEST_MAIN(mymain) + +#else + +int main(void) +{ + return EXIT_AM_SKIP; +} + +#endif /* WITH_QEMU */ -- 1.7.1

On Tue, Oct 18, 2011 at 09:16:01PM +0200, Philipp Hahn wrote:
Add test cases for parsing the qemu-name-space. This is based on qemuxml2argv{test,data/}, but can not reside in qemuxml2argv{test,data/} because ...
1. qemuxmlns-qemu-ns-domain.xml is not schema-valid and breaks domainschematest. The test is still important to detect xmlns:qemu bindings to a name-space other than http://libvirt.org/schemas/domain/qemu/1.0
2. they break qemuxml2xml, because the xmlns:qemu binding is moved to the top-level <domain> element when converting from argv to xml.
Signed-off-by: Philipp Hahn <hahn@univention.de> --- tests/Makefile.am | 12 +- .../qemuxmlns-qemu-ns-commandline-ns0.args | 4 + .../qemuxmlns-qemu-ns-commandline-ns0.xml | 27 ++ .../qemuxmlns-qemu-ns-commandline-ns1.args | 4 + .../qemuxmlns-qemu-ns-commandline-ns1.xml | 27 ++ .../qemuxmlns-qemu-ns-commandline.args | 4 + .../qemuxmlns-qemu-ns-commandline.xml | 27 ++ .../qemuxmlns-qemu-ns-domain-commandline-ns0.args | 4 + .../qemuxmlns-qemu-ns-domain-commandline-ns0.xml | 27 ++ .../qemuxmlns-qemu-ns-domain-commandline.args | 4 + .../qemuxmlns-qemu-ns-domain-commandline.xml | 27 ++ .../qemuxmlns-qemu-ns-domain-ns0.args | 4 + .../qemuxmlnsdata/qemuxmlns-qemu-ns-domain-ns0.xml | 27 ++ tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.args | 4 + tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.xml | 27 ++ tests/qemuxmlnstest.c | 290 ++++++++++++++++++++ 16 files changed, 516 insertions(+), 3 deletions(-) create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns0.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns0.xml create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns1.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline-ns1.xml create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-commandline.xml create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline-ns0.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline-ns0.xml create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-commandline.xml create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-ns0.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain-ns0.xml create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.args create mode 100644 tests/qemuxmlnsdata/qemuxmlns-qemu-ns-domain.xml create mode 100644 tests/qemuxmlnstest.c
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 10/19/2011 01:44 AM, Daniel P. Berrange wrote:
On Tue, Oct 18, 2011 at 09:16:01PM +0200, Philipp Hahn wrote:
Add test cases for parsing the qemu-name-space. This is based on qemuxml2argv{test,data/}, but can not reside in qemuxml2argv{test,data/} because ...
ACK
Pushed. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Tue, Oct 18, 2011 at 06:22:49PM +0200, Philipp Hahn wrote:
The XML parser for the qemu specific extensions expects the qemu name-space to be bound to the 'qemu' prefix. This is too strict, since the name of the name-space-prefix is only mend as an internal lookup key. Only the associated URI is relevant. <domain>... <qemu:commandline xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> ...</qemu:commandline> </domain>
<domain xmlns:ns0="http://libvirt.org/schemas/domain/qemu/1.0">... <ns0:commandline> ...</ns0:commandline> </domain>
<domain xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> <qemu:commandline xmlns:qemu="urn:foo"> ...</qemu:commandline> </domain>
Remove the test for checking the name-space binding on the top-level <domain> element. Registering the name-space with XPath is enough.
Signed-off-by: Philipp Hahn <hahn@univention.de> --- src/qemu/qemu_domain.c | 30 ++++++++++++------------------ 1 files changed, 12 insertions(+), 18 deletions(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 10/19/2011 01:44 AM, Daniel P. Berrange wrote:
On Tue, Oct 18, 2011 at 06:22:49PM +0200, Philipp Hahn wrote:
The XML parser for the qemu specific extensions expects the qemu name-space to be bound to the 'qemu' prefix. This is too strict, since the name of the name-space-prefix is only mend as an internal lookup key. Only the associated
s/mend/meant/
URI is relevant. <domain>... <qemu:commandline xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> ...</qemu:commandline> </domain>
<domain xmlns:ns0="http://libvirt.org/schemas/domain/qemu/1.0">... <ns0:commandline> ...</ns0:commandline> </domain>
<domain xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> <qemu:commandline xmlns:qemu="urn:foo"> ...</qemu:commandline> </domain>
Remove the test for checking the name-space binding on the top-level<domain> element. Registering the name-space with XPath is enough.
Signed-off-by: Philipp Hahn<hahn@univention.de> --- src/qemu/qemu_domain.c | 30 ++++++++++++------------------ 1 files changed, 12 insertions(+), 18 deletions(-)
ACK
Pushed. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org
participants (3)
-
Daniel P. Berrange
-
Eric Blake
-
Philipp Hahn