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(a)redhat.com>
---
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