qemu: Add support for controling qemu capabilities via the qemu XML namespace

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@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
Peter Krempa 2019-06-17 17:17:56 +02:00
parent ca62170e8c
commit c6da5913d9
5 changed files with 134 additions and 2 deletions

View File

@ -519,6 +519,36 @@ mount -t cgroup none /dev/cgroup -o devices
&lt;qemu:env name='QEMU_ENV' value='VAL'/&gt;
&lt;/qemu:commandline&gt;
&lt;/domain&gt;
</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>&lt;qemu:capabilities&gt;</code> element to add
(<code>&lt;qemu:add capability="capname"/&gt;</code>) or remove
(<code>&lt;qemu:del capability="capname"/&gt;</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>
&lt;domain type='qemu' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'&gt;
&lt;name&gt;testvm&lt;/name&gt;
[...]
&lt;qemu:capabilities&gt;
&lt;qemu:add capability='blockdev'/&gt;
&lt;qemu:del capability='drive'/&gt;
&lt;/qemu:capabilities&gt;
&lt;/domain&gt;
</pre>
<h2><a id="xmlconfig">Example domain XML config</a></h2>

View File

@ -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

View File

@ -3096,6 +3096,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);
}
@ -3195,6 +3197,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,
@ -3215,10 +3261,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;
@ -3256,6 +3304,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)
@ -3263,6 +3334,7 @@ qemuDomainDefNamespaceFormatXML(virBufferPtr buf,
qemuDomainXmlNsDefPtr cmd = nsdata;
qemuDomainDefNamespaceFormatXMLCommandline(buf, cmd);
qemuDomainDefNamespaceFormatXMLCaps(buf, cmd);
return 0;
}

View File

@ -539,6 +539,12 @@ struct _qemuDomainXmlNsDef {
unsigned int num_env;
char **env_name;
char **env_value;
size_t ncapsadd;
char **capsadd;
size_t ncapsdel;
char **capsdel;
};

View File

@ -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>