From: Brandon Bennett <bbennett(a)fb.com>
This replicates the metadata field found in the domain configuration
and adds it to the network configuration XML.
---
docs/formatnetwork.html.in | 13 +++++++++++++
docs/schemas/basictypes.rng | 23 +++++++++++++++++++++++
docs/schemas/domaincommon.rng | 23 -----------------------
docs/schemas/network.rng | 5 +++++
src/conf/network_conf.c | 35 ++++++++++++++++++++++++++++++++++-
src/conf/network_conf.h | 3 +++
tests/networkxml2xmlin/metadata.xml | 10 ++++++++++
tests/networkxml2xmlout/metadata.xml | 10 ++++++++++
tests/networkxml2xmltest.c | 1 +
9 files changed, 99 insertions(+), 24 deletions(-)
create mode 100644 tests/networkxml2xmlin/metadata.xml
create mode 100644 tests/networkxml2xmlout/metadata.xml
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 1cea931..15ebf0c 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -38,6 +38,10 @@
<network ipv6='yes' trustGuestRxFilters='no'>
<name>default</name>
<uuid>3e3fce45-4f53-4fa7-bb32-11f34168b82b</uuid>
+ <metadata>
+ <app1:foo
xmlns:app1="http://app1.org/app1/">..</app1:foo&a...
+ <app2:bar
xmlns:app2="http://app1.org/app2/">..</app2:bar&a...
+ </metadata>
...</pre>
<dl>
@@ -54,6 +58,12 @@
The format must be RFC 4122 compliant, eg
<code>3e3fce45-4f53-4fa7-bb32-11f34168b82b</code>.
If omitted when defining/creating a new network, a random
UUID is generated. <span class="since">Since
0.3.0</span></dd>
+ <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
1.3.6</span></dd>
<dt><code>ipv6</code></dt>
<dd>When set to <code>yes</code>, the optional parameter
<code>ipv6</code> enables
@@ -73,6 +83,9 @@
override the setting in the network.</dd>
</dl>
++
+
+
<h3><a
name="elementsConnect">Connectivity</a></h3>
<p>
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index 83fd4ec..474ad77 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -495,4 +495,27 @@
</choice>
</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>
+
</grammar>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 162c2e0..78eb3f5 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -5338,29 +5338,6 @@
</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
-->
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 4edb6eb..b67a5ea 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -37,6 +37,11 @@
<text/>
</element>
+ <!-- <metadata> element -->
+ <optional>
+ <ref name="metadata"/>
+ </optional>
+
<!-- <uuid> element -->
<optional>
<element name="uuid"><ref
name="UUID"/></element>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 02b8cd7..4239c32 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -419,6 +419,9 @@ virNetworkDefFree(virNetworkDefPtr def)
virNetDevBandwidthFree(def->bandwidth);
virNetDevVlanClear(&def->vlan);
+
+ xmlFreeNode(def->metadata);
+
VIR_FREE(def);
}
@@ -2059,6 +2062,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
xmlNodePtr save = ctxt->node;
xmlNodePtr bandwidthNode = NULL;
xmlNodePtr vlanNode;
+ xmlNodePtr metadataNode = NULL;
if (VIR_ALLOC(def) < 0)
return NULL;
@@ -2388,8 +2392,12 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
}
break;
}
-
VIR_FREE(stp);
+
+ /* Extract custom metadata */
+ if ((metadataNode = virXPathNode("./metadata[1]", ctxt)) != NULL)
+ def->metadata = xmlCopyNode(metadataNode, 1);
+
ctxt->node = save;
return def;
@@ -2412,12 +2420,14 @@ virNetworkDefParse(const char *xmlStr,
{
xmlDocPtr xml;
virNetworkDefPtr def = NULL;
+ int keepBlanksDefault = xmlKeepBlanksDefault(0);
if ((xml = virXMLParse(filename, xmlStr, _("(network_definition)")))) {
def = virNetworkDefParseNode(xml, xmlDocGetRootElement(xml));
xmlFreeDoc(xml);
}
+ xmlKeepBlanksDefault(keepBlanksDefault);
return def;
}
@@ -2736,6 +2746,29 @@ virNetworkDefFormatBuf(virBufferPtr buf,
virUUIDFormat(uuid, uuidstr);
virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuidstr);
+ 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) < 0) {
+ xmlBufferFree(xmlbuf);
+ xmlIndentTreeOutput = oldIndentTreeOutput;
+ goto error;
+ }
+ virBufferAsprintf(buf, "%s\n", (char *) xmlBufferContent(xmlbuf));
+ xmlBufferFree(xmlbuf);
+ xmlIndentTreeOutput = oldIndentTreeOutput;
+ }
+
if (def->forward.type != VIR_NETWORK_FORWARD_NONE) {
const char *dev = NULL;
if (!def->forward.npfs)
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 0d34dfe..4481f60 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -253,6 +253,9 @@ struct _virNetworkDef {
virNetDevBandwidthPtr bandwidth;
virNetDevVlan vlan;
int trustGuestRxFilters; /* enum virTristateBool */
+
+ /* Application-specific custom metadata */
+ xmlNodePtr metadata;
};
typedef struct _virNetworkObj virNetworkObj;
diff --git a/tests/networkxml2xmlin/metadata.xml b/tests/networkxml2xmlin/metadata.xml
new file mode 100644
index 0000000..c075f93
--- /dev/null
+++ b/tests/networkxml2xmlin/metadata.xml
@@ -0,0 +1,10 @@
+<network>
+ <name>host-bridge-net</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a8e</uuid>
+ <forward mode='bridge'/>
+ <bridge name='br0'/>
+ <metadata>
+ <app1:foo
xmlns:app1="http://foo.org/">fooish</app1:foo>
+ <app2:bar
xmlns:app2="http://bar.com/"
maman="baz">barish</app2:bar>
+ </metadata>
+</network>
diff --git a/tests/networkxml2xmlout/metadata.xml b/tests/networkxml2xmlout/metadata.xml
new file mode 100644
index 0000000..a9364ab
--- /dev/null
+++ b/tests/networkxml2xmlout/metadata.xml
@@ -0,0 +1,10 @@
+<network>
+ <name>host-bridge-net</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a8e</uuid>
+ <metadata>
+ <app1:foo
xmlns:app1="http://foo.org/">fooish</app1:foo>
+ <app2:bar
xmlns:app2="http://bar.com/"
maman="baz">barish</app2:bar>
+ </metadata>
+ <forward mode='bridge'/>
+ <bridge name='br0'/>
+</network>
diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c
index d65f6aa..2a2c348 100644
--- a/tests/networkxml2xmltest.c
+++ b/tests/networkxml2xmltest.c
@@ -153,6 +153,7 @@ mymain(void)
DO_TEST("host-bridge-no-flood");
DO_TEST_PARSE_ERROR("hostdev-duplicate");
DO_TEST_PARSE_ERROR("passthrough-duplicate");
+ DO_TEST("metadata");
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
2.7.4