[libvirt] [PATCH v3 11/18] snapshot: Add virDomainSnapshotObjListParse

Eric Blake eblake at redhat.com
Tue Mar 5 03:34:38 UTC 2019


Add a new function to make it possible to parse a list of snapshots
at once.  This is a counterpart to an earlier patch making it
possible to produce all snapshots in a single XML string, and
intentionally parses the same top-level element <snapshots> with
an optional attribute current='name'.

Note that since we know we started with no relations at all, and
since checking parent relationships per-snapshot is not viable as
we don't control which order the snapshots appear in, that we are
fine with doing a final pass to update all parent/child
relationships among the definitions.

Signed-off-by: Eric Blake <eblake at redhat.com>
---
 src/conf/snapshot_conf.h |   7 +++
 src/conf/snapshot_conf.c | 111 +++++++++++++++++++++++++++++++++++++++
 src/libvirt_private.syms |   1 +
 3 files changed, 119 insertions(+)

diff --git a/src/conf/snapshot_conf.h b/src/conf/snapshot_conf.h
index 69a7750b0b..f8af991907 100644
--- a/src/conf/snapshot_conf.h
+++ b/src/conf/snapshot_conf.h
@@ -132,6 +132,13 @@ virDomainSnapshotDefPtr virDomainSnapshotDefParseNode(xmlDocPtr xml,
                                                       virCapsPtr caps,
                                                       virDomainXMLOptionPtr xmlopt,
                                                       unsigned int flags);
+int virDomainSnapshotObjListParse(const char *xmlStr,
+                                  const unsigned char *domain_uuid,
+                                  virDomainSnapshotObjListPtr snapshots,
+                                  virDomainSnapshotObjPtr *current_snap,
+                                  virCapsPtr caps,
+                                  virDomainXMLOptionPtr xmlopt,
+                                  unsigned int flags);
 void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def);
 char *virDomainSnapshotDefFormat(const char *uuidstr,
                                  virDomainSnapshotDefPtr def,
diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c
index a5b05eadf4..52742d82d6 100644
--- a/src/conf/snapshot_conf.c
+++ b/src/conf/snapshot_conf.c
@@ -507,6 +507,117 @@ virDomainSnapshotRedefineValidate(virDomainSnapshotDefPtr def,
 }


+/* Parse a <snapshots> XML entry into snapshots, which must start empty.
+ * Any <domain> sub-elements of a <domainsnapshot> must match domain_uuid.
+ */
+int
+virDomainSnapshotObjListParse(const char *xmlStr,
+                              const unsigned char *domain_uuid,
+                              virDomainSnapshotObjListPtr snapshots,
+                              virDomainSnapshotObjPtr *current_snap,
+                              virCapsPtr caps,
+                              virDomainXMLOptionPtr xmlopt,
+                              unsigned int flags)
+{
+    int ret = -1;
+    xmlDocPtr xml;
+    xmlNodePtr root;
+    xmlXPathContextPtr ctxt = NULL;
+    int n;
+    size_t i;
+    int keepBlanksDefault = xmlKeepBlanksDefault(0);
+    VIR_AUTOFREE(xmlNodePtr *) nodes = NULL;
+    VIR_AUTOFREE(char *) current = NULL;
+
+    if (!(flags & VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE) ||
+        (flags & VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("incorrect flags for bulk parse"));
+        return -1;
+    }
+    if (snapshots->metaroot.nchildren || *current_snap) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("bulk define of snapshots only possible with "
+                         "no existing snapshot"));
+        return -1;
+    }
+
+    if (!(xml = virXMLParse(NULL, xmlStr, _("(domain_snapshot)"))))
+        goto cleanup;
+
+    root = xmlDocGetRootElement(xml);
+    if (!virXMLNodeNameEqual(root, "snapshots")) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("unexpected root element <%s>, "
+                         "expecting <snapshots>"), root->name);
+        goto cleanup;
+    }
+    ctxt = xmlXPathNewContext(xml);
+    if (ctxt == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+    ctxt->node = root;
+    current = virXMLPropString(root, "current");
+
+    if ((n = virXPathNodeSet("./domainsnapshot", ctxt, &nodes)) < 0)
+        goto cleanup;
+    if (!n) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("expected at least one <domainsnapshot> child"));
+        goto cleanup;
+    }
+
+    for (i = 0; i < n; i++) {
+        virDomainSnapshotDefPtr def;
+        virDomainSnapshotObjPtr snap;
+
+        def = virDomainSnapshotDefParseNode(xml, nodes[i], caps, xmlopt, flags);
+        if (!def)
+            goto cleanup;
+        if (!(snap = virDomainSnapshotAssignDef(snapshots, def))) {
+            virDomainSnapshotDefFree(def);
+            goto cleanup;
+        }
+        if (virDomainSnapshotRedefineValidate(def, domain_uuid, NULL, NULL,
+                                              flags) < 0)
+            goto cleanup;
+    }
+
+    if (virDomainSnapshotUpdateRelations(snapshots) < 0) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("<snapshots> contains inconsistent parent-child "
+                         "relationships"));
+        goto cleanup;
+    }
+
+    if (current) {
+        if (!(*current_snap = virDomainSnapshotFindByName(snapshots,
+                                                          current))) {
+            virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
+                           _("no snapshot matching current='%s'"), current);
+            goto cleanup;
+        }
+        (*current_snap)->def->current = true;
+    }
+
+    ret = 0;
+ cleanup:
+    if (ret < 0) {
+        /* There were no snapshots before this call; so on error, just
+         * blindly delete anything created before the failure. */
+        virHashRemoveAll(snapshots->objs);
+        snapshots->metaroot.nchildren = 0;
+        snapshots->metaroot.first_child = NULL;
+    }
+    VIR_FREE(current);
+    xmlXPathFreeContext(ctxt);
+    xmlFreeDoc(xml);
+    xmlKeepBlanksDefault(keepBlanksDefault);
+    return ret;
+}
+
+
 /**
  * virDomainSnapshotDefAssignExternalNames:
  * @def: snapshot def object
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 35e0c6d9dc..395e1f8764 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -899,6 +899,7 @@ virDomainSnapshotObjListFree;
 virDomainSnapshotObjListGetNames;
 virDomainSnapshotObjListNew;
 virDomainSnapshotObjListNum;
+virDomainSnapshotObjListParse;
 virDomainSnapshotObjListRemove;
 virDomainSnapshotRedefinePrep;
 virDomainSnapshotStateTypeFromString;
-- 
2.20.1




More information about the libvir-list mailing list