snapshot: Add virDomainSnapshotObjListParse

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@redhat.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
This commit is contained in:
Eric Blake 2019-03-04 21:26:38 -06:00
parent 1e90fa89d1
commit 1b57269cbc
3 changed files with 118 additions and 0 deletions

View File

@ -507,6 +507,116 @@ 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)"))))
return -1;
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;
}
xmlXPathFreeContext(ctxt);
xmlFreeDoc(xml);
xmlKeepBlanksDefault(keepBlanksDefault);
return ret;
}
/**
* virDomainSnapshotDefAssignExternalNames:
* @def: snapshot def object

View File

@ -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,

View File

@ -900,6 +900,7 @@ virDomainSnapshotObjListFree;
virDomainSnapshotObjListGetNames;
virDomainSnapshotObjListNew;
virDomainSnapshotObjListNum;
virDomainSnapshotObjListParse;
virDomainSnapshotObjListRemove;
virDomainSnapshotRedefinePrep;
virDomainSnapshotStateTypeFromString;