mirror of https://gitee.com/openkylin/libvirt.git
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:
parent
d19149dda8
commit
fa981fc945
1
AUTHORS
1
AUTHORS
|
@ -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....]
|
||||
|
||||
|
|
|
@ -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>
|
||||
...
|
||||
<metadata>
|
||||
<app1:foo xmlns:app1="http://app1.org/app1/">..</app1:foo>
|
||||
<app2:bar xmlns:app2="http://app1.org/app2/">..</app2:bar>
|
||||
</metadata>
|
||||
...</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>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1525,6 +1525,9 @@ struct _virDomainDef {
|
|||
|
||||
void *namespaceData;
|
||||
virDomainXMLNamespace ns;
|
||||
|
||||
/* Application-specific custom metadata */
|
||||
xmlNodePtr metadata;
|
||||
};
|
||||
|
||||
enum virDomainTaintFlags {
|
||||
|
|
|
@ -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>
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue