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