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

The first patch do all the job. It is rather large but does not touch any existing code so I found it reasonable not to split it. Nikolay Shirokovskiy (2): vz: add domain snapshots functionality vz: drop prlsdkDomainHasSnapshots src/libvirt_private.syms | 2 + src/vz/vz_driver.c | 535 +++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 303 +++++++++++++++++++++------ src/vz/vz_sdk.h | 5 + src/vz/vz_utils.h | 1 + 5 files changed, 777 insertions(+), 69 deletions(-) -- 1.8.3.1

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@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, ¤t); + 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

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@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, ¤t); + 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"

Let's use introduced domain snapshots infrastructure instead. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_sdk.c | 87 ++++++++++++--------------------------------------------- 1 file changed, 18 insertions(+), 69 deletions(-) diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index 23b9277..ed9b8bf 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -3831,75 +3831,16 @@ prlsdkDetachDomainHardDisks(PRL_HANDLE sdkdom) return ret; } -/** - * prlsdkDomainHasSnapshots: - * - * This function detects where a domain specified by @sdkdom - * has snapshots. It doesn't count them correctly. - * - * @sdkdom: domain handle - * @found: a value more than zero if snapshots present - * - * Returns 0 if function succeeds, -1 otherwise. - */ -static int -prlsdkDomainHasSnapshots(PRL_HANDLE sdkdom, int* found) -{ - int ret = -1; - PRL_RESULT pret; - PRL_HANDLE job; - PRL_HANDLE result; - char *snapshotxml = NULL; - unsigned int paramsCount; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - - if (!found) - goto cleanup; - - job = PrlVm_GetSnapshotsTreeEx(sdkdom, PGST_WITHOUT_SCREENSHOTS); - if (PRL_FAILED(getJobResult(job, &result))) - goto cleanup; - - pret = PrlResult_GetParamsCount(result, ¶msCount); - prlsdkCheckRetGoto(pret, cleanup); - - if (!paramsCount) - goto cleanup; - - if (!(snapshotxml = prlsdkGetStringParamVar(PrlResult_GetParamAsString, - result))) - goto cleanup; - - if (*snapshotxml == '\0') { - /* The document is empty that means no snapshots */ - *found = 0; - ret = 0; - goto cleanup; - } - - if (!(xml = virXMLParseStringCtxt(snapshotxml, "SavedStateItem", &ctxt))) - goto cleanup; - - *found = virXMLChildElementCount(ctxt->node); - ret = 0; - - cleanup: - - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml); - VIR_FREE(snapshotxml); - return ret; -} - int prlsdkUnregisterDomain(vzDriverPtr driver, virDomainObjPtr dom, unsigned int flags) { vzDomObjPtr privdom = dom->privateData; PRL_HANDLE job; size_t i; - int snapshotfound = 0; + virDomainSnapshotObjListPtr snapshots = NULL; VIRTUAL_MACHINE_STATE domainState; + int ret = -1; + int num; if (prlsdkGetDomainState(privdom->sdkdom, &domainState) < 0) return -1; @@ -3913,31 +3854,39 @@ prlsdkUnregisterDomain(vzDriverPtr driver, virDomainObjPtr dom, unsigned int fla return -1; } - if (prlsdkDomainHasSnapshots(privdom->sdkdom, &snapshotfound) < 0) + if (!(snapshots = prlsdkLoadSnapshots(dom))) return -1; - if (snapshotfound && !(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) { + if ((num = virDomainSnapshotObjListNum(snapshots, NULL, 0)) < 0) + goto cleanup; + + if (num > 0 && !(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Refusing to undefine while snapshots exist")); - return -1; + goto cleanup; } if (prlsdkDetachDomainHardDisks(privdom->sdkdom)) - return -1; + goto cleanup; job = PrlVm_Delete(privdom->sdkdom, PRL_INVALID_HANDLE); if (PRL_FAILED(waitJob(job))) - return -1; + goto cleanup; for (i = 0; i < dom->def->nnets; i++) prlsdkCleanupBridgedNet(driver, dom->def->nets[i]); if (prlsdkSendEvent(driver, dom, VIR_DOMAIN_EVENT_UNDEFINED, VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) < 0) - return -1; + goto cleanup; virDomainObjListRemove(driver->domains, dom); - return 0; + + ret = 0; + cleanup: + + virDomainSnapshotObjListFree(snapshots); + return ret; } int -- 1.8.3.1

02.05.2016 12:33, Nikolay Shirokovskiy пишет:
Let's use introduced domain snapshots infrastructure instead.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_sdk.c | 87 ++++++++++++--------------------------------------------- 1 file changed, 18 insertions(+), 69 deletions(-)
ACK

02.05.2016 12:33, Nikolay Shirokovskiy пишет:
The first patch do all the job. It is rather large but does not touch any existing code so I found it reasonable not to split it.
Nikolay Shirokovskiy (2): vz: add domain snapshots functionality vz: drop prlsdkDomainHasSnapshots
src/libvirt_private.syms | 2 + src/vz/vz_driver.c | 535 +++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 303 +++++++++++++++++++++------ src/vz/vz_sdk.h | 5 + src/vz/vz_utils.h | 1 + 5 files changed, 777 insertions(+), 69 deletions(-)
I fixed the mentioned issue in the first patch and pushed. Thanks! Maxim
participants (2)
-
Maxim Nestratov
-
Nikolay Shirokovskiy