Index: libvirt-0.4.6/include/libvirt/libvirt.h.in =================================================================== --- libvirt-0.4.6.orig/include/libvirt/libvirt.h.in +++ libvirt-0.4.6/include/libvirt/libvirt.h.in @@ -470,6 +470,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.4.6/src/libvirt.c =================================================================== --- libvirt-0.4.6.orig/src/libvirt.c +++ libvirt-0.4.6/src/libvirt.c @@ -1659,6 +1659,168 @@ virDomainRestore(virConnectPtr conn, con 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.4.6/src/driver.h =================================================================== --- libvirt-0.4.6.orig/src/driver.h +++ libvirt-0.4.6/src/driver.h @@ -146,6 +146,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); @@ -352,6 +367,12 @@ struct _virDriver { virDrvDomainMemoryPeek domainMemoryPeek; virDrvNodeGetCellsFreeMemory nodeGetCellsFreeMemory; virDrvNodeGetFreeMemory getFreeMemory; + + virDrvDomainSnapshotCreate domainSnapshotCreate; + virDrvDomainSnapshotApply domainSnapshotApply; + virDrvDomainSnapshotDelete domainSnapshotDelete; + virDrvDomainNumOfSnapshots domainNumOfSnapshots; + virDrvDomainListSnapshots domainListSnapshots; }; typedef int Index: libvirt-0.4.6/src/xen_unified.c =================================================================== --- libvirt-0.4.6.orig/src/xen_unified.c +++ libvirt-0.4.6/src/xen_unified.c @@ -869,6 +869,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); @@ -1336,6 +1411,11 @@ static virDriver xenUnifiedDriver = { .domainGetInfo = xenUnifiedDomainGetInfo, .domainSave = xenUnifiedDomainSave, .domainRestore = xenUnifiedDomainRestore, + .domainSnapshotCreate = xenUnifiedDomainSnapshotCreate, + .domainSnapshotApply = xenUnifiedDomainSnapshotApply, + .domainSnapshotDelete = xenUnifiedDomainSnapshotDelete, + .domainNumOfSnapshots = xenUnifiedDomainNumOfSnapshots, + .domainListSnapshots = xenUnifiedDomainListSnapshots, .domainCoreDump = xenUnifiedDomainCoreDump, .domainSetVcpus = xenUnifiedDomainSetVcpus, .domainPinVcpu = xenUnifiedDomainPinVcpu, Index: libvirt-0.4.6/src/xen_unified.h =================================================================== --- libvirt-0.4.6.orig/src/xen_unified.h +++ libvirt-0.4.6/src/xen_unified.h @@ -63,6 +63,11 @@ struct xenUnifiedDriver { virDrvDomainGetInfo domainGetInfo; virDrvDomainSave domainSave; virDrvDomainRestore domainRestore; + virDrvDomainSnapshotCreate domainSnapshotCreate; + virDrvDomainSnapshotApply domainSnapshotApply; + virDrvDomainSnapshotDelete domainSnapshotDelete; + virDrvDomainNumOfSnapshots domainNumOfSnapshots; + virDrvDomainListSnapshots domainListSnapshots; virDrvDomainCoreDump domainCoreDump; virDrvDomainSetVcpus domainSetVcpus; virDrvDomainPinVcpu domainPinVcpu; Index: libvirt-0.4.6/src/xend_internal.c =================================================================== --- libvirt-0.4.6.orig/src/xend_internal.c +++ libvirt-0.4.6/src/xend_internal.c @@ -51,6 +51,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 */ @@ -3070,6 +3076,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 */ /** @@ -4824,6 +4911,11 @@ struct xenUnifiedDriver xenDaemonDriver xenDaemonDomainGetInfo, /* domainGetInfo */ xenDaemonDomainSave, /* domainSave */ xenDaemonDomainRestore, /* domainRestore */ + xenDaemonDomainSnapshotCreate, /* domainSnapshotCreate */ + xenDaemonDomainSnapshotApply, /* domainSnapshotApply */ + xenDaemonDomainSnapshotDelete, /* domainSnapshotDelete */ + xenDaemonDomainNumOfSnapshots, /* domainNumOfSnapshots */ + xenDaemonDomainListSnapshots, /* domainListSnapshots */ xenDaemonDomainCoreDump, /* domainCoreDump */ xenDaemonDomainSetVcpus, /* domainSetVcpus */ xenDaemonDomainPinVcpu, /* domainPinVcpu */ Index: libvirt-0.4.6/src/proxy_internal.c =================================================================== --- libvirt-0.4.6.orig/src/proxy_internal.c +++ libvirt-0.4.6/src/proxy_internal.c @@ -66,6 +66,11 @@ struct xenUnifiedDriver xenProxyDriver = xenProxyDomainGetInfo, /* domainGetInfo */ NULL, /* domainSave */ NULL, /* domainRestore */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ NULL, /* domainCoreDump */ NULL, /* domainSetVcpus */ NULL, /* domainPinVcpu */ Index: libvirt-0.4.6/src/xen_internal.c =================================================================== --- libvirt-0.4.6.orig/src/xen_internal.c +++ libvirt-0.4.6/src/xen_internal.c @@ -700,6 +700,11 @@ struct xenUnifiedDriver xenHypervisorDri xenHypervisorGetDomainInfo, /* domainGetInfo */ NULL, /* domainSave */ NULL, /* domainRestore */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ NULL, /* domainCoreDump */ xenHypervisorSetVcpus, /* domainSetVcpus */ xenHypervisorPinVcpu, /* domainPinVcpu */ Index: libvirt-0.4.6/src/xm_internal.c =================================================================== --- libvirt-0.4.6.orig/src/xm_internal.c +++ libvirt-0.4.6/src/xm_internal.c @@ -105,6 +105,11 @@ struct xenUnifiedDriver xenXMDriver = { xenXMDomainGetInfo, /* domainGetInfo */ NULL, /* domainSave */ NULL, /* domainRestore */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ NULL, /* domainCoreDump */ xenXMDomainSetVcpus, /* domainSetVcpus */ xenXMDomainPinVcpu, /* domainPinVcpu */ Index: libvirt-0.4.6/src/xs_internal.c =================================================================== --- libvirt-0.4.6.orig/src/xs_internal.c +++ libvirt-0.4.6/src/xs_internal.c @@ -66,6 +66,11 @@ struct xenUnifiedDriver xenStoreDriver = xenStoreGetDomainInfo, /* domainGetInfo */ NULL, /* domainSave */ NULL, /* domainRestore */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ NULL, /* domainCoreDump */ NULL, /* domainSetVcpus */ NULL, /* domainPinVcpu */ Index: libvirt-0.4.6/src/virsh.c =================================================================== --- libvirt-0.4.6.orig/src/virsh.c +++ libvirt-0.4.6/src/virsh.c @@ -1100,6 +1100,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, 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", &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, 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", &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, 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", &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, 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", &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 */ @@ -5568,6 +5751,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-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as}, {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete}, Index: libvirt-0.4.6/src/lxc_driver.c =================================================================== --- libvirt-0.4.6.orig/src/lxc_driver.c +++ libvirt-0.4.6/src/lxc_driver.c @@ -1203,6 +1203,11 @@ static virDriver lxcDriver = { NULL, /* domainMemoryPeek */ NULL, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; Index: libvirt-0.4.6/src/openvz_driver.c =================================================================== --- libvirt-0.4.6.orig/src/openvz_driver.c +++ libvirt-0.4.6/src/openvz_driver.c @@ -1014,6 +1014,11 @@ static virDriver openvzDriver = { NULL, /* domainMemoryPeek */ NULL, /* nodeGetCellsFreeMemory */ NULL, /* nodeGetFreeMemory */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; int openvzRegister(void) { Index: libvirt-0.4.6/src/qemu_driver.c =================================================================== --- libvirt-0.4.6.orig/src/qemu_driver.c +++ libvirt-0.4.6/src/qemu_driver.c @@ -4079,6 +4079,11 @@ static virDriver qemuDriver = { NULL, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ #endif + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; static virNetworkDriver qemuNetworkDriver = { Index: libvirt-0.4.6/src/remote_internal.c =================================================================== --- libvirt-0.4.6.orig/src/remote_internal.c +++ libvirt-0.4.6/src/remote_internal.c @@ -4888,6 +4888,11 @@ static virDriver driver = { .domainMemoryPeek = remoteDomainMemoryPeek, .nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory, .getFreeMemory = remoteNodeGetFreeMemory, + .domainSnapshotCreate = NULL, + .domainSnapshotApply = NULL, + .domainSnapshotDelete = NULL, + .domainNumOfSnapshots = NULL, + .domainListSnapshots = NULL, }; static virNetworkDriver network_driver = { Index: libvirt-0.4.6/src/test.c =================================================================== --- libvirt-0.4.6.orig/src/test.c +++ libvirt-0.4.6/src/test.c @@ -1595,6 +1595,11 @@ static virDriver testDriver = { NULL, /* domainMemoryPeek */ testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ + NULL, /* domainSnapshotCreate */ + NULL, /* domainSnapshotApply */ + NULL, /* domainSnapshotDelete */ + NULL, /* domainNumOfSnapshots */ + NULL, /* domainListSnapshots */ }; static virNetworkDriver testNetworkDriver = { Index: libvirt-0.4.6/src/libvirt_sym.version =================================================================== --- libvirt-0.4.6.orig/src/libvirt_sym.version +++ libvirt-0.4.6/src/libvirt_sym.version @@ -35,6 +35,11 @@ virDomainRestore; virDomainResume; virDomainSave; + virDomainSnapshotCreate; + virDomainSnapshotApply; + virDomainSnapshotDelete; + virDomainNumOfSnapshots; + virDomainListSnapshots; virDomainCoreDump; virDomainSetMemory; virDomainSetMaxMemory; Index: libvirt-0.4.6/docs/libvirt-api.xml =================================================================== --- libvirt-0.4.6.orig/docs/libvirt-api.xml +++ libvirt-0.4.6/docs/libvirt-api.xml @@ -143,6 +143,11 @@ + + + + + @@ -1096,6 +1101,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.4.6/python/libvirt-py.c =================================================================== --- libvirt-0.4.6.orig/python/libvirt-py.c +++ libvirt-0.4.6/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; @@ -520,24 +539,6 @@ LIBVIRT_END_ALLOW_THREADS; } PyObject * -libvirt_virNetworkGetName(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { - PyObject *py_retval; - const char * c_retval; - virNetworkPtr network; - PyObject *pyobj_network; - - if (!PyArg_ParseTuple(args, (char *)"O:virNetworkGetName", &pyobj_network)) - return(NULL); - network = (virNetworkPtr) PyvirNetwork_Get(pyobj_network); -LIBVIRT_BEGIN_ALLOW_THREADS; - - c_retval = virNetworkGetName(network); -LIBVIRT_END_ALLOW_THREADS; - py_retval = libvirt_charPtrConstWrap((const char *) c_retval); - return(py_retval); -} - -PyObject * libvirt_virNetworkDestroy(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; int c_retval; @@ -771,6 +772,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; @@ -806,6 +826,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; @@ -824,6 +862,25 @@ LIBVIRT_END_ALLOW_THREADS; } 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 * libvirt_virConnectGetHostname(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; char * c_retval; @@ -897,6 +954,24 @@ LIBVIRT_END_ALLOW_THREADS; } PyObject * +libvirt_virNetworkGetName(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + const char * c_retval; + virNetworkPtr network; + PyObject *pyobj_network; + + if (!PyArg_ParseTuple(args, (char *)"O:virNetworkGetName", &pyobj_network)) + return(NULL); + network = (virNetworkPtr) PyvirNetwork_Get(pyobj_network); +LIBVIRT_BEGIN_ALLOW_THREADS; + + c_retval = virNetworkGetName(network); +LIBVIRT_END_ALLOW_THREADS; + py_retval = libvirt_charPtrConstWrap((const char *) c_retval); + return(py_retval); +} + +PyObject * libvirt_virConnectGetCapabilities(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; char * c_retval; Index: libvirt-0.4.6/python/libvirt-py.h =================================================================== --- libvirt-0.4.6.orig/python/libvirt-py.h +++ libvirt-0.4.6/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_virConnectClose(PyObject *self, PyObject *args); PyObject * libvirt_virDomainDefineXML(PyObject *self, PyObject *args); @@ -28,7 +29,6 @@ PyObject * libvirt_virConnectNumOfNetwor PyObject * libvirt_virStorageVolGetName(PyObject *self, PyObject *args); PyObject * libvirt_virStoragePoolLookupByUUIDString(PyObject *self, PyObject *args); PyObject * libvirt_virDomainGetXMLDesc(PyObject *self, PyObject *args); -PyObject * libvirt_virNetworkGetName(PyObject *self, PyObject *args); PyObject * libvirt_virNetworkDestroy(PyObject *self, PyObject *args); PyObject * libvirt_virStoragePoolLookupByName(PyObject *self, PyObject *args); PyObject * libvirt_virNetworkGetBridgeName(PyObject *self, PyObject *args); @@ -42,13 +42,17 @@ PyObject * libvirt_virNetworkSetAutostar PyObject * libvirt_virDomainGetMaxMemory(PyObject *self, PyObject *args); PyObject * libvirt_virResetLastError(PyObject *self, PyObject *args); PyObject * libvirt_virStoragePoolFree(PyObject *self, PyObject *args); +PyObject * libvirt_virDomainSnapshotCreate(PyObject *self, PyObject *args); PyObject * libvirt_virNetworkDefineXML(PyObject *self, PyObject *args); PyObject * libvirt_virConnResetLastError(PyObject *self, PyObject *args); +PyObject * libvirt_virDomainNumOfSnapshots(PyObject *self, PyObject *args); PyObject * libvirt_virDomainResume(PyObject *self, PyObject *args); +PyObject * libvirt_virDomainSnapshotApply(PyObject *self, PyObject *args); PyObject * libvirt_virConnectGetHostname(PyObject *self, PyObject *args); PyObject * libvirt_virDomainGetName(PyObject *self, PyObject *args); PyObject * libvirt_virNetworkGetXMLDesc(PyObject *self, PyObject *args); PyObject * libvirt_virConnectNumOfStoragePools(PyObject *self, PyObject *args); +PyObject * libvirt_virNetworkGetName(PyObject *self, PyObject *args); PyObject * libvirt_virConnectGetCapabilities(PyObject *self, PyObject *args); PyObject * libvirt_virDomainLookupByName(PyObject *self, PyObject *args); PyObject * libvirt_virConnectFindStoragePoolSources(PyObject *self, PyObject *args); Index: libvirt-0.4.6/python/libvirt.py =================================================================== --- libvirt-0.4.6.orig/python/libvirt.py +++ libvirt-0.4.6/python/libvirt.py @@ -359,6 +359,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. @@ -433,6 +439,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 @@ -489,6 +513,12 @@ class virDomain: ret = libvirtmod.virDomainInterfaceStats(self._o, path) 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.4.6/python/libvir.c =================================================================== --- libvirt-0.4.6.orig/python/libvir.c +++ libvirt-0.4.6/python/libvir.c @@ -1466,6 +1466,35 @@ libvirt_virStoragePoolLookupByUUID(PyObj 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); +} + /************************************************************************ @@ -1502,6 +1531,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.4.6/python/libvirt-python-api.xml =================================================================== --- libvirt-0.4.6.orig/python/libvirt-python-api.xml +++ libvirt-0.4.6/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.4.6/python/generator.py =================================================================== --- libvirt-0.4.6.orig/python/generator.py +++ libvirt-0.4.6/python/generator.py @@ -306,6 +306,7 @@ skip_impl = ( 'virDomainSetSchedulerParameters', 'virDomainGetVcpus', 'virDomainPinVcpu', + 'virDomainListSnapshots', 'virStoragePoolGetUUID', 'virStoragePoolGetUUIDString', 'virStoragePoolLookupByUUID',