libvirt/snapshots.patch

1123 lines
38 KiB
Diff
Raw Normal View History

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
@@ -1167,6 +1167,189 @@ cmdSave(vshControl *ctl, const vshCmd *c
return ret;
}
+
+/*
+ * "snapshot-create" command
+ */
+static vshCmdInfo info_snapshot_create[] = {
+ {"syntax", "snapshot-create <domain> <name>"},
+ {"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 <domain> <name>"},
+ {"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 <domain> <name>"},
+ {"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 <domain>"},
+ {"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
*/
@@ -7252,6 +7435,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 @@
<exports symbol='virInterfaceDefineXML' type='function'/>
<exports symbol='virDomainMigrate' type='function'/>
<exports symbol='virDomainSuspend' type='function'/>
+ <exports symbol='virDomainSnapshotApply' type='function'/>
+ <exports symbol='virDomainSnapshotCreate' type='function'/>
+ <exports symbol='virDomainSnapshotDelete' type='function'/>
+ <exports symbol='virDomainNumOfSnapshots' type='function'/>
+ <exports symbol='virDomainListSnapshots' type='function'/>
<exports symbol='virDomainCreateLinux' type='function'/>
<exports symbol='virNodeDeviceGetXMLDesc' type='function'/>
<exports symbol='virEventUpdateHandleFunc' type='function'/>
@@ -1432,6 +1437,36 @@ see note above'/>
<return type='int' info='0 in case of success and -1 in case of failure.'/>
<arg name='domain' type='virDomainPtr' info='a domain object'/>
</function>
+ <function name='virDomainSnapshotApply' file='libvirt' module='libvirt'>
+ <info>Start a shut off domain based on a previously taken snapshot</info>
+ <return type='int' info='0 in case of success and -1 in case of failure.'/>
+ <arg name='domain' type='virDomainPtr' info='a domain object'/>
+ <arg name='name' type='const char *' info='name of the snapshot'/>
+ </function>
+ <function name='virDomainSnapshotCreate' file='libvirt' module='libvirt'>
+ <info>Create a snapshot from a running domain</info>
+ <return type='int' info='0 in case of success and -1 in case of failure.'/>
+ <arg name='domain' type='virDomainPtr' info='a domain object'/>
+ <arg name='name' type='const char *' info='name of the snapshot'/>
+ </function>
+ <function name='virDomainSnapshotDelete' file='libvirt' module='libvirt'>
+ <info>Delete a snapshot from a domain</info>
+ <return type='int' info='0 in case of success and -1 in case of failure.'/>
+ <arg name='domain' type='virDomainPtr' info='a domain object'/>
+ <arg name='name' type='const char *' info='name of the snapshot'/>
+ </function>
+ <function name='virDomainNumOfSnapshots' file='libvirt' module='libvirt'>
+ <info>Returns the number of snapshot a given domain has</info>
+ <return type='int' info='the number of snapshots in case of success and -1 in case of failure.'/>
+ <arg name='domain' type='virDomainPtr' info='a domain object'/>
+ </function>
+ <function name='virDomainListSnapshots' file='libvirt' module='libvirt'>
+ <info>Returns the names of the snapshots of a domain</info>
+ <return type='int' info='0 in case of success and -1 in case of failure.'/>
+ <arg name='domain' type='virDomainPtr' info='a domain object'/>
+ <arg name='names' type='char ** const' info='pointer to an array to store the snapshot names'/>
+ <arg name='maxnames' type='int' info='size of the names array'/>
+ </function>
<function name='virDomainUndefine' file='libvirt' module='libvirt'>
<info>Undefine a domain but does not stop it if it is running</info>
<return type='int' info='0 in case of success, -1 in case of error'/>
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 @@
<arg name='domain' type='virDomainPtr' info='pointer to domain object'/>
<arg name='params' type='virSchedParameterPtr' info='pointer to scheduler parameter objects'/>
</function>
+ <function name='virDomainListSnapshots' file='python'>
+ <info>Returns the names of the snapshots of a domain</info>
+ <arg name='domain' type='virDomainPtr' info='pointer to domain object'/>
+ <return type='str *' info='the list of Names or None in case of error'/>
+ </function>
<function name='virConnectListStoragePools' file='python'>
<info>list the storage pools, stores the pointers to the names in @names</info>
<arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/>
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 {