Add a new function to make it possible to parse a list of snapshots
at once. This is a counterpart to the previous 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 existing REDEFINE code uses virDomainSnapshotRedefinePrep()
for some sanity checking - much of that checking involves parent/child
relationships (which make sense when doing one element at a time and
worrying about replacement), but where this patch gets away with the
much simpler final call to virDomainSnapshotUpdateRelations() (for
all relationship checking after the end, 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). All other domain-agnostic sanity checks used
during a redefinition are copied here.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
src/conf/snapshot_conf.h | 7 ++
src/conf/snapshot_conf.c | 135 +++++++++++++++++++++++++++++++++++++++
src/libvirt_private.syms | 1 +
3 files changed, 143 insertions(+)
diff --git a/src/conf/snapshot_conf.h b/src/conf/snapshot_conf.h
index 19ab75f895..6a92241fe6 100644
--- a/src/conf/snapshot_conf.h
+++ b/src/conf/snapshot_conf.h
@@ -117,6 +117,13 @@ virDomainSnapshotDefPtr virDomainSnapshotDefParseNode(xmlDocPtr xml,
virCapsPtr caps,
virDomainXMLOptionPtr xmlopt,
unsigned int flags);
+int virDomainSnapshotDefParseList(const char *xmlSstr,
+ 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 963dc10247..61e26726e9 100644
--- a/src/conf/snapshot_conf.c
+++ b/src/conf/snapshot_conf.c
@@ -426,6 +426,141 @@ virDomainSnapshotDefParseString(const char *xmlStr,
}
+int virDomainSnapshotDefParseList(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;
+ char *current = NULL;
+ int n;
+ size_t i;
+ VIR_AUTOFREE(xmlNodePtr *) nodes = NULL;
+ int keepBlanksDefault = xmlKeepBlanksDefault(0);
+
+ 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;
+ int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
+ bool align_match = true;
+ bool offline;
+
+ def = virDomainSnapshotDefParseNode(xml, nodes[i], caps, xmlopt, flags);
+ if (!def)
+ goto cleanup;
+ if (!(snap = virDomainSnapshotAssignDef(snapshots, def))) {
+ virDomainSnapshotDefFree(def);
+ goto cleanup;
+ }
+ /* Sanity checking, similar to virDomainSnapshotRedefinePrep */
+ offline = def->state == VIR_DOMAIN_DISK_SNAPSHOT ||
+ virDomainSnapshotDefIsExternal(def);
+ if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) && !offline) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("disk-only flag for snapshot %s requires "
+ "disk-snapshot state"),
+ def->name);
+ goto cleanup;
+ }
+ if (def->dom) {
+ if (memcmp(def->dom->uuid, domain_uuid, VIR_UUID_BUFLEN)) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ virUUIDFormat(domain_uuid, uuidstr);
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("definition for snapshot %s must use uuid
%s"),
+ def->name, uuidstr);
+ goto cleanup;
+ }
+ if (offline ||
+ def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
+ align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
+ align_match = false;
+ }
+ if (virDomainSnapshotAlignDisks(def, align_location,
+ align_match) < 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 c623737c30..96f54a97fe 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -881,6 +881,7 @@ virDomainSnapshotAssignDef;
virDomainSnapshotDefFormat;
virDomainSnapshotDefFree;
virDomainSnapshotDefIsExternal;
+virDomainSnapshotDefParseList;
virDomainSnapshotDefParseString;
virDomainSnapshotDropParent;
virDomainSnapshotFindByName;
--
2.20.1