From ac38bff077642daa17f9a82480062ebef4c11a7b Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Fri, 6 Sep 2013 17:34:43 +0200 Subject: [PATCH] conf: Add support for requesting of XML metadata via the API The virDomainGetMetadata function was designed to support also retrieval of app specific metadata from the 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 087c351c54..509e7228af 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -18542,7 +18542,6 @@ virDomainObjGetMetadata(virDomainObjPtr vm, unsigned int flags) { virDomainDefPtr def; - char *field = NULL; char *ret = NULL; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | @@ -18557,17 +18556,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: @@ -18577,12 +18580,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 e6be9e0bb3..50e2f487a6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2092,6 +2092,7 @@ virUUIDParse; # util/virxml.h virXMLChildElementCount; +virXMLExtractNamespaceXML; virXMLNodeToString; virXMLParseHelper; virXMLPickShellSafeComment; diff --git a/src/util/virxml.c b/src/util/virxml.c index 6d1a2e9395..7a9bcf9cab 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 bb340699ba..7dc6c9d427 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__ */