From: Brandon Bennett <bbennett@xxxxxx> 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> + <app2:bar xmlns:app2="http://app1.org/app2/">..</app2:bar> + </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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list