Allow custom metadata in domain configuration XML

Applications can now insert custom nodes and hierarchies into domain
configuration XML. Although currently not enforced, applications are
required to use their own namespaces on every custom node they insert,
with only one top-level element per namespace.
This commit is contained in:
Zeeshan Ali (Khattak) 2012-01-24 04:26:18 +02:00 committed by Eric Blake
parent d19149dda8
commit fa981fc945
11 changed files with 192 additions and 0 deletions

View File

@ -217,6 +217,7 @@ Patches have also been contributed by:
Deepak C Shetty <deepakcs@linux.vnet.ibm.com>
Martin Kletzander <mkletzan@redhat.com>
Laszlo Ersek <lersek@redhat.com>
Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
[....send patches to get your name here....]

View File

@ -3556,6 +3556,26 @@ qemu-kvm -net nic,model=? /dev/null
sub-element <code>label</code> are supported.
</p>
<h3><a name="customMetadata">Custom metadata</a></h3>
<pre>
...
&lt;metadata&gt;
&lt;app1:foo xmlns:app1="http://app1.org/app1/"&gt;..&lt;/app1:foo&gt;
&lt;app2:bar xmlns:app2="http://app1.org/app2/"&gt;..&lt;/app2:bar&gt;
&lt;/metadata&gt;
...</pre>
<dl>
<dt><code>metadata</code></dt>
<dd>The <code>metadata</code> node can be used by applications to
store custom metadata in the form of XML nodes/trees. Applications
must use custom namespaces on their XML nodes/trees, with only
one top-level element per namespace (if the application needs
structure, they should have sub-elements to their namespace
element). <span class="since">Since 0.9.10</span></dd>
</dl>
<h2><a name="examples">Example configs</a></h2>
<p>

View File

@ -25,6 +25,9 @@
<optional>
<ref name="description"/>
</optional>
<optional>
<ref name="metadata"/>
</optional>
<optional>
<ref name="cpu"/>
</optional>
@ -2942,6 +2945,29 @@
</element>
</define>
<define name="metadata">
<element name="metadata">
<zeroOrMore>
<ref name="customElement"/>
</zeroOrMore>
</element>
</define>
<define name="customElement">
<element>
<anyName/>
<zeroOrMore>
<choice>
<attribute>
<anyName/>
</attribute>
<text/>
<ref name="customElement"/>
</choice>
</zeroOrMore>
</element>
</define>
<!--
Type library

View File

@ -1500,6 +1500,8 @@ void virDomainDefFree(virDomainDefPtr def)
if (def->namespaceData && def->ns.free)
(def->ns.free)(def->namespaceData);
xmlFreeNode(def->metadata);
VIR_FREE(def);
}
@ -8072,6 +8074,11 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
def->os.smbios_mode = VIR_DOMAIN_SMBIOS_NONE; /* not present */
}
/* Extract custom metadata */
if ((node = virXPathNode("./metadata[1]", ctxt)) != NULL) {
def->metadata = xmlCopyNode(node, 1);
}
/* we have to make a copy of all of the callback pointers here since
* we won't have the virCaps structure available during free
*/
@ -8211,6 +8218,7 @@ virDomainDefParse(const char *xmlStr,
{
xmlDocPtr xml;
virDomainDefPtr def = NULL;
int keepBlanksDefault = xmlKeepBlanksDefault(0);
if ((xml = virXMLParse(filename, xmlStr, _("(domain_definition)")))) {
def = virDomainDefParseNode(caps, xml, xmlDocGetRootElement(xml),
@ -8218,6 +8226,7 @@ virDomainDefParse(const char *xmlStr,
xmlFreeDoc(xml);
}
xmlKeepBlanksDefault(keepBlanksDefault);
return def;
}
@ -8311,6 +8320,7 @@ virDomainObjParseFile(virCapsPtr caps,
{
xmlDocPtr xml;
virDomainObjPtr obj = NULL;
int keepBlanksDefault = xmlKeepBlanksDefault(0);
if ((xml = virXMLParseFile(filename))) {
obj = virDomainObjParseNode(caps, xml,
@ -8319,6 +8329,7 @@ virDomainObjParseFile(virCapsPtr caps,
xmlFreeDoc(xml);
}
xmlKeepBlanksDefault(keepBlanksDefault);
return obj;
}
@ -11833,6 +11844,30 @@ virDomainDefFormatInternal(virDomainDefPtr def,
goto cleanup;
}
/* Custom metadata comes at the end */
if (def->metadata) {
xmlBufferPtr xmlbuf;
int oldIndentTreeOutput = xmlIndentTreeOutput;
/* Indentation on output requires that we previously set
* xmlKeepBlanksDefault to 0 when parsing; also, libxml does 2
* spaces per level of indentation of intermediate elements,
* but no leading indentation before the starting element.
* Thankfully, libxml maps what looks like globals into
* thread-local uses, so we are thread-safe. */
xmlIndentTreeOutput = 1;
xmlbuf = xmlBufferCreate();
if (xmlNodeDump(xmlbuf, def->metadata->doc, def->metadata,
virBufferGetIndent(buf, false) / 2 + 1, 1) < 0) {
xmlBufferFree(xmlbuf);
xmlIndentTreeOutput = oldIndentTreeOutput;
goto cleanup;
}
virBufferAsprintf(buf, " %s\n", (char *) xmlBufferContent(xmlbuf));
xmlBufferFree(xmlbuf);
xmlIndentTreeOutput = oldIndentTreeOutput;
}
virBufferAddLit(buf, "</domain>\n");
if (virBufferError(buf))
@ -12517,11 +12552,14 @@ virDomainSnapshotDefParseString(const char *xmlStr,
struct timeval tv;
int active;
char *tmp;
int keepBlanksDefault = xmlKeepBlanksDefault(0);
xml = virXMLParseCtxt(NULL, xmlStr, _("(domain_snapshot)"), &ctxt);
if (!xml) {
xmlKeepBlanksDefault(keepBlanksDefault);
return NULL;
}
xmlKeepBlanksDefault(keepBlanksDefault);
if (VIR_ALLOC(def) < 0) {
virReportOOMError();

View File

@ -1525,6 +1525,9 @@ struct _virDomainDef {
void *namespaceData;
virDomainXMLNamespace ns;
/* Application-specific custom metadata */
xmlNodePtr metadata;
};
enum virDomainTaintFlags {

View File

@ -0,0 +1,38 @@
<domainsnapshot>
<name>my snap name</name>
<description>!@#$%^</description>
<state>running</state>
<parent>
<name>earlier_snap</name>
</parent>
<creationTime>1272917631</creationTime>
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory>219100</memory>
<currentMemory>219100</currentMemory>
<vcpu cpuset='1-4,8-20,525'>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'/>
<memballoon model='virtio'/>
</devices>
<metadata>
<app1:foo xmlns:app1="http://foo.org/">fooish</app1:foo>
<app2:bar xmlns:app2="http://bar.com/" maman="baz">barish</app2:bar>
</metadata>
</domain>
</domainsnapshot>

View File

@ -109,6 +109,7 @@ mymain(void)
DO_TEST("noparent_nodescription_noactive", NULL, 0);
DO_TEST("noparent_nodescription", NULL, 1);
DO_TEST("noparent", "9d37b878-a7cc-9f9a-b78f-49b3abad25a8", 0);
DO_TEST("metadata", "c7a5fdbd-edaf-9455-926a-d65c16db1809", 0);
virCapabilitiesFree(driver.caps);

View File

@ -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 -name QEMUGuest1 -nographic -monitor unix:/tmp/test-monitor,\
server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial \
none -parallel none -usb

View File

@ -0,0 +1,30 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory>219100</memory>
<currentMemory>219100</currentMemory>
<vcpu cpuset='1-4,8-20,525'>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'/>
<memballoon model='virtio'/>
</devices>
<!-- intentional mis-indentation -->
<metadata>
<app1:foo xmlns:app1="http://foo.org/">fooish</app1:foo>
<app2:bar xmlns:app2="http://bar.com/" maman="baz">barish</app2:bar>
</metadata>
</domain>

View File

@ -0,0 +1,29 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory>219100</memory>
<currentMemory>219100</currentMemory>
<vcpu cpuset='1-4,8-20,525'>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'/>
<memballoon model='virtio'/>
</devices>
<metadata>
<app1:foo xmlns:app1="http://foo.org/">fooish</app1:foo>
<app2:bar xmlns:app2="http://bar.com/" maman="baz">barish</app2:bar>
</metadata>
</domain>

View File

@ -210,6 +210,8 @@ mymain(void)
DO_TEST_DIFFERENT("graphics-listen-network2");
DO_TEST_DIFFERENT("graphics-spice-timeout");
DO_TEST_DIFFERENT("metadata");
virCapabilitiesFree(driver.caps);
return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);