Similarly how we allow adding arbitrary command line arguments and environment variables this patch introduces the ability to control libvirt's perception of the qemu process by tweaking the capability bits for testing purposes. The idea is to allow developers and users either test a new feature by enabling it early or disabling it to see whether it introduced regressions. This feature is not meant for production use though, so users should handle it with care. Signed-off-by: Peter Krempa <pkrempa@xxxxxxxxxx> --- docs/drvqemu.html.in | 30 ++++++++++++ docs/schemas/domaincommon.rng | 19 ++++++++ src/qemu/qemu_domain.c | 76 +++++++++++++++++++++++++++++- src/qemu/qemu_domain.h | 6 +++ tests/qemuxml2argvdata/qemu-ns.xml | 5 ++ 5 files changed, 134 insertions(+), 2 deletions(-) diff --git a/docs/drvqemu.html.in b/docs/drvqemu.html.in index cf36f6cc7b..aa61ee5ced 100644 --- a/docs/drvqemu.html.in +++ b/docs/drvqemu.html.in @@ -519,6 +519,36 @@ mount -t cgroup none /dev/cgroup -o devices <qemu:env name='QEMU_ENV' value='VAL'/> </qemu:commandline> </domain> +</pre> + + <h2><a id="xmlnsfeatures">QEMU feature configuration for testing</a></h2> + + <p> + In some cases e.g. when developing a new feature or for testing it may + be required to control a given qemu feature (or qemu capability) to test + it before it's complete or disable it for debugging purposes. + <span class="since">Since 5.5.0</span> it's possible to use the same + special qemu namespace as above + (<code>http://libvirt.org/schemas/domain/qemu/1.0</code>) and use + <code><qemu:capabilities></code> element to add + (<code><qemu:add capability="capname"/></code>) or remove + (<code><qemu:del capability="capname"/></code>) capability bits. + The naming of the feature bits is the same libvirt uses in the status + XML. Note that this feature is meant for experiments only and should + _not_ be used in production. + </p> + + <p>Example:</p><pre> +<domain type='qemu' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'> + <name>testvm</name> + + [...] + + <qemu:capabilities> + <qemu:add capability='blockdev'/> + <qemu:del capability='drive'/> + </qemu:capabilities> +</domain> </pre> <h2><a id="xmlconfig">Example domain XML config</a></h2> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 3661f0a556..ad4c32d480 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -72,6 +72,9 @@ <optional> <ref name='qemucmdline'/> </optional> + <optional> + <ref name='qemucapabilities'/> + </optional> <optional> <ref name='lxcsharens'/> </optional> @@ -6197,6 +6200,22 @@ </element> </define> + <define name="qemucapabilities"> + <element name="capabilities" ns="http://libvirt.org/schemas/domain/qemu/1.0"> + <zeroOrMore> + <element name="add"> + <attribute name="capability"/> + </element> + </zeroOrMore> + <zeroOrMore> + <element name="del"> + <attribute name="capability"/> + </element> + </zeroOrMore> + </element> + </define> + + <!-- Optional hypervisor extensions in their own namespace: LXC diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 864071220b..5caa31d3bc 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3100,6 +3100,8 @@ qemuDomainXmlNsDefFree(qemuDomainXmlNsDefPtr def) virStringListFreeCount(def->args, def->num_args); virStringListFreeCount(def->env_name, def->num_env); virStringListFreeCount(def->env_value, def->num_env); + virStringListFreeCount(def->capsadd, def->ncapsadd); + virStringListFreeCount(def->capsdel, def->ncapsdel); VIR_FREE(def); } @@ -3199,6 +3201,50 @@ qemuDomainDefNamespaceParseCommandlineEnv(qemuDomainXmlNsDefPtr nsdef, } +static int +qemuDomainDefNamespaceParseCaps(qemuDomainXmlNsDefPtr nsdef, + xmlXPathContextPtr ctxt) +{ + VIR_AUTOFREE(xmlNodePtr *) nodesadd = NULL; + ssize_t nnodesadd; + VIR_AUTOFREE(xmlNodePtr *) nodesdel = NULL; + ssize_t nnodesdel; + size_t i; + + if ((nnodesadd = virXPathNodeSet("./qemu:capabilities/qemu:add", ctxt, &nodesadd)) < 0 || + (nnodesdel = virXPathNodeSet("./qemu:capabilities/qemu:del", ctxt, &nodesdel)) < 0) + return -1; + + if (nnodesadd > 0) { + if (VIR_ALLOC_N(nsdef->capsadd, nnodesadd) < 0) + return -1; + + for (i = 0; i < nnodesadd; i++) { + if (!(nsdef->capsadd[nsdef->ncapsadd++] = virXMLPropString(nodesadd[i], "capability"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing capability name")); + return -1; + } + } + } + + if (nnodesdel > 0) { + if (VIR_ALLOC_N(nsdef->capsdel, nnodesdel) < 0) + return -1; + + for (i = 0; i < nnodesdel; i++) { + if (!(nsdef->capsdel[nsdef->ncapsdel++] = virXMLPropString(nodesdel[i], "capability"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing capability name")); + return -1; + } + } + } + + return 0; +} + + static int qemuDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED, xmlNodePtr root ATTRIBUTE_UNUSED, @@ -3219,10 +3265,12 @@ qemuDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED, return -1; if (qemuDomainDefNamespaceParseCommandlineArgs(nsdata, ctxt) < 0 || - qemuDomainDefNamespaceParseCommandlineEnv(nsdata, ctxt) < 0) + qemuDomainDefNamespaceParseCommandlineEnv(nsdata, ctxt) < 0 || + qemuDomainDefNamespaceParseCaps(nsdata, ctxt) < 0) goto cleanup; - if (nsdata->num_args > 0 || nsdata->num_env > 0) + if (nsdata->num_args > 0 || nsdata->num_env > 0 || + nsdata->ncapsadd > 0 || nsdata->ncapsdel > 0) VIR_STEAL_PTR(*data, nsdata); ret = 0; @@ -3260,6 +3308,29 @@ qemuDomainDefNamespaceFormatXMLCommandline(virBufferPtr buf, } +static void +qemuDomainDefNamespaceFormatXMLCaps(virBufferPtr buf, + qemuDomainXmlNsDefPtr xmlns) +{ + size_t i; + + if (!xmlns->ncapsadd && !xmlns->ncapsdel) + return; + + virBufferAddLit(buf, "<qemu:capabilities>\n"); + virBufferAdjustIndent(buf, 2); + + for (i = 0; i < xmlns->ncapsadd; i++) + virBufferEscapeString(buf, "<qemu:add capability='%s'/>\n", xmlns->capsadd[i]); + + for (i = 0; i < xmlns->ncapsdel; i++) + virBufferEscapeString(buf, "<qemu:del capability='%s'/>\n", xmlns->capsdel[i]); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</qemu:capabilities>\n"); +} + + static int qemuDomainDefNamespaceFormatXML(virBufferPtr buf, void *nsdata) @@ -3267,6 +3338,7 @@ qemuDomainDefNamespaceFormatXML(virBufferPtr buf, qemuDomainXmlNsDefPtr cmd = nsdata; qemuDomainDefNamespaceFormatXMLCommandline(buf, cmd); + qemuDomainDefNamespaceFormatXMLCaps(buf, cmd); return 0; } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 474c7b613a..fd52696807 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -541,6 +541,12 @@ struct _qemuDomainXmlNsDef { unsigned int num_env; char **env_name; char **env_value; + + size_t ncapsadd; + char **capsadd; + + size_t ncapsdel; + char **capsdel; }; diff --git a/tests/qemuxml2argvdata/qemu-ns.xml b/tests/qemuxml2argvdata/qemu-ns.xml index 62860a683c..c1095b3e81 100644 --- a/tests/qemuxml2argvdata/qemu-ns.xml +++ b/tests/qemuxml2argvdata/qemu-ns.xml @@ -27,4 +27,9 @@ <qemu:env name='NS' value='ns'/> <qemu:env name='BAR'/> </qemu:commandline> + <qemu:capabilities> + <qemu:add capability="vnc-colon"/> + <qemu:add capability="drive"/> + <qemu:del capability="name"/> + </qemu:capabilities> </domain> -- 2.21.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list