Index: libvirt-0.7.6/include/libvirt/libvirt.h.in =================================================================== --- libvirt-0.7.6.orig/include/libvirt/libvirt.h.in +++ libvirt-0.7.6/include/libvirt/libvirt.h.in @@ -621,6 +621,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.6/src/libvirt.c =================================================================== --- libvirt-0.7.6.orig/src/libvirt.c +++ libvirt-0.7.6/src/libvirt.c @@ -2379,6 +2379,166 @@ error: } /** + * 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 * @to: path for the core file Index: libvirt-0.7.6/src/driver.h =================================================================== --- libvirt-0.7.6.orig/src/driver.h +++ libvirt-0.7.6/src/driver.h @@ -136,6 +136,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); @@ -458,6 +473,11 @@ struct _virDriver { virDrvDomainIsActive domainIsActive; virDrvDomainIsPersistent domainIsPersistent; virDrvCPUCompare cpuCompare; + virDrvDomainSnapshotCreate domainSnapshotCreate; + virDrvDomainSnapshotApply domainSnapshotApply; + virDrvDomainSnapshotDelete domainSnapshotDelete; + virDrvDomainNumOfSnapshots domainNumOfSnapshots; + virDrvDomainListSnapshots domainListSnapshots; }; typedef int Index: libvirt-0.7.6/src/xen/xen_driver.c =================================================================== --- libvirt-0.7.6.orig/src/xen/xen_driver.c +++ libvirt-0.7.6/src/xen/xen_driver.c @@ -1052,6 +1052,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); @@ -1904,6 +1979,11 @@ static virDriver xenUnifiedDriver = { xenUnifiedDomainIsActive, xenUnifiedDomainisPersistent, NULL, /* cpuCompare */ + xenUnifiedDomainSnapshotCreate, /* domainSnapshotCreate */ + xenUnifiedDomainSnapshotApply, /* domainSnapshotApply */ + xenUnifiedDomainSnapshotDelete, /* domainSnapshotDelete */ + xenUnifiedDomainNumOfSnapshots, /* domainNumOfSnapshots */ + xenUnifiedDomainListSnapshots, /* domainListSnapshots */ }; /** Index: libvirt-0.7.6/src/xen/xen_driver.h =================================================================== --- libvirt-0.7.6.orig/src/xen/xen_driver.h +++ libvirt-0.7.6/src/xen/xen_driver.h @@ -100,6 +100,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.6/src/xen/xend_internal.c =================================================================== --- libvirt-0.7.6.orig/src/xen/xend_internal.c +++ libvirt-0.7.6/src/xen/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 */ @@ -3284,6 +3290,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 */ /** @@ -5235,6 +5322,11 @@ struct xenUnifiedDriver xenDaemonDriver xenDaemonGetSchedulerType, /* domainGetSchedulerType */ xenDaemonGetSchedulerParameters, /* domainGetSchedulerParameters */ xenDaemonSetSchedulerParameters, /* domainSetSchedulerParameters */ + xenDaemonDomainSnapshotCreate, /* domainSnapshotCreate */ + xenDaemonDomainSnapshotApply, /* domainSnapshotApply */ + xenDaemonDomainSnapshotDelete, /* domainSnapshotDelete */ + xenDaemonDomainNumOfSnapshots, /* domainNumOfSnapshots */ + xenDaemonDomainListSnapshots, /* domainListSnapshots */ }; /************************************************************************ Index: libvirt-0.7.6/src/xen/proxy_internal.c =================================================================== --- libvirt-0.7.6.orig/src/xen/proxy_internal.c +++ libvirt-0.7.6/src/xen/proxy_internal.c @@ -83,6 +83,11 @@ struct xenUnifiedDriver xenProxyDriver = NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; Index: libvirt-0.7.6/src/xen/xen_hypervisor.c =================================================================== --- libvirt-0.7.6.orig/src/xen/xen_hypervisor.c +++ libvirt-0.7.6/src/xen/xen_hypervisor.c @@ -800,6 +800,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.6/src/xen/xm_internal.c =================================================================== --- libvirt-0.7.6.orig/src/xen/xm_internal.c +++ libvirt-0.7.6/src/xen/xm_internal.c @@ -118,6 +118,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.6/src/xen/xs_internal.c =================================================================== --- libvirt-0.7.6.orig/src/xen/xs_internal.c +++ libvirt-0.7.6/src/xen/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.6/tools/virsh.c =================================================================== --- libvirt-0.7.6.orig/tools/virsh.c +++ libvirt-0.7.6/tools/virsh.c @@ -1237,6 +1237,188 @@ cmdSave(vshControl *ctl, const vshCmd *c } /* + * "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, _("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, _("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, _("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 */ static const vshCmdInfo info_schedinfo[] = { @@ -7502,6 +7684,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.6/src/lxc/lxc_driver.c =================================================================== --- libvirt-0.7.6.orig/src/lxc/lxc_driver.c +++ libvirt-0.7.6/src/lxc/lxc_driver.c @@ -2458,6 +2458,11 @@ static virDriver lxcDriver = { lxcDomainIsActive, lxcDomainIsPersistent, NULL, /* cpuCompare */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; static virStateDriver lxcStateDriver = { Index: libvirt-0.7.6/src/openvz/openvz_driver.c =================================================================== --- libvirt-0.7.6.orig/src/openvz/openvz_driver.c +++ libvirt-0.7.6/src/openvz/openvz_driver.c @@ -1537,6 +1537,11 @@ static virDriver openvzDriver = { openvzDomainIsActive, openvzDomainIsPersistent, NULL, /* cpuCompare */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; int openvzRegister(void) { Index: libvirt-0.7.6/src/qemu/qemu_driver.c =================================================================== --- libvirt-0.7.6.orig/src/qemu/qemu_driver.c +++ libvirt-0.7.6/src/qemu/qemu_driver.c @@ -8632,6 +8632,11 @@ static virDriver qemuDriver = { qemuDomainIsActive, qemuDomainIsPersistent, qemuCPUCompare, /* cpuCompare */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; Index: libvirt-0.7.6/src/esx/esx_driver.c =================================================================== --- libvirt-0.7.6.orig/src/esx/esx_driver.c +++ libvirt-0.7.6/src/esx/esx_driver.c @@ -3403,6 +3403,11 @@ static virDriver esxDriver = { esxDomainIsActive, /* domainIsActive */ esxDomainIsPersistent, /* domainIsPersistent */ NULL, /* cpuCompare */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; Index: libvirt-0.7.6/src/test/test_driver.c =================================================================== --- libvirt-0.7.6.orig/src/test/test_driver.c +++ libvirt-0.7.6/src/test/test_driver.c @@ -5240,6 +5240,11 @@ static virDriver testDriver = { testDomainIsActive, /* domainIsActive */ testDomainIsPersistent, /* domainIsPersistent */ NULL, /* cpuCompare */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; static virNetworkDriver testNetworkDriver = { Index: libvirt-0.7.6/src/uml/uml_driver.c =================================================================== --- libvirt-0.7.6.orig/src/uml/uml_driver.c +++ libvirt-0.7.6/src/uml/uml_driver.c @@ -1926,6 +1926,11 @@ static virDriver umlDriver = { umlDomainIsActive, umlDomainIsPersistent, NULL, /* cpuCompare */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; Index: libvirt-0.7.6/src/vbox/vbox_tmpl.c =================================================================== --- libvirt-0.7.6.orig/src/vbox/vbox_tmpl.c +++ libvirt-0.7.6/src/vbox/vbox_tmpl.c @@ -7059,6 +7059,11 @@ virDriver NAME(Driver) = { vboxDomainIsActive, vboxDomainIsPersistent, NULL, /* cpuCompare */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; virNetworkDriver NAME(NetworkDriver) = { Index: libvirt-0.7.6/src/opennebula/one_driver.c =================================================================== --- libvirt-0.7.6.orig/src/opennebula/one_driver.c +++ libvirt-0.7.6/src/opennebula/one_driver.c @@ -785,6 +785,11 @@ static virDriver oneDriver = { NULL, /* domainIsActive */ NULL, /* domainIsPersistent */ NULL, /* cpuCompare */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; static virStateDriver oneStateDriver = { Index: libvirt-0.7.6/src/phyp/phyp_driver.c =================================================================== --- libvirt-0.7.6.orig/src/phyp/phyp_driver.c +++ libvirt-0.7.6/src/phyp/phyp_driver.c @@ -1653,6 +1653,11 @@ virDriver phypDriver = { NULL, /* domainIsActive */ NULL, /* domainIsPersistent */ NULL, /* cpuCompare */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; int Index: libvirt-0.7.6/src/remote/remote_driver.c =================================================================== --- libvirt-0.7.6.orig/src/remote/remote_driver.c +++ libvirt-0.7.6/src/remote/remote_driver.c @@ -8994,6 +8994,11 @@ static virDriver remote_driver = { remoteDomainIsActive, /* domainIsActive */ remoteDomainIsPersistent, /* domainIsPersistent */ remoteCPUCompare, /* cpuCompare */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; static virNetworkDriver network_driver = { Index: libvirt-0.7.6/docs/libvirt-api.xml =================================================================== --- libvirt-0.7.6.orig/docs/libvirt-api.xml +++ libvirt-0.7.6/docs/libvirt-api.xml @@ -293,6 +293,11 @@ + + + + + @@ -1972,6 +1977,36 @@ This function may requires privileged ac + + 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 + + + + + Index: libvirt-0.7.6/src/libvirt_public.syms =================================================================== --- libvirt-0.7.6.orig/src/libvirt_public.syms +++ libvirt-0.7.6/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 { Index: libvirt-0.7.6/python/generator.py =================================================================== --- libvirt-0.7.6.orig/python/generator.py +++ libvirt-0.7.6/python/generator.py @@ -289,6 +289,7 @@ skip_impl = ( 'virDomainSetSchedulerParameters', 'virDomainGetVcpus', 'virDomainPinVcpu', + 'virDomainListSnapshots', 'virSecretGetValue', 'virSecretSetValue', 'virSecretGetUUID', Index: libvirt-0.7.6/python/libvirt-override.c =================================================================== --- libvirt-0.7.6.orig/python/libvirt-override.c +++ libvirt-0.7.6/python/libvirt-override.c @@ -1542,6 +1542,34 @@ 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) { @@ -2717,6 +2745,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virStoragePoolGetAutostart", libvirt_virStoragePoolGetAutostart, METH_VARARGS, NULL}, {(char *) "virStoragePoolListVolumes", libvirt_virStoragePoolListVolumes, METH_VARARGS, NULL}, {(char *) "virStoragePoolGetInfo", libvirt_virStoragePoolGetInfo, METH_VARARGS, NULL}, + {(char *) "virDomainListSnapshots", libvirt_virDomainListSnapshots, METH_VARARGS, NULL}, {(char *) "virStorageVolGetInfo", libvirt_virStorageVolGetInfo, METH_VARARGS, NULL}, {(char *) "virStoragePoolGetUUID", libvirt_virStoragePoolGetUUID, METH_VARARGS, NULL}, {(char *) "virStoragePoolGetUUIDString", libvirt_virStoragePoolGetUUIDString, METH_VARARGS, NULL}, Index: libvirt-0.7.6/python/libvirt-override-api.xml =================================================================== --- libvirt-0.7.6.orig/python/libvirt-override-api.xml +++ libvirt-0.7.6/python/libvirt-override-api.xml @@ -150,6 +150,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.6/src/xen/xen_inotify.c =================================================================== --- libvirt-0.7.6.orig/src/xen/xen_inotify.c +++ libvirt-0.7.6/src/xen/xen_inotify.c @@ -86,6 +86,11 @@ struct xenUnifiedDriver xenInotifyDriver NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; static int