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

Maxim Nestratov mnestratov at virtuozzo.com
Wed May 18 15:07:40 UTC 2016


02.05.2016 12:33, Nikolay Shirokovskiy пишет:

> 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);

There is a typo here, should be "string(./@state)".
Otherwise you will show the state of parent's snapshot and not the one 
you are parsing.

> +        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"




More information about the libvir-list mailing list