898951
From 25d339a412b1a3d3436d3ff3c9ed63139c8f2428 Mon Sep 17 00:00:00 2001
898951
Message-Id: <25d339a412b1a3d3436d3ff3c9ed63139c8f2428@dist-git>
898951
From: Peter Krempa <pkrempa@redhat.com>
898951
Date: Thu, 22 Jan 2015 15:53:45 +0100
898951
Subject: [PATCH] conf: Add support for requesting of XML metadata via the API
898951
898951
https://bugzilla.redhat.com/show_bug.cgi?id=1184929
898951
898951
The virDomainGetMetadata function was designed to support also retrieval
898951
of app specific metadata from the <metadata> element. This functionality
898951
was never implemented originally.
898951
898951
(cherry picked from commit ac38bff077642daa17f9a82480062ebef4c11a7b)
898951
898951
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
898951
---
898951
 src/conf/domain_conf.c   |  19 ++++----
898951
 src/libvirt_private.syms |   1 +
898951
 src/util/virxml.c        | 122 +++++++++++++++++++++++++++++++++++++++++++++++
898951
 src/util/virxml.h        |   7 +++
898951
 4 files changed, 140 insertions(+), 9 deletions(-)
898951
898951
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
898951
index 6817e0e..c104218 100644
898951
--- a/src/conf/domain_conf.c
898951
+++ b/src/conf/domain_conf.c
898951
@@ -18987,7 +18987,6 @@ virDomainObjGetMetadata(virDomainObjPtr vm,
898951
                         unsigned int flags)
898951
 {
898951
     virDomainDefPtr def;
898951
-    char *field = NULL;
898951
     char *ret = NULL;
898951
 
898951
     virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
898951
@@ -19002,17 +19001,21 @@ virDomainObjGetMetadata(virDomainObjPtr vm,
898951
 
898951
     switch ((virDomainMetadataType) type) {
898951
     case VIR_DOMAIN_METADATA_DESCRIPTION:
898951
-        field = def->description;
898951
+        if (VIR_STRDUP(ret, def->description) < 0)
898951
+            goto cleanup;
898951
         break;
898951
 
898951
     case VIR_DOMAIN_METADATA_TITLE:
898951
-        field = def->title;
898951
+        if (VIR_STRDUP(ret, def->title) < 0)
898951
+            goto cleanup;
898951
         break;
898951
 
898951
     case VIR_DOMAIN_METADATA_ELEMENT:
898951
-        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
898951
-                       _("<metadata> element is not yet supported"));
898951
-        goto cleanup;
898951
+        if (!def->metadata)
898951
+            break;
898951
+
898951
+        if (virXMLExtractNamespaceXML(def->metadata, uri, &ret) < 0)
898951
+            goto cleanup;
898951
         break;
898951
 
898951
     default:
898951
@@ -19022,12 +19025,10 @@ virDomainObjGetMetadata(virDomainObjPtr vm,
898951
         break;
898951
     }
898951
 
898951
-    if (!field)
898951
+    if (!ret)
898951
         virReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
898951
                        _("Requested metadata element is not present"));
898951
 
898951
-    ignore_value(VIR_STRDUP(ret, field));
898951
-
898951
 cleanup:
898951
     return ret;
898951
 }
898951
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
898951
index 3df4379..1fbee18 100644
898951
--- a/src/libvirt_private.syms
898951
+++ b/src/libvirt_private.syms
898951
@@ -2140,6 +2140,7 @@ virUUIDParse;
898951
 
898951
 # util/virxml.h
898951
 virXMLChildElementCount;
898951
+virXMLExtractNamespaceXML;
898951
 virXMLNodeToString;
898951
 virXMLParseHelper;
898951
 virXMLPickShellSafeComment;
898951
diff --git a/src/util/virxml.c b/src/util/virxml.c
898951
index 9bb8bf0..9048d78 100644
898951
--- a/src/util/virxml.c
898951
+++ b/src/util/virxml.c
898951
@@ -928,3 +928,125 @@ cleanup:
898951
 
898951
      return ret;
898951
 }
898951
+
898951
+typedef int (*virXMLForeachCallback)(xmlNodePtr node,
898951
+                                     void *opaque);
898951
+
898951
+static int
898951
+virXMLForeachNode(xmlNodePtr root,
898951
+                  virXMLForeachCallback cb,
898951
+                  void *opaque);
898951
+
898951
+static int
898951
+virXMLForeachNode(xmlNodePtr root,
898951
+                  virXMLForeachCallback cb,
898951
+                  void *opaque)
898951
+{
898951
+    xmlNodePtr next;
898951
+    int ret;
898951
+
898951
+    for (next = root; next; next = next->next) {
898951
+        if ((ret = cb(next, opaque)) != 0)
898951
+            return ret;
898951
+
898951
+        /* recurse into children */
898951
+        if (next->children) {
898951
+            if ((ret = virXMLForeachNode(next->children, cb, opaque)) != 0)
898951
+                return ret;
898951
+        }
898951
+    }
898951
+
898951
+    return 0;
898951
+}
898951
+
898951
+
898951
+static int
898951
+virXMLRemoveElementNamespace(xmlNodePtr node,
898951
+                             void *opaque)
898951
+{
898951
+    const char *uri = opaque;
898951
+
898951
+    if (node->ns &&
898951
+        STREQ_NULLABLE((const char *)node->ns->href, uri))
898951
+        xmlSetNs(node, NULL);
898951
+    return 0;
898951
+}
898951
+
898951
+
898951
+xmlNodePtr
898951
+virXMLFindChildNodeByNs(xmlNodePtr root,
898951
+                        const char *uri)
898951
+{
898951
+    xmlNodePtr next;
898951
+
898951
+    for (next = root->children; next; next = next->next) {
898951
+        if (next->ns &&
898951
+            STREQ_NULLABLE((const char *) next->ns->href, uri))
898951
+            return next;
898951
+    }
898951
+
898951
+    return NULL;
898951
+}
898951
+
898951
+
898951
+/**
898951
+ * virXMLExtractNamespaceXML: extract a sub-namespace of XML as string
898951
+ */
898951
+int
898951
+virXMLExtractNamespaceXML(xmlNodePtr root,
898951
+                          const char *uri,
898951
+                          char **doc)
898951
+{
898951
+    xmlNodePtr node;
898951
+    xmlNodePtr nodeCopy = NULL;
898951
+    xmlNsPtr actualNs;
898951
+    xmlNsPtr prevNs = NULL;
898951
+    char *xmlstr = NULL;
898951
+    int ret = -1;
898951
+
898951
+    if (!(node = virXMLFindChildNodeByNs(root, uri))) {
898951
+        /* node not found */
898951
+        ret = 1;
898951
+        goto cleanup;
898951
+    }
898951
+
898951
+    /* copy the node so that we can modify the namespace */
898951
+    if (!(nodeCopy = xmlCopyNode(node, 1))) {
898951
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
898951
+                       _("Failed to copy XML node"));
898951
+        goto cleanup;
898951
+    }
898951
+
898951
+    virXMLForeachNode(nodeCopy, virXMLRemoveElementNamespace,
898951
+                      (void *)uri);
898951
+
898951
+    /* remove the namespace declaration
898951
+     *  - it's only a single linked list ... doh */
898951
+    for (actualNs = nodeCopy->nsDef; actualNs; actualNs = actualNs->next) {
898951
+        if (STREQ_NULLABLE((const char *)actualNs->href, uri)) {
898951
+
898951
+            /* unlink */
898951
+            if (prevNs)
898951
+                prevNs->next = actualNs->next;
898951
+            else
898951
+                nodeCopy->nsDef = actualNs->next;
898951
+
898951
+            /* discard */
898951
+            xmlFreeNs(actualNs);
898951
+            break;
898951
+        }
898951
+
898951
+        prevNs = actualNs;
898951
+    }
898951
+
898951
+    if (!(xmlstr = virXMLNodeToString(nodeCopy->doc, nodeCopy)))
898951
+        goto cleanup;
898951
+
898951
+    ret = 0;
898951
+
898951
+cleanup:
898951
+    if (doc)
898951
+        *doc = xmlstr;
898951
+    xmlFreeNode(nodeCopy);
898951
+    return ret;
898951
+}
898951
diff --git a/src/util/virxml.h b/src/util/virxml.h
898951
index bb34069..7dc6c9d 100644
898951
--- a/src/util/virxml.h
898951
+++ b/src/util/virxml.h
898951
@@ -165,4 +165,11 @@ int virXMLSaveFile(const char *path,
898951
 
898951
 char *virXMLNodeToString(xmlDocPtr doc, xmlNodePtr node);
898951
 
898951
+xmlNodePtr virXMLFindChildNodeByNs(xmlNodePtr root,
898951
+                                   const char *uri);
898951
+
898951
+int virXMLExtractNamespaceXML(xmlNodePtr root,
898951
+                              const char *uri,
898951
+                              char **doc);
898951
+
898951
 #endif                          /* __VIR_XML_H__ */
898951
-- 
898951
2.2.1
898951