[libvirt] [PATCH 09/14] conf: Add support for requesting of XML metadata via the API

Peter Krempa pkrempa at redhat.com
Tue Sep 10 10:15:45 UTC 2013


The virDomainGetMetadata function was designed to support also retrieval
of app specific metadata from the <metadata> element. This functionality
was never implemented originally.
---
 src/conf/domain_conf.c   |  19 ++++----
 src/libvirt_private.syms |   1 +
 src/util/virxml.c        | 122 +++++++++++++++++++++++++++++++++++++++++++++++
 src/util/virxml.h        |   7 +++
 4 files changed, 140 insertions(+), 9 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index aa07056..4269690 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -18538,7 +18538,6 @@ virDomainObjGetMetadata(virDomainObjPtr vm,
                         unsigned int flags)
 {
     virDomainDefPtr def;
-    char *field = NULL;
     char *ret = NULL;

     virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
@@ -18553,17 +18552,21 @@ virDomainObjGetMetadata(virDomainObjPtr vm,

     switch ((virDomainMetadataType) type) {
     case VIR_DOMAIN_METADATA_DESCRIPTION:
-        field = def->description;
+        if (VIR_STRDUP(ret, def->description) < 0)
+            goto cleanup;
         break;

     case VIR_DOMAIN_METADATA_TITLE:
-        field = def->title;
+        if (VIR_STRDUP(ret, def->title) < 0)
+            goto cleanup;
         break;

     case VIR_DOMAIN_METADATA_ELEMENT:
-        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                       _("<metadata> element is not yet supported"));
-        goto cleanup;
+        if (!def->metadata)
+            break;
+
+        if (virXMLExtractNamespaceXML(def->metadata, uri, &ret) < 0)
+            goto cleanup;
         break;

     default:
@@ -18573,12 +18576,10 @@ virDomainObjGetMetadata(virDomainObjPtr vm,
         break;
     }

-    if (!field)
+    if (!ret)
         virReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
                        _("Requested metadata element is not present"));

-    ignore_value(VIR_STRDUP(ret, field));
-
 cleanup:
     return ret;
 }
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 18e9a4b..b643c51 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2091,6 +2091,7 @@ virUUIDParse;

 # util/virxml.h
 virXMLChildElementCount;
+virXMLExtractNamespaceXML;
 virXMLNodeDump;
 virXMLParseHelper;
 virXMLPickShellSafeComment;
diff --git a/src/util/virxml.c b/src/util/virxml.c
index 44d6f27..0fac931 100644
--- a/src/util/virxml.c
+++ b/src/util/virxml.c
@@ -928,3 +928,125 @@ cleanup:

      return ret;
 }
+
+typedef int (*virXMLForeachCallback)(xmlNodePtr node,
+                                     void *opaque);
+
+static int
+virXMLForeachNode(xmlNodePtr root,
+                  virXMLForeachCallback cb,
+                  void *opaque);
+
+static int
+virXMLForeachNode(xmlNodePtr root,
+                  virXMLForeachCallback cb,
+                  void *opaque)
+{
+    xmlNodePtr next;
+    int ret;
+
+    for (next = root; next; next = next->next) {
+        if ((ret = cb(next, opaque)) != 0)
+            return ret;
+
+        /* recurse into children */
+        if (next->children) {
+            if ((ret = virXMLForeachNode(next->children, cb, opaque)) != 0)
+                return ret;
+        }
+    }
+
+    return 0;
+}
+
+
+static int
+virXMLRemoveElementNamespace(xmlNodePtr node,
+                             void *opaque)
+{
+    const char *uri = opaque;
+
+    if (node->ns &&
+        STREQ_NULLABLE((const char *)node->ns->href, uri))
+        xmlSetNs(node, NULL);
+    return 0;
+}
+
+
+xmlNodePtr
+virXMLFindChildNodeByNs(xmlNodePtr root,
+                        const char *uri)
+{
+    xmlNodePtr next;
+
+    for (next = root->children; next; next = next->next) {
+        if (next->ns &&
+            STREQ_NULLABLE((const char *) next->ns->href, uri))
+            return next;
+    }
+
+    return NULL;
+}
+
+
+/**
+ * virXMLExtractNamespaceXML: extract a sub-namespace of a XML as string
+ */
+int
+virXMLExtractNamespaceXML(xmlNodePtr root,
+                          const char *uri,
+                          char **doc)
+{
+    xmlNodePtr node;
+    xmlNodePtr nodeCopy = NULL;
+    xmlNsPtr actualNs;
+    xmlNsPtr prevNs = NULL;
+    char *xmlstr = NULL;
+    int ret = -1;
+
+    if (!(node = virXMLFindChildNodeByNs(root, uri))) {
+        /* node not found */
+        ret = 1;
+        goto cleanup;
+    }
+
+    /* copy the node so that we can modify the namespace */
+    if (!(nodeCopy = xmlCopyNode(node, 1))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Failed to copy XML node"));
+        goto cleanup;
+    }
+
+    virXMLForeachNode(nodeCopy, virXMLRemoveElementNamespace,
+                      (void *)uri);
+
+    /* remove the namespace declaration
+     *  - it's only a single linked list ... doh */
+    for (actualNs = nodeCopy->nsDef; actualNs; actualNs = actualNs->next) {
+        if (STREQ_NULLABLE((const char *)actualNs->href, uri)) {
+
+            /* unlink */
+            if (prevNs)
+                prevNs->next = actualNs->next;
+            else
+                nodeCopy->nsDef = actualNs->next;
+
+            /* discard */
+            xmlFreeNs(actualNs);
+            break;
+        }
+
+        prevNs = actualNs;
+    }
+
+    if (!(xmlstr = virXMLNodeDump(nodeCopy->doc, nodeCopy)))
+        goto cleanup;
+
+    ret = 0;
+
+cleanup:
+    if (doc)
+        *doc = xmlstr;
+    xmlFreeNode(nodeCopy);
+    return ret;
+}
diff --git a/src/util/virxml.h b/src/util/virxml.h
index 9165cb1..aab29fb 100644
--- a/src/util/virxml.h
+++ b/src/util/virxml.h
@@ -165,4 +165,11 @@ int virXMLSaveFile(const char *path,

 char *virXMLNodeDump(xmlDocPtr doc, xmlNodePtr node);

+xmlNodePtr virXMLFindChildNodeByNs(xmlNodePtr root,
+                                   const char *uri);
+
+int virXMLExtractNamespaceXML(xmlNodePtr root,
+                              const char *uri,
+                              char **doc);
+
 #endif                          /* __VIR_XML_H__ */
-- 
1.8.3.2




More information about the libvir-list mailing list