[libvirt] [PATCH 1/2] vz: add domain snapshots functionality

Nikolay Shirokovskiy nshirokovskiy at virtuozzo.com
Mon May 2 09:33:07 UTC 2016


This solution does not keep snapshots cache because vz sdk lacks good support
for snapshot related events.

Libvirt and vz sdk has different approach to snapshot ids. vz sdk always
auto generate them while libvirt has ability to specify id by user.
Thus I have no other choice rather than simply ignore ids set by user
or generated by libvirt.

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy at virtuozzo.com>
---
 src/libvirt_private.syms |   2 +
 src/vz/vz_driver.c       | 535 +++++++++++++++++++++++++++++++++++++++++++++++
 src/vz/vz_sdk.c          | 216 +++++++++++++++++++
 src/vz/vz_sdk.h          |   5 +
 src/vz/vz_utils.h        |   1 +
 5 files changed, 759 insertions(+)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0de35ef..81b9b1d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -808,7 +808,9 @@ virDomainSnapshotForEachDescendant;
 virDomainSnapshotIsExternal;
 virDomainSnapshotLocationTypeFromString;
 virDomainSnapshotLocationTypeToString;
+virDomainSnapshotObjListFree;
 virDomainSnapshotObjListGetNames;
+virDomainSnapshotObjListNew;
 virDomainSnapshotObjListNum;
 virDomainSnapshotObjListRemove;
 virDomainSnapshotRedefinePrep;
diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c
index 1497b72..03d3e53 100644
--- a/src/vz/vz_driver.c
+++ b/src/vz/vz_driver.c
@@ -1581,6 +1581,525 @@ static int vzDomainSetMemory(virDomainPtr domain, unsigned long memory)
     return vzDomainSetMemoryFlagsImpl(domain, memory, 0, false);
 }
 
+static virDomainSnapshotObjPtr
+vzSnapObjFromName(virDomainSnapshotObjListPtr snapshots, const char *name)
+{
+    virDomainSnapshotObjPtr snap = NULL;
+    snap = virDomainSnapshotFindByName(snapshots, name);
+    if (!snap)
+        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
+                       _("no domain snapshot with matching name '%s'"), name);
+
+    return snap;
+}
+
+static virDomainSnapshotObjPtr
+vzSnapObjFromSnapshot(virDomainSnapshotObjListPtr snapshots,
+                      virDomainSnapshotPtr snapshot)
+{
+    return vzSnapObjFromName(snapshots, snapshot->name);
+}
+
+static int
+vzCurrentSnapshotIterator(void *payload,
+                              const void *name ATTRIBUTE_UNUSED,
+                              void *data)
+{
+    virDomainSnapshotObjPtr snapshot = payload;
+    virDomainSnapshotObjPtr *current = data;
+
+    if (snapshot->def->current)
+        *current = snapshot;
+
+    return 0;
+}
+
+static virDomainSnapshotObjPtr
+vzFindCurrentSnapshot(virDomainSnapshotObjListPtr snapshots)
+{
+    virDomainSnapshotObjPtr current = NULL;
+
+    virDomainSnapshotForEach(snapshots, vzCurrentSnapshotIterator, &current);
+    return current;
+}
+
+static int
+vzDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
+{
+    virDomainObjPtr dom;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+    int n = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+    if (!(dom = vzDomObjFromDomain(domain)))
+        return -1;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    n = virDomainSnapshotObjListNum(snapshots, NULL, flags);
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+
+    return n;
+}
+
+static int
+vzDomainSnapshotListNames(virDomainPtr domain,
+                          char **names,
+                          int nameslen,
+                          unsigned int flags)
+{
+    virDomainObjPtr dom;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+    int n = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+    if (!(dom = vzDomObjFromDomain(domain)))
+        return -1;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    n = virDomainSnapshotObjListGetNames(snapshots, NULL, names, nameslen, flags);
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+
+    return n;
+}
+
+static int
+vzDomainListAllSnapshots(virDomainPtr domain,
+                         virDomainSnapshotPtr **snaps,
+                         unsigned int flags)
+{
+    virDomainObjPtr dom;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+    int n = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+    if (!(dom = vzDomObjFromDomain(domain)))
+        return -1;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    n = virDomainListSnapshots(snapshots, NULL, domain, snaps, flags);
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+
+    return n;
+}
+
+static char *
+vzDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+    virDomainObjPtr dom;
+    char *xml = NULL;
+    virDomainSnapshotObjPtr snap;
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    virDomainSnapshotObjListPtr snapshots = NULL;
+    vzConnPtr privconn = snapshot->domain->conn->privateData;
+
+    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
+
+    if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+        return NULL;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
+        goto cleanup;
+
+    virUUIDFormat(snapshot->domain->uuid, uuidstr);
+
+    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, privconn->driver->caps,
+                                     virDomainDefFormatConvertXMLFlags(flags),
+                                     0);
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+
+    return xml;
+}
+
+static int
+vzDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+    virDomainObjPtr dom;
+    virDomainSnapshotObjPtr snap;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+    int n = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+    if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+        return -1;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
+        goto cleanup;
+
+    n = virDomainSnapshotObjListNum(snapshots, snap, flags);
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+
+    return n;
+}
+
+static int
+vzDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
+                                  char **names,
+                                  int nameslen,
+                                  unsigned int flags)
+{
+    virDomainObjPtr dom;
+    virDomainSnapshotObjPtr snap;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+    int n = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+    if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+        return -1;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
+        goto cleanup;
+
+    n = virDomainSnapshotObjListGetNames(snapshots, snap, names, nameslen, flags);
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+
+    return n;
+}
+
+static int
+vzDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
+                                virDomainSnapshotPtr **snaps,
+                                unsigned int flags)
+{
+    virDomainObjPtr dom;
+    virDomainSnapshotObjPtr snap;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+    int n = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+    if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+        return -1;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
+        goto cleanup;
+
+    n = virDomainListSnapshots(snapshots, snap, snapshot->domain, snaps, flags);
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+
+    return n;
+}
+
+static virDomainSnapshotPtr
+vzDomainSnapshotLookupByName(virDomainPtr domain,
+                             const char *name,
+                             unsigned int flags)
+{
+    virDomainObjPtr dom;
+    virDomainSnapshotObjPtr snap;
+    virDomainSnapshotPtr snapshot = NULL;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+
+    virCheckFlags(0, NULL);
+
+    if (!(dom = vzDomObjFromDomain(domain)))
+        return NULL;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    if (!(snap = vzSnapObjFromName(snapshots, name)))
+        goto cleanup;
+
+    snapshot = virGetDomainSnapshot(domain, snap->def->name);
+
+ cleanup:
+    virObjectUnlock(dom);
+    virDomainSnapshotObjListFree(snapshots);
+
+    return snapshot;
+}
+
+static int
+vzDomainHasCurrentSnapshot(virDomainPtr domain, unsigned int flags)
+{
+    virDomainObjPtr dom;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    if (!(dom = vzDomObjFromDomain(domain)))
+        return -1;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    ret = vzFindCurrentSnapshot(snapshots) != NULL;
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+
+    return ret;
+}
+
+static virDomainSnapshotPtr
+vzDomainSnapshotGetParent(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+    virDomainObjPtr dom;
+    virDomainSnapshotObjPtr snap;
+    virDomainSnapshotPtr parent = NULL;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+
+    virCheckFlags(0, NULL);
+
+    if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+        return NULL;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
+        goto cleanup;
+
+    if (!snap->def->parent) {
+        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
+                       _("snapshot '%s' does not have a parent"),
+                       snap->def->name);
+        goto cleanup;
+    }
+
+    parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+
+    return parent;
+}
+
+static virDomainSnapshotPtr
+vzDomainSnapshotCurrent(virDomainPtr domain, unsigned int flags)
+{
+    virDomainObjPtr dom;
+    virDomainSnapshotPtr snapshot = NULL;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+    virDomainSnapshotObjPtr current;
+
+    virCheckFlags(0, NULL);
+
+    if (!(dom = vzDomObjFromDomain(domain)))
+        return NULL;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    if (!(current = vzFindCurrentSnapshot(snapshots))) {
+        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
+                       _("the domain does not have a current snapshot"));
+        goto cleanup;
+    }
+
+    snapshot = virGetDomainSnapshot(domain, current->def->name);
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+
+    return snapshot;
+}
+
+static int
+vzDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+    virDomainObjPtr dom;
+    int ret = -1;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+    virDomainSnapshotObjPtr current;
+
+    virCheckFlags(0, -1);
+
+    if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+        return -1;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    current = vzFindCurrentSnapshot(snapshots);
+    ret = current && STREQ(snapshot->name, current->def->name);
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+
+    return ret;
+}
+
+static int
+vzDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
+                              unsigned int flags)
+{
+    virDomainObjPtr dom;
+    int ret = -1;
+    virDomainSnapshotObjPtr snap;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+
+    virCheckFlags(0, -1);
+
+    if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+        return -1;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
+        goto cleanup;
+
+    ret = 1;
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+    return ret;
+}
+
+static virDomainSnapshotPtr
+vzDomainSnapshotCreateXML(virDomainPtr domain,
+                          const char *xmlDesc,
+                          unsigned int flags)
+{
+    virDomainSnapshotDefPtr def = NULL;
+    virDomainSnapshotPtr snapshot = NULL;
+    virDomainObjPtr dom;
+    vzConnPtr privconn = domain->conn->privateData;
+    vzDriverPtr driver = privconn->driver;
+    unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+    virDomainSnapshotObjPtr current;
+
+    virCheckFlags(0, NULL);
+
+    if (!(dom = vzDomObjFromDomain(domain)))
+        return NULL;
+
+    if (!(def = virDomainSnapshotDefParseString(xmlDesc, driver->caps,
+                                                driver->xmlopt, parse_flags)))
+        goto cleanup;
+
+    if (def->ndisks > 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("configuring disks is not supported for vz snapshots"));
+        goto cleanup;
+    }
+
+    if (def->memory) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("configuring memory location is not supported"));
+        goto cleanup;
+    }
+
+    /* snaphot name is ignored, it will be set to auto generated by sdk uuid */
+    if (prlsdkCreateSnapshot(dom, def->description) < 0)
+        goto cleanup;
+
+    if (!(snapshots = prlsdkLoadSnapshots(dom)))
+        goto cleanup;
+
+    if (!(current = vzFindCurrentSnapshot(snapshots))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("can't find created snapshot"));
+        goto cleanup;
+    }
+
+    /* hopefully new current snapshot is newly created one */
+    snapshot = virGetDomainSnapshot(domain, current->def->name);
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    virObjectUnlock(dom);
+    virDomainSnapshotDefFree(def);
+
+    return snapshot;
+}
+
+static int
+vzDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+    virDomainObjPtr dom;
+    int ret = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN, -1);
+
+    if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+        return -1;
+
+    ret = prlsdkDeleteSnapshot(dom, snapshot->name,
+                               flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN);
+
+    virObjectUnlock(dom);
+
+    return ret;
+}
+
+static int
+vzDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+    virDomainObjPtr dom;
+    int ret = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED, -1);
+
+    if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+        return -1;
+
+    ret = prlsdkSwitchToSnapshot(dom, snapshot->name,
+                                 flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED);
+
+    virObjectUnlock(dom);
+
+    return ret;
+}
+
 static virHypervisorDriver vzHypervisorDriver = {
     .name = "vz",
     .connectOpen = vzConnectOpen,            /* 0.10.0 */
@@ -1648,6 +2167,22 @@ static virHypervisorDriver vzHypervisorDriver = {
     .connectUnregisterCloseCallback = vzConnectUnregisterCloseCallback, /* 1.3.2 */
     .domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */
     .domainSetMemory = vzDomainSetMemory, /* 1.3.4 */
+    .domainSnapshotNum = vzDomainSnapshotNum, /* 1.3.5 */
+    .domainSnapshotListNames = vzDomainSnapshotListNames, /* 1.3.5 */
+    .domainListAllSnapshots = vzDomainListAllSnapshots, /* 1.3.5 */
+    .domainSnapshotGetXMLDesc = vzDomainSnapshotGetXMLDesc, /* 1.3.5 */
+    .domainSnapshotNumChildren = vzDomainSnapshotNumChildren, /* 1.3.5 */
+    .domainSnapshotListChildrenNames = vzDomainSnapshotListChildrenNames, /* 1.3.5 */
+    .domainSnapshotListAllChildren = vzDomainSnapshotListAllChildren, /* 1.3.5 */
+    .domainSnapshotLookupByName = vzDomainSnapshotLookupByName, /* 1.3.5 */
+    .domainHasCurrentSnapshot = vzDomainHasCurrentSnapshot, /* 1.3.5 */
+    .domainSnapshotGetParent = vzDomainSnapshotGetParent, /* 1.3.5 */
+    .domainSnapshotCurrent = vzDomainSnapshotCurrent, /* 1.3.5 */
+    .domainSnapshotIsCurrent = vzDomainSnapshotIsCurrent, /* 1.3.5 */
+    .domainSnapshotHasMetadata = vzDomainSnapshotHasMetadata, /* 1.3.5 */
+    .domainSnapshotCreateXML = vzDomainSnapshotCreateXML, /* 1.3.5 */
+    .domainSnapshotDelete = vzDomainSnapshotDelete, /* 1.3.5 */
+    .domainRevertToSnapshot = vzDomainRevertToSnapshot, /* 1.3.5 */
 };
 
 static virConnectDriver vzConnectDriver = {
diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c
index 8cc8430..23b9277 100644
--- a/src/vz/vz_sdk.c
+++ b/src/vz/vz_sdk.c
@@ -4267,3 +4267,219 @@ int prlsdkSetMemsize(virDomainObjPtr dom, unsigned int memsize)
  error:
     return -1;
 }
+
+static long long
+prlsdkParseDateTime(const char *str)
+{
+    struct tm tm;
+    const char *tmp;
+
+    tmp = strptime(str, "%Y-%m-%d %H:%M:%S", &tm);
+    if (!tmp || *tmp != '\0') {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unexpected DateTime format: '%s'"), str);
+        return -1;
+    }
+
+    return mktime(&tm);
+}
+
+static virDomainSnapshotObjListPtr
+prlsdkParseSnapshotTree(const char *treexml)
+{
+    virDomainSnapshotObjListPtr ret = NULL;
+    xmlDocPtr xml = NULL;
+    xmlXPathContextPtr ctxt = NULL;
+    xmlNodePtr root;
+    xmlNodePtr *nodes = NULL;
+    virDomainSnapshotDefPtr def = NULL;
+    virDomainSnapshotObjPtr snapshot;
+    virDomainSnapshotObjPtr current = NULL;
+    virDomainSnapshotObjListPtr snapshots = NULL;
+    char *xmlstr = NULL;
+    int n;
+    size_t i;
+
+    if (!(snapshots = virDomainSnapshotObjListNew()))
+        return NULL;
+
+    if (*treexml == '\0')
+        return snapshots;
+
+    if (!(xml = virXMLParse(NULL, treexml, _("(snapshot_tree)"))))
+        goto cleanup;
+
+    root = xmlDocGetRootElement(xml);
+    if (!xmlStrEqual(root->name, BAD_CAST "ParallelsSavedStates")) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unexpected root element: '%s'"), root->name);
+        goto cleanup;
+    }
+
+    ctxt = xmlXPathNewContext(xml);
+    if (ctxt == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+    ctxt->node = root;
+
+    if ((n = virXPathNodeSet("//SavedStateItem", ctxt, &nodes)) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("cannot extract snapshot nodes"));
+        goto cleanup;
+    }
+
+    for (i = 0; i < n; i++) {
+        if (nodes[i]->parent == root)
+            continue;
+
+        if (VIR_ALLOC(def) < 0)
+            goto cleanup;
+
+        ctxt->node = nodes[i];
+
+        def->name = virXPathString("string(./@guid)", ctxt);
+        if (!def->name) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("missing 'guid' attribute"));
+            goto cleanup;
+        }
+
+        def->parent = virXPathString("string(../@guid)", ctxt);
+
+        xmlstr = virXPathString("string(./DateTime)", ctxt);
+        if (!xmlstr) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("missing 'DateTime' element"));
+            goto cleanup;
+        }
+        if ((def->creationTime = prlsdkParseDateTime(xmlstr)) < 0)
+            goto cleanup;
+        VIR_FREE(xmlstr);
+
+        def->description = virXPathString("string(./Description)", ctxt);
+
+        def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
+        xmlstr = virXPathString("string(../@state)", ctxt);
+        if (!xmlstr) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("missing 'state' attribute"));
+            goto cleanup;
+        } else if (STREQ(xmlstr, "poweron")) {
+            def->state = VIR_DOMAIN_RUNNING;
+            def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
+        } else if (STREQ(xmlstr, "pause")) {
+            def->state = VIR_DOMAIN_PAUSED;
+            def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
+        } else if (STREQ(xmlstr, "suspend")) {
+            def->state = VIR_DOMAIN_SHUTOFF;
+        } else if (STREQ(xmlstr, "poweroff")) {
+            def->state = VIR_DOMAIN_SHUTOFF;
+        } else {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("unexpected snapshot state: %s"), xmlstr);
+        }
+        VIR_FREE(xmlstr);
+
+        xmlstr = virXPathString("string(./@current)", ctxt);
+        def->current = xmlstr && STREQ("yes", xmlstr);
+        VIR_FREE(xmlstr);
+
+        if (!(snapshot = virDomainSnapshotAssignDef(snapshots, def)))
+            goto cleanup;
+        def = NULL;
+
+        if (snapshot->def->current) {
+            if (current) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("too many current snapshots"));
+                goto cleanup;
+            }
+            current = snapshot;
+        }
+    }
+
+    if (virDomainSnapshotUpdateRelations(snapshots) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("snapshots have inconsistent relations"));
+        goto cleanup;
+    }
+
+    ret = snapshots;
+    snapshots = NULL;
+
+ cleanup:
+    virDomainSnapshotObjListFree(snapshots);
+    VIR_FREE(nodes);
+    VIR_FREE(xmlstr);
+    xmlXPathFreeContext(ctxt);
+    xmlFreeDoc(xml);
+    VIR_FREE(def);
+
+    return ret;
+}
+
+virDomainSnapshotObjListPtr
+prlsdkLoadSnapshots(virDomainObjPtr dom)
+{
+    virDomainSnapshotObjListPtr ret = NULL;
+    PRL_HANDLE job;
+    PRL_HANDLE result = PRL_INVALID_HANDLE;
+    vzDomObjPtr privdom = dom->privateData;
+    char *treexml = NULL;
+
+    job = PrlVm_GetSnapshotsTreeEx(privdom->sdkdom, PGST_WITHOUT_SCREENSHOTS);
+    if (PRL_FAILED(getJobResult(job, &result)))
+        goto cleanup;
+
+    if (!(treexml = prlsdkGetStringParamVar(PrlResult_GetParamAsString, result)))
+        goto cleanup;
+
+    ret = prlsdkParseSnapshotTree(treexml);
+ cleanup:
+
+    PrlHandle_Free(result);
+    VIR_FREE(treexml);
+    return ret;
+}
+
+int prlsdkCreateSnapshot(virDomainObjPtr dom, const char *description)
+{
+    vzDomObjPtr privdom = dom->privateData;
+    PRL_HANDLE job;
+
+    job = PrlVm_CreateSnapshot(privdom->sdkdom, "",
+                               description ? : "");
+    if (PRL_FAILED(waitJob(job)))
+        return -1;
+
+    return 0;
+}
+
+int prlsdkDeleteSnapshot(virDomainObjPtr dom, const char *uuid, bool children)
+{
+    vzDomObjPtr privdom = dom->privateData;
+    PRL_HANDLE job;
+
+    job = PrlVm_DeleteSnapshot(privdom->sdkdom, uuid, children);
+    if (PRL_FAILED(waitJob(job)))
+        return -1;
+
+    return 0;
+}
+
+int prlsdkSwitchToSnapshot(virDomainObjPtr dom, const char *uuid, bool paused)
+{
+    vzDomObjPtr privdom = dom->privateData;
+    PRL_HANDLE job;
+    PRL_UINT32 flags = 0;
+
+    if (paused)
+        flags |= PSSF_SKIP_RESUME;
+
+    job = PrlVm_SwitchToSnapshotEx(privdom->sdkdom, uuid, flags);
+    if (PRL_FAILED(waitJob(job)))
+        return -1;
+
+    return 0;
+}
diff --git a/src/vz/vz_sdk.h b/src/vz/vz_sdk.h
index e562f98..47ff5b9 100644
--- a/src/vz/vz_sdk.h
+++ b/src/vz/vz_sdk.h
@@ -82,3 +82,8 @@ void
 prlsdkDomObjFreePrivate(void *p);
 /* memsize is in MiB */
 int prlsdkSetMemsize(virDomainObjPtr dom, unsigned int memsize);
+
+virDomainSnapshotObjListPtr prlsdkLoadSnapshots(virDomainObjPtr dom);
+int prlsdkCreateSnapshot(virDomainObjPtr dom, const char *description);
+int prlsdkDeleteSnapshot(virDomainObjPtr dom, const char *uuid, bool children);
+int prlsdkSwitchToSnapshot(virDomainObjPtr dom, const char *uuid, bool paused);
diff --git a/src/vz/vz_utils.h b/src/vz/vz_utils.h
index ee843d8..ba4d3c5 100644
--- a/src/vz/vz_utils.h
+++ b/src/vz/vz_utils.h
@@ -27,6 +27,7 @@
 
 # include "driver.h"
 # include "conf/domain_conf.h"
+# include "conf/snapshot_conf.h"
 # include "conf/virdomainobjlist.h"
 # include "conf/domain_event.h"
 # include "virthread.h"
-- 
1.8.3.1




More information about the libvir-list mailing list