Index: libvirt-0.7.1/include/libvirt/libvirt.h.in =================================================================== --- libvirt-0.7.1.orig/include/libvirt/libvirt.h.in +++ libvirt-0.7.1/include/libvirt/libvirt.h.in @@ -537,6 +537,21 @@ int virDomainRestore const char *from); /* + * Snapshots + */ +int virDomainSnapshotCreate (virDomainPtr domain, + const char* name); +int virDomainSnapshotApply (virDomainPtr domain, + const char* name); +int virDomainSnapshotDelete (virDomainPtr domain, + const char* name); +int virDomainNumOfSnapshots (virDomainPtr domain); +int virDomainListSnapshots (virDomainPtr domain, + char **const names, + int maxnames); + + +/* * Domain core dump */ int virDomainCoreDump (virDomainPtr domain, Index: libvirt-0.7.1/src/libvirt.c =================================================================== --- libvirt-0.7.1.orig/src/libvirt.c +++ libvirt-0.7.1/src/libvirt.c @@ -2245,6 +2245,168 @@ error: return -1; } + +/** + * virDomainSnapshotCreate: + * @domain: a domain object + * @name: name for the new snapshot + * + * Creates a snapshot from a running domain + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainSnapshotCreate(virDomainPtr domain, const char* name) +{ + virConnectPtr conn; + + DEBUG("domain=%p", domain); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + return (-1); + } + + conn = domain->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->driver->domainSnapshotCreate) + return conn->driver->domainSnapshotCreate(domain, name); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +/** + * virDomainSnapshotApply: + * @domain: a domain object + * @name: name of the snapshot to apply + * + * Starts a domain using a given snapshot. The domain needs to be shut down + * before calling thsi function. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainSnapshotApply(virDomainPtr domain, const char* name) +{ + virConnectPtr conn; + + DEBUG("domain=%p", domain); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + return (-1); + } + + conn = domain->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->driver->domainSnapshotApply) + return conn->driver->domainSnapshotApply(domain, name); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +/** + * virDomainSnapshotDelete: + * @domain: a domain object + * @name: name of the snapshot to delete + * + * Deletes a snapshot from the given domain + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainSnapshotDelete(virDomainPtr domain, const char* name) +{ + virConnectPtr conn; + + DEBUG("domain=%p", domain); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + return (-1); + } + + conn = domain->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->driver->domainSnapshotDelete) + return conn->driver->domainSnapshotDelete(domain, name); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +/** + * virDomainNumOfSnapshots: + * @domain: a domain object + * + * Returns the number of snapshots of the given domain or -1 in case of failure + */ +int +virDomainNumOfSnapshots(virDomainPtr domain) +{ + virConnectPtr conn; + + DEBUG("domain=%p", domain); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + return (-1); + } + + conn = domain->conn; + if (conn->driver->domainNumOfSnapshots) + return conn->driver->domainNumOfSnapshots(domain); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +/** + * virDomainListSnapshots: + * @domain: a domain object + * @names: pointer to an array to store the snapshot names + * @maxnames: size of the array + * + * List the names of all snapshots of the given domain. The names are + * stored in the @names array. Unused array entries are set to NULL. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainListSnapshots(virDomainPtr domain, char **const names, int maxnames) +{ + virConnectPtr conn; + + DEBUG("domain=%p", domain); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + return (-1); + } + + conn = domain->conn; + if (conn->driver->domainListSnapshots) + return conn->driver->domainListSnapshots(domain, names, maxnames); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + /** * virDomainCoreDump: * @domain: a domain object Index: libvirt-0.7.1/src/driver.h =================================================================== --- libvirt-0.7.1.orig/src/driver.h +++ libvirt-0.7.1/src/driver.h @@ -152,6 +152,21 @@ typedef int (*virDrvDomainRestore) (virConnectPtr conn, const char *from); typedef int + (*virDrvDomainSnapshotCreate) (virDomainPtr domain, + const char* name); +typedef int + (*virDrvDomainSnapshotApply) (virDomainPtr domain, + const char* name); +typedef int + (*virDrvDomainSnapshotDelete) (virDomainPtr domain, + const char* name); +typedef int + (*virDrvDomainNumOfSnapshots) (virDomainPtr domain); +typedef int + (*virDrvDomainListSnapshots) (virDomainPtr domain, + char **const names, + int maxnames); +typedef int (*virDrvDomainCoreDump) (virDomainPtr domain, const char *to, int flags); @@ -427,6 +442,11 @@ struct _virDriver { virDrvNodeDeviceDettach nodeDeviceDettach; virDrvNodeDeviceReAttach nodeDeviceReAttach; virDrvNodeDeviceReset nodeDeviceReset; + virDrvDomainSnapshotCreate domainSnapshotCreate; + virDrvDomainSnapshotApply domainSnapshotApply; + virDrvDomainSnapshotDelete domainSnapshotDelete; + virDrvDomainNumOfSnapshots domainNumOfSnapshots; + virDrvDomainListSnapshots domainListSnapshots; }; typedef int Index: libvirt-0.7.1/src/xen_unified.c =================================================================== --- libvirt-0.7.1.orig/src/xen_unified.c +++ libvirt-0.7.1/src/xen_unified.c @@ -952,6 +952,81 @@ xenUnifiedDomainRestore (virConnectPtr c } static int +xenUnifiedDomainSnapshotCreate(virDomainPtr domain, const char* name) +{ + GET_PRIVATE(domain->conn); + int i; + + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) + if (priv->opened[i] && + drivers[i]->domainSnapshotCreate && + drivers[i]->domainSnapshotCreate(domain, name) == 0) + return 0; + + return -1; +} + +static int +xenUnifiedDomainSnapshotApply(virDomainPtr domain, const char* name) +{ + GET_PRIVATE(domain->conn); + int i; + + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) + if (priv->opened[i] && + drivers[i]->domainSnapshotApply && + drivers[i]->domainSnapshotApply(domain, name) == 0) + return 0; + + return -1; +} + +static int +xenUnifiedDomainSnapshotDelete(virDomainPtr domain, const char* name) +{ + GET_PRIVATE(domain->conn); + int i; + + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) + if (priv->opened[i] && + drivers[i]->domainSnapshotDelete && + drivers[i]->domainSnapshotDelete(domain, name) == 0) + return 0; + + return -1; +} + +static int +xenUnifiedDomainNumOfSnapshots(virDomainPtr domain) +{ + GET_PRIVATE(domain->conn); + int i; + + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) + if (priv->opened[i] && + drivers[i]->domainNumOfSnapshots) + return drivers[i]->domainNumOfSnapshots(domain); + + return -1; +} + +static int +xenUnifiedDomainListSnapshots(virDomainPtr domain, char **const names, + int maxnames) +{ + GET_PRIVATE(domain->conn); + int i; + + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) + if (priv->opened[i] && + drivers[i]->domainListSnapshots && + drivers[i]->domainListSnapshots(domain, names, maxnames) == 0) + return 0; + + return -1; +} + +static int xenUnifiedDomainCoreDump (virDomainPtr dom, const char *to, int flags) { GET_PRIVATE(dom->conn); @@ -1722,6 +1797,11 @@ static virDriver xenUnifiedDriver = { xenUnifiedNodeDeviceDettach, /* nodeDeviceDettach */ xenUnifiedNodeDeviceReAttach, /* nodeDeviceReAttach */ xenUnifiedNodeDeviceReset, /* nodeDeviceReset */ + xenUnifiedDomainSnapshotCreate, + xenUnifiedDomainSnapshotApply, + xenUnifiedDomainSnapshotDelete, + xenUnifiedDomainNumOfSnapshots, + xenUnifiedDomainListSnapshots, }; /** Index: libvirt-0.7.1/src/xen_unified.h =================================================================== --- libvirt-0.7.1.orig/src/xen_unified.h +++ libvirt-0.7.1/src/xen_unified.h @@ -98,6 +98,11 @@ struct xenUnifiedDriver { virDrvDomainGetSchedulerType domainGetSchedulerType; virDrvDomainGetSchedulerParameters domainGetSchedulerParameters; virDrvDomainSetSchedulerParameters domainSetSchedulerParameters; + virDrvDomainSnapshotCreate domainSnapshotCreate; + virDrvDomainSnapshotApply domainSnapshotApply; + virDrvDomainSnapshotDelete domainSnapshotDelete; + virDrvDomainNumOfSnapshots domainNumOfSnapshots; + virDrvDomainListSnapshots domainListSnapshots; }; typedef struct xenXMConfCache *xenXMConfCachePtr; Index: libvirt-0.7.1/src/xend_internal.c =================================================================== --- libvirt-0.7.1.orig/src/xend_internal.c +++ libvirt-0.7.1/src/xend_internal.c @@ -53,6 +53,12 @@ #ifndef PROXY +static int xenDaemonDomainSnapshotCreate(virDomainPtr domain, const char* name); +static int xenDaemonDomainSnapshotApply(virDomainPtr domain, const char* name); +static int xenDaemonDomainSnapshotDelete(virDomainPtr domain, const char* name); +static int xenDaemonDomainNumOfSnapshots(virDomainPtr domain); +static int xenDaemonDomainListSnapshots(virDomainPtr domain, char **const names, int maxnames); + /* * The number of Xen scheduler parameters */ @@ -3248,6 +3254,87 @@ xenDaemonDomainRestore(virConnectPtr con } return xend_op(conn, "", "op", "restore", "file", filename, NULL); } + +static int +xenDaemonDomainSnapshotCreate(virDomainPtr domain, const char* name) +{ + if ((domain == NULL) || (name == NULL)) { + virXendError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + return xend_op(domain->conn, domain->name, "op", + "snapshot_create", "name", name, NULL); +} + +static int +xenDaemonDomainSnapshotApply(virDomainPtr domain, const char* name) +{ + if ((domain == NULL) || (name == NULL)) { + virXendError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + return xend_op(domain->conn, domain->name, "op", + "snapshot_apply", "name", name, NULL); +} + +static int +xenDaemonDomainSnapshotDelete(virDomainPtr domain, const char* name) +{ + if ((domain == NULL) || (name == NULL)) { + virXendError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + return xend_op(domain->conn, domain->name, "op", + "snapshot_delete", "name", name, NULL); +} + +static int +xenDaemonDomainNumOfSnapshots(virDomainPtr domain) +{ + struct sexpr *root, *node, *value; + int i; + + root = sexpr_get(domain->conn, + "/xend/domain/%s?op=snapshot_list", domain->name); + if (root == NULL) + return -1; + + for (node = root, i = 0; node->kind == SEXPR_CONS; node = node->u.s.cdr) { + value = node->u.s.car; + + if (value->kind == SEXPR_VALUE) + i++; + } + + return i; +} + +static int +xenDaemonDomainListSnapshots(virDomainPtr domain, char **const names, + int maxnames) +{ + struct sexpr *root, *node, *value; + int i; + root = sexpr_get(domain->conn, + "/xend/domain/%s?op=snapshot_list", domain->name); + if (root == NULL) + return -1; + + for (node = root, i = 0; node->kind == SEXPR_CONS; node = node->u.s.cdr) { + value = node->u.s.car; + + if (value->kind == SEXPR_VALUE) { + names[i] = strdup(value->u.value); + if (++i > maxnames) + return 0; + } + } + + for (; i < maxnames; i++) + names[i] = NULL; + + return 0; +} #endif /* !PROXY */ /** @@ -5064,6 +5151,11 @@ struct xenUnifiedDriver xenDaemonDriver xenDaemonGetSchedulerType, /* domainGetSchedulerType */ xenDaemonGetSchedulerParameters, /* domainGetSchedulerParameters */ xenDaemonSetSchedulerParameters, /* domainSetSchedulerParameters */ + xenDaemonDomainSnapshotCreate, /* domainSnapshotCreate */ + xenDaemonDomainSnapshotApply, /* domainSnapshotApply */ + xenDaemonDomainSnapshotDelete, /* domainSnapshotDelete */ + xenDaemonDomainNumOfSnapshots, /* domainNumOfSnapshots */ + xenDaemonDomainListSnapshots, /* domainListSnapshots */ }; /************************************************************************ Index: libvirt-0.7.1/src/proxy_internal.c =================================================================== --- libvirt-0.7.1.orig/src/proxy_internal.c +++ libvirt-0.7.1/src/proxy_internal.c @@ -84,6 +84,11 @@ struct xenUnifiedDriver xenProxyDriver = NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; Index: libvirt-0.7.1/src/xen_internal.c =================================================================== --- libvirt-0.7.1.orig/src/xen_internal.c +++ libvirt-0.7.1/src/xen_internal.c @@ -741,6 +741,11 @@ struct xenUnifiedDriver xenHypervisorDri xenHypervisorGetSchedulerType, /* domainGetSchedulerType */ xenHypervisorGetSchedulerParameters, /* domainGetSchedulerParameters */ xenHypervisorSetSchedulerParameters, /* domainSetSchedulerParameters */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; #endif /* !PROXY */ Index: libvirt-0.7.1/src/xm_internal.c =================================================================== --- libvirt-0.7.1.orig/src/xm_internal.c +++ libvirt-0.7.1/src/xm_internal.c @@ -116,6 +116,11 @@ struct xenUnifiedDriver xenXMDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; #define xenXMError(conn, code, fmt...) \ Index: libvirt-0.7.1/src/xs_internal.c =================================================================== --- libvirt-0.7.1.orig/src/xs_internal.c +++ libvirt-0.7.1/src/xs_internal.c @@ -83,6 +83,11 @@ struct xenUnifiedDriver xenStoreDriver = NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; #endif /* ! PROXY */ Index: libvirt-0.7.1/src/virsh.c =================================================================== --- libvirt-0.7.1.orig/src/virsh.c +++ libvirt-0.7.1/src/virsh.c @@ -1171,6 +1171,189 @@ cmdSave(vshControl *ctl, const vshCmd *c return ret; } + +/* + * "snapshot-create" command + */ +static vshCmdInfo info_snapshot_create[] = { + {"syntax", "snapshot-create "}, + {"help", gettext_noop("Create a snapshot of the domain")}, + {"desc", gettext_noop("Create a snapshot of the domain")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_snapshot_create[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Domain name, id or uuid")}, + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Name of the snapshot")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + char *name; + char *domain; + int ret = TRUE; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(name = vshCommandOptString(cmd, "name", NULL))) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &domain))) + return FALSE; + + if (virDomainSnapshotCreate(dom, name) == 0) { + vshPrint(ctl, _("Snapshot %s created for domain %s\n"), name, domain); + } else { + vshError(ctl, FALSE, _("Failed to create snapshot %s for domain %s"), + name, domain); + ret = FALSE; + } + + virDomainFree(dom); + return ret; +} + +/* + * "snapshot-apply" command + */ +static vshCmdInfo info_snapshot_apply[] = { + {"syntax", "snapshot-apply "}, + {"help", gettext_noop("Start the domain using a snapshot")}, + {"desc", gettext_noop("Start the domain using a snapshot")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_snapshot_apply[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Domain name, id or uuid")}, + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Name of the snapshot")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdSnapshotApply(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + char *name; + char *domain; + int ret = TRUE; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(name = vshCommandOptString(cmd, "name", NULL))) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &domain))) + return FALSE; + + if (virDomainSnapshotApply(dom, name) == 0) { + vshPrint(ctl, _("Domain %s started using snapshot %s\n"), + domain, name); + } else { + vshError(ctl, FALSE, _("Failed to start domain %s using snapshot %s"), + domain, name); + ret = FALSE; + } + + virDomainFree(dom); + return ret; +} + +/* + * "snapshot-delete" command + */ +static vshCmdInfo info_snapshot_delete[] = { + {"syntax", "snapshot-delete "}, + {"help", gettext_noop("Delete a snapshot from a domain")}, + {"desc", gettext_noop("Delete a snapshot from a domain")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_snapshot_delete[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Domain name, id or uuid")}, + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Name of the snapshot")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdSnapshotDelete(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + char *name; + char *domain; + int ret = TRUE; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(name = vshCommandOptString(cmd, "name", NULL))) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &domain))) + return FALSE; + + if (virDomainSnapshotDelete(dom, name) == 0) { + vshPrint(ctl, _("Snapshot %s deleted from domain %s\n"), name, domain); + } else { + vshError(ctl, FALSE, _("Failed to delete snapshot %s from domain %s"), + name, domain); + ret = FALSE; + } + + virDomainFree(dom); + return ret; +} + +/* + * "snapshot-list" command + */ +static vshCmdInfo info_snapshot_list[] = { + {"syntax", "snapshot-list "}, + {"help", gettext_noop("List all snapshots of a domain")}, + {"desc", gettext_noop("List all snapshots of a domain")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_snapshot_list[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + char *domain; + char** names; + int num; + int i; + int ret = TRUE; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &domain))) + return FALSE; + + // TODO Display snapshot details + num = virDomainNumOfSnapshots(dom); + names = malloc(num * sizeof(*names)); + virDomainListSnapshots(dom, names, num); + + for (i = 0; i < num; i++) { + printf("%s\n", names[i]); + free(names[i]); + } + + free(names); + virDomainFree(dom); + return ret; +} + /* * "schedinfo" command */ @@ -7265,6 +7448,12 @@ static const vshCmdDef commands[] = { {"undefine", cmdUndefine, opts_undefine, info_undefine}, {"uri", cmdURI, NULL, info_uri}, + {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, info_snapshot_create}, + {"snapshot-apply", cmdSnapshotApply, opts_snapshot_apply, info_snapshot_apply}, + {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, info_snapshot_delete}, + {"snapshot-list", cmdSnapshotList, opts_snapshot_list, info_snapshot_list}, + + {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create}, {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, info_vol_create_from}, {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as}, Index: libvirt-0.7.1/src/lxc_driver.c =================================================================== --- libvirt-0.7.1.orig/src/lxc_driver.c +++ libvirt-0.7.1/src/lxc_driver.c @@ -1931,6 +1931,11 @@ static virDriver lxcDriver = { NULL, /* nodeDeviceDettach */ NULL, /* nodeDeviceReAttach */ NULL, /* nodeDeviceReset */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; static virStateDriver lxcStateDriver = { Index: libvirt-0.7.1/src/openvz_driver.c =================================================================== --- libvirt-0.7.1.orig/src/openvz_driver.c +++ libvirt-0.7.1/src/openvz_driver.c @@ -1392,6 +1392,11 @@ static virDriver openvzDriver = { NULL, /* nodeDeviceDettach */ NULL, /* nodeDeviceReAttach */ NULL, /* nodeDeviceReset */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; int openvzRegister(void) { Index: libvirt-0.7.1/src/qemu_driver.c =================================================================== --- libvirt-0.7.1.orig/src/qemu_driver.c +++ libvirt-0.7.1/src/qemu_driver.c @@ -7576,6 +7576,11 @@ static virDriver qemuDriver = { qemudNodeDeviceDettach, /* nodeDeviceDettach */ qemudNodeDeviceReAttach, /* nodeDeviceReAttach */ qemudNodeDeviceReset, /* nodeDeviceReset */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; Index: libvirt-0.7.1/src/test.c =================================================================== --- libvirt-0.7.1.orig/src/test.c +++ libvirt-0.7.1/src/test.c @@ -4257,6 +4257,11 @@ static virDriver testDriver = { NULL, /* nodeDeviceDettach */ NULL, /* nodeDeviceReAttach */ NULL, /* nodeDeviceReset */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; static virNetworkDriver testNetworkDriver = { Index: libvirt-0.7.1/docs/libvirt-api.xml =================================================================== --- libvirt-0.7.1.orig/docs/libvirt-api.xml +++ libvirt-0.7.1/docs/libvirt-api.xml @@ -208,6 +208,11 @@ + + + + + @@ -1432,6 +1437,36 @@ see note above'/> + + Start a shut off domain based on a previously taken snapshot + + + + + + Create a snapshot from a running domain + + + + + + Delete a snapshot from a domain + + + + + + Returns the number of snapshot a given domain has + + + + + Returns the names of the snapshots of a domain + + + + + Undefine a domain but does not stop it if it is running Index: libvirt-0.7.1/python/libvirt-py.c =================================================================== --- libvirt-0.7.1.orig/python/libvirt-py.c +++ libvirt-0.7.1/python/libvirt-py.c @@ -25,6 +25,25 @@ LIBVIRT_END_ALLOW_THREADS; } PyObject * +libvirt_virDomainSnapshotDelete(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + int c_retval; + virDomainPtr domain; + PyObject *pyobj_domain; + char * name; + + if (!PyArg_ParseTuple(args, (char *)"Oz:virDomainSnapshotDelete", &pyobj_domain, &name)) + return(NULL); + domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); +LIBVIRT_BEGIN_ALLOW_THREADS; + + c_retval = virDomainSnapshotDelete(domain, name); +LIBVIRT_END_ALLOW_THREADS; + py_retval = libvirt_intWrap((int) c_retval); + return(py_retval); +} + +PyObject * libvirt_virStorageVolGetKey(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; const char * c_retval; @@ -1151,6 +1170,25 @@ LIBVIRT_END_ALLOW_THREADS; } PyObject * +libvirt_virDomainSnapshotCreate(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + int c_retval; + virDomainPtr domain; + PyObject *pyobj_domain; + char * name; + + if (!PyArg_ParseTuple(args, (char *)"Oz:virDomainSnapshotCreate", &pyobj_domain, &name)) + return(NULL); + domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); +LIBVIRT_BEGIN_ALLOW_THREADS; + + c_retval = virDomainSnapshotCreate(domain, name); +LIBVIRT_END_ALLOW_THREADS; + py_retval = libvirt_intWrap((int) c_retval); + return(py_retval); +} + +PyObject * libvirt_virNetworkDefineXML(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; virNetworkPtr c_retval; @@ -1186,6 +1224,24 @@ LIBVIRT_END_ALLOW_THREADS; } PyObject * +libvirt_virDomainNumOfSnapshots(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + int c_retval; + virDomainPtr domain; + PyObject *pyobj_domain; + + if (!PyArg_ParseTuple(args, (char *)"O:virDomainNumOfSnapshots", &pyobj_domain)) + return(NULL); + domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); +LIBVIRT_BEGIN_ALLOW_THREADS; + + c_retval = virDomainNumOfSnapshots(domain); +LIBVIRT_END_ALLOW_THREADS; + py_retval = libvirt_intWrap((int) c_retval); + return(py_retval); +} + +PyObject * libvirt_virDomainResume(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; int c_retval; @@ -1201,6 +1257,25 @@ LIBVIRT_BEGIN_ALLOW_THREADS; LIBVIRT_END_ALLOW_THREADS; py_retval = libvirt_intWrap((int) c_retval); return(py_retval); +} + +PyObject * +libvirt_virDomainSnapshotApply(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + int c_retval; + virDomainPtr domain; + PyObject *pyobj_domain; + char * name; + + if (!PyArg_ParseTuple(args, (char *)"Oz:virDomainSnapshotApply", &pyobj_domain, &name)) + return(NULL); + domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); +LIBVIRT_BEGIN_ALLOW_THREADS; + + c_retval = virDomainSnapshotApply(domain, name); +LIBVIRT_END_ALLOW_THREADS; + py_retval = libvirt_intWrap((int) c_retval); + return(py_retval); } PyObject * Index: libvirt-0.7.1/python/libvirt-py.h =================================================================== --- libvirt-0.7.1.orig/python/libvirt-py.h +++ libvirt-0.7.1/python/libvirt-py.h @@ -1,6 +1,7 @@ /* Generated */ PyObject * libvirt_virStoragePoolGetXMLDesc(PyObject *self, PyObject *args); +PyObject * libvirt_virDomainSnapshotDelete(PyObject *self, PyObject *args); PyObject * libvirt_virStorageVolGetKey(PyObject *self, PyObject *args); PyObject * libvirt_virDomainUndefine(PyObject *self, PyObject *args); PyObject * libvirt_virDomainDefineXML(PyObject *self, PyObject *args); Index: libvirt-0.7.1/python/libvirt.py =================================================================== --- libvirt-0.7.1.orig/python/libvirt.py +++ libvirt-0.7.1/python/libvirt.py @@ -390,6 +390,12 @@ class virDomain: ret = libvirtmod.virDomainGetName(self._o) return ret + def numOfSnapshots(self): + """Returns the number of snapshot a given domain has """ + ret = libvirtmod.virDomainNumOfSnapshots(self._o) + if ret == -1: raise libvirtError ('virDomainNumOfSnapshots() failed', dom=self) + return ret + def reboot(self, flags): """Reboot a domain, the domain object is still usable there after but the domain OS is being stopped for a restart. @@ -478,6 +484,24 @@ class virDomain: if ret == -1: raise libvirtError ('virDomainShutdown() failed', dom=self) return ret + def snapshotApply(self, name): + """Start a shut off domain based on a previously taken snapshot """ + ret = libvirtmod.virDomainSnapshotApply(self._o, name) + if ret == -1: raise libvirtError ('virDomainSnapshotApply() failed', dom=self) + return ret + + def snapshotCreate(self, name): + """Create a snapshot from a running domain """ + ret = libvirtmod.virDomainSnapshotCreate(self._o, name) + if ret == -1: raise libvirtError ('virDomainSnapshotCreate() failed', dom=self) + return ret + + def snapshotDelete(self, name): + """Delete a snapshot from a domain """ + ret = libvirtmod.virDomainSnapshotDelete(self._o, name) + if ret == -1: raise libvirtError ('virDomainSnapshotDelete() failed', dom=self) + return ret + def suspend(self): """Suspends an active domain, the process is frozen without further access to CPU resources and I/O but the memory used @@ -536,6 +560,12 @@ class virDomain: if ret is None: raise libvirtError ('virDomainInterfaceStats() failed', dom=self) return ret + def listSnapshots(self): + """Returns the names of the snapshots of a domain """ + ret = libvirtmod.virDomainListSnapshots(self._o) + if ret is None: raise libvirtError ('virDomainListSnapshots() failed', dom=self) + return ret + def pinVcpu(self, vcpu, cpumap): """Dynamically change the real CPUs which can be allocated to a virtual CPU. This function requires privileged access to Index: libvirt-0.7.1/python/libvir.c =================================================================== --- libvirt-0.7.1.orig/python/libvir.c +++ libvirt-0.7.1/python/libvir.c @@ -1375,6 +1375,35 @@ libvirt_virStoragePoolGetInfo(PyObject * return(py_retval); } +static PyObject * +libvirt_virDomainListSnapshots(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + int i, num; + char** names; + virDomainPtr domain; + PyObject *pyobj_domain; + + if (!PyArg_ParseTuple(args, (char *)"O:virDomainListSnapshots", + &pyobj_domain)) + return(NULL); + domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); + +LIBVIRT_BEGIN_ALLOW_THREADS; + num = virDomainNumOfSnapshots(domain); + names = malloc(num * sizeof(*names)); + virDomainListSnapshots(domain, names, num); +LIBVIRT_END_ALLOW_THREADS; + + py_retval = PyList_New(num); + for (i = 0; i < num; i++) { + PyList_SetItem(py_retval, i, Py_BuildValue("s", names[i])); + free(names[i]); + } + free(names); + + return(py_retval); +} + static PyObject * libvirt_virStorageVolGetInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { @@ -2420,6 +2449,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virDomainSetSchedulerParameters", libvirt_virDomainSetSchedulerParameters, METH_VARARGS, NULL}, {(char *) "virDomainGetVcpus", libvirt_virDomainGetVcpus, METH_VARARGS, NULL}, {(char *) "virDomainPinVcpu", libvirt_virDomainPinVcpu, METH_VARARGS, NULL}, + {(char *) "virDomainListSnapshots", libvirt_virDomainListSnapshots, METH_VARARGS, NULL}, {(char *) "virConnectListStoragePools", libvirt_virConnectListStoragePools, METH_VARARGS, NULL}, {(char *) "virConnectListDefinedStoragePools", libvirt_virConnectListDefinedStoragePools, METH_VARARGS, NULL}, {(char *) "virStoragePoolGetAutostart", libvirt_virStoragePoolGetAutostart, METH_VARARGS, NULL}, Index: libvirt-0.7.1/python/libvirt-python-api.xml =================================================================== --- libvirt-0.7.1.orig/python/libvirt-python-api.xml +++ libvirt-0.7.1/python/libvirt-python-api.xml @@ -135,6 +135,11 @@ + + Returns the names of the snapshots of a domain + + + list the storage pools, stores the pointers to the names in @names Index: libvirt-0.7.1/python/generator.py =================================================================== --- libvirt-0.7.1.orig/python/generator.py +++ libvirt-0.7.1/python/generator.py @@ -326,6 +326,7 @@ skip_impl = ( 'virDomainSetSchedulerParameters', 'virDomainGetVcpus', 'virDomainPinVcpu', + 'virDomainListSnapshots', 'virSecretGetValue', 'virSecretSetValue', 'virSecretGetUUID', Index: libvirt-0.7.1/src/libvirt_public.syms =================================================================== --- libvirt-0.7.1.orig/src/libvirt_public.syms +++ libvirt-0.7.1/src/libvirt_public.syms @@ -215,6 +215,11 @@ LIBVIRT_0.4.2 { LIBVIRT_0.4.5 { global: virConnectFindStoragePoolSources; + virDomainSnapshotCreate; + virDomainSnapshotApply; + virDomainSnapshotDelete; + virDomainNumOfSnapshots; + virDomainListSnapshots; } LIBVIRT_0.4.2; LIBVIRT_0.5.0 {