From 25d339a412b1a3d3436d3ff3c9ed63139c8f2428 Mon Sep 17 00:00:00 2001 Message-Id: <25d339a412b1a3d3436d3ff3c9ed63139c8f2428@dist-git> From: Peter Krempa Date: Thu, 22 Jan 2015 15:53:45 +0100 Subject: [PATCH] conf: Add support for requesting of XML metadata via the API https://bugzilla.redhat.com/show_bug.cgi?id=1184929 The virDomainGetMetadata function was designed to support also retrieval of app specific metadata from the element. This functionality was never implemented originally. (cherry picked from commit ac38bff077642daa17f9a82480062ebef4c11a7b) Signed-off-by: Jiri Denemark --- 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 6817e0e..c104218 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -18987,7 +18987,6 @@ virDomainObjGetMetadata(virDomainObjPtr vm, unsigned int flags) { virDomainDefPtr def; - char *field = NULL; char *ret = NULL; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | @@ -19002,17 +19001,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", - _(" element is not yet supported")); - goto cleanup; + if (!def->metadata) + break; + + if (virXMLExtractNamespaceXML(def->metadata, uri, &ret) < 0) + goto cleanup; break; default: @@ -19022,12 +19025,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 3df4379..1fbee18 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2140,6 +2140,7 @@ virUUIDParse; # util/virxml.h virXMLChildElementCount; +virXMLExtractNamespaceXML; virXMLNodeToString; virXMLParseHelper; virXMLPickShellSafeComment; diff --git a/src/util/virxml.c b/src/util/virxml.c index 9bb8bf0..9048d78 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 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 = virXMLNodeToString(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 bb34069..7dc6c9d 100644 --- a/src/util/virxml.h +++ b/src/util/virxml.h @@ -165,4 +165,11 @@ int virXMLSaveFile(const char *path, char *virXMLNodeToString(xmlDocPtr doc, xmlNodePtr node); +xmlNodePtr virXMLFindChildNodeByNs(xmlNodePtr root, + const char *uri); + +int virXMLExtractNamespaceXML(xmlNodePtr root, + const char *uri, + char **doc); + #endif /* __VIR_XML_H__ */ -- 2.2.1