]> xenbits.xensource.com Git - libvirt.git/commitdiff
Allow custom metadata in network configuration XML
authorBrandon Bennett <bbennett@fb.com>
Wed, 22 Jun 2016 22:05:50 +0000 (16:05 -0600)
committerLaine Stump <laine@laine.org>
Fri, 1 Jul 2016 17:05:25 +0000 (13:05 -0400)
    This replicates the metadata field found in the domain configuration
    and adds it to the network configuration XML.

docs/formatnetwork.html.in
docs/schemas/basictypes.rng
docs/schemas/domaincommon.rng
docs/schemas/network.rng
src/conf/network_conf.c
src/conf/network_conf.h
tests/networkxml2xmlin/metadata.xml [new file with mode: 0644]
tests/networkxml2xmlout/metadata.xml [new file with mode: 0644]
tests/networkxml2xmltest.c

index 1cea931da4eeefed15b8c7afe7c7c033bf6d8f15..a9226e52ea6bda637bfac37aa78a04ff8ef826ec 100644 (file)
       &lt;network ipv6='yes' trustGuestRxFilters='no'&gt;
         &lt;name&gt;default&lt;/name&gt;
         &lt;uuid&gt;3e3fce45-4f53-4fa7-bb32-11f34168b82b&lt;/uuid&gt;
+        &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>
         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 2.1.0</span></dd>
       <dt><code>ipv6</code></dt>
       <dd>When set to <code>yes</code>, the optional parameter
         <code>ipv6</code> enables
index 83fd4ec24dfef9c9a3fa8983c967c1e7fbe38e14..474ad77b2881352be13aef04c1f5d1219d0d3b34 100644 (file)
     </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>
index 563cb3c43781b0762b90237895370d4ceed386be..4314cbe6a2ae6631ade9a18004c7977a91fb1502 100644 (file)
     </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
     -->
index 4edb6eb31ad04b865716157a1845cd97656241bb..b67a5eae88701a094062efcdf3ac5b373b596c3f 100644 (file)
           <text/>
         </element>
 
+        <!-- <metadata> element -->
+        <optional>
+          <ref name="metadata"/>
+        </optional>
+
         <!-- <uuid> element -->
         <optional>
           <element name="uuid"><ref name="UUID"/></element>
index 2d904dfbe21b5fa0321b924acb17e946a5893f6c..a75ca7192c7929456fc95ddf3b47c1e0f7c416b5 100644 (file)
@@ -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;
@@ -2390,6 +2394,13 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
     }
 
     VIR_FREE(stp);
+
+    /* Extract custom metadata */
+    if ((metadataNode = virXPathNode("./metadata[1]", ctxt)) != NULL) {
+        def->metadata = xmlCopyNode(metadataNode, 1);
+        virXMLNodeSanitizeNamespaces(def->metadata);
+    }
+
     ctxt->node = save;
     return def;
 
@@ -2412,12 +2423,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 +2749,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)
index e7ce67424a84eba2158bb6ebbeb398b05863d00e..78148890c2991e2816a820de35550c0f4949b972 100644 (file)
@@ -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 (file)
index 0000000..c075f93
--- /dev/null
@@ -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 (file)
index 0000000..a9364ab
--- /dev/null
@@ -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>
index d65f6aaf7e175d8d1a4527ec41e5bcf1a5d63b73..2a2c3484302c4a926c0ad364bf750f8ed3a550df 100644 (file)
@@ -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;
 }