The first two flags are essential for being able to replicate
snapshot hierarchies across multiple hosts, which will come in
handy for supervised migrations. It also allows a management app
to take a snapshot of a transient domain, save the metadata, stop
the domain, recreate a new transient domain by the same name,
redefine the snapshot, then revert to it.
This is not quite as convenient as leaving the metadata behind
after a domain is no longer around, but doing that has a few
problems: 1. the libvirt API can only delete snapshot metadata
if there is a valid domain handle to use to get to that snapshot
object - if stale data is left behind without a domain, there is
no way to request that the data be cleaned up. 2. creating a new
domain with the same name but different uuid than the older
domain where a snapshot existed cannot use the older snapshot
data; this risks confusing libvirt, and forbidding the stale
data is similar to the recent patch to forbid stale managed save.
The first two flags might be useful on hypervisors with no metadata,
but only for modifying the notion of the current snapshot;
however, I don't know how to do that for ESX or VBox.
The third flag is a convenience option, to combine a creation with
a delete metadata into one step. It is trivial for hypervisors
with no metadata.
The qemu changes will be involved enough to warrant a separate patch.
* include/libvirt/libvirt.h.in
(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)
(VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)
(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA): New flags.
* src/libvirt.c (virDomainSnapshotCreateXML): Document them, and
enforce mutual exclusion.
* src/esx/esx_driver.c (esxDomainSnapshotCreateXML): Trivial
implementation.
* src/vbox/vbox_tmpl.c (vboxDomainSnapshotCreateXML): Likewise.
* docs/formatsnapshot.html.in: Document re-creation.
---
docs/formatsnapshot.html.in | 69 ++++++++++++++++++++++++++----------------
include/libvirt/libvirt.h.in | 9 +++++
src/esx/esx_driver.c | 3 +-
src/libvirt.c | 50 +++++++++++++++++++++++++++++-
src/vbox/vbox_tmpl.c | 3 +-
5 files changed, 105 insertions(+), 29 deletions(-)
diff --git a/docs/formatsnapshot.html.in b/docs/formatsnapshot.html.in
index 79ed1d2..e43d192 100644
--- a/docs/formatsnapshot.html.in
+++ b/docs/formatsnapshot.html.in
@@ -9,10 +9,26 @@
<p>
Attributes of libvirt snapshots are stored as child elements of
the <code>domainsnapshot</code> element. At snapshot creation
- time, only the <code>name</code> and
<code>description</code>
- elements are settable; the rest of the fields are informational
- (and readonly) and will be filled in by libvirt when the
- snapshot is created.
+ time, normally only the <code>name</code>
+ and <code>description</code> elements are settable; the rest of
+ the fields are ignored on creation, and will be filled in by
+ libvirt in for informational purposes
+ by <code>virDomainSnapshotGetXMLDesc()</code>. However, when
+ redefining a snapshot with
+ the <code>VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE</code> flag
+ of <code>virDomainSnapshotCreateXML()</code>, all of the XML
+ described here is relevant.
+ </p>
+ <p>
+ Snapshots are maintained in a hierarchy. A domain can have a
+ current snapshot, which is the most recent snapshot compared to
+ the current state of the domain (although a domain might have
+ snapshots without a current snapshot, if snapshots have been
+ deleted in the meantime). Creating or reverting to a snapshot
+ sets that snapshot as current, and the prior current snapshot is
+ the parent of the new snapshot. Branches in the hierarchy can
+ be formed by reverting to a snapshot with a child, then creating
+ another snapshot.
</p>
<p>
The top-level <code>domainsnapshot</code> element may contain
@@ -21,9 +37,10 @@
<dl>
<dt><code>name</code></dt>
<dd>The name for this snapshot. If the name is specified when
- initially creating the snapshot, then the snapshot will have
- that particular name. If the name is omitted when initially
- creating the snapshot, then libvirt will make up a name for the snapshot.
+ initially creating the snapshot, then the snapshot will have
+ that particular name. If the name is omitted when initially
+ creating the snapshot, then libvirt will make up a name for
+ the snapshot, based on the time when it was created.
</dd>
<dt><code>description</code></dt>
<dd>A human-readable description of the snapshot. If the
@@ -32,18 +49,18 @@
</dd>
<dt><code>creationTime</code></dt>
<dd>The time this snapshot was created. The time is specified
- in seconds since the Epoch, UTC (i.e. Unix time). Readonly.
+ in seconds since the Epoch, UTC (i.e. Unix time). Readonly.
</dd>
<dt><code>state</code></dt>
- <dd>The state of the domain at the time this snapshot was
- taken. When the domain is reverted to this snapshot, the domain's state
- will be set to whatever is in this field. Readonly.
+ <dd>The state of the domain at the time this snapshot was taken.
+ When the domain is reverted to this snapshot, the domain's
+ state will default to whatever is in this field. Readonly.
</dd>
<dt><code>parent</code></dt>
<dd>The parent of this snapshot. This element contains exactly
- one child element, name. This specifies the name of the parent
- snapshot of this snapshot, and is used to represent trees of
- snapshots. Readonly.
+ one child element, name. This specifies the name of the parent
+ snapshot of this snapshot, and is used to represent trees of
+ snapshots, as described above. Readonly.
</dd>
<dt><code>domain</code></dt>
<dd>The domain that this snapshot was taken against. This
@@ -56,17 +73,17 @@
<h2><a name="example">Example</a></h2>
<pre>
- <domainsnapshot>
- <name>os-updates</name>
- <description>Snapshot of OS install and
updates</description>
- <state>running</state>
- <creationTime>1270477159</creationTime>
- <parent>
- <name>bare-os-install</name>
- </parent>
- <domain>
-
<uuid>93a5c045-6457-2c09-e56c-927cdf34e178</uuid>
- </domain>
- </domainsnapshot></pre>
+<domainsnapshot>
+ <name>os-updates</name>
+ <description>Snapshot of OS install and
updates</description>
+ <state>running</state>
+ <creationTime>1270477159</creationTime>
+ <parent>
+ <name>bare-os-install</name>
+ </parent>
+ <domain>
+ <uuid>93a5c045-6457-2c09-e56c-927cdf34e178</uuid>
+ </domain>
+</domainsnapshot></pre>
</body>
</html>
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 38a9058..00b8350 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2552,6 +2552,15 @@ typedef struct _virDomainSnapshot virDomainSnapshot;
*/
typedef virDomainSnapshot *virDomainSnapshotPtr;
+typedef enum {
+ VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE = (1 << 0), /* Restore or alter
+ metadata */
+ VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT = (1 << 1), /* With redefine, make
+ snapshot current */
+ VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA = (1 << 2), /* Make snapshot without
+ remembering it */
+} virDomainSnapshotCreateFlags;
+
/* Take a snapshot of the current VM state */
virDomainSnapshotPtr virDomainSnapshotCreateXML(virDomainPtr domain,
const char *xmlDesc,
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index dbc7694..1e87664 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -4210,7 +4210,8 @@ esxDomainSnapshotCreateXML(virDomainPtr domain, const char
*xmlDesc,
char *taskInfoErrorMessage = NULL;
virDomainSnapshotPtr snapshot = NULL;
- virCheckFlags(0, NULL);
+ /* ESX has no snapshot metadata, so this flag is trivial. */
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
if (esxVI_EnsureSession(priv->primary) < 0) {
return NULL;
diff --git a/src/libvirt.c b/src/libvirt.c
index 8870f47..e3188b7 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -15571,11 +15571,46 @@ error:
* virDomainSnapshotCreateXML:
* @domain: a domain object
* @xmlDesc: string containing an XML description of the domain
- * @flags: unused flag parameters; callers should pass 0
+ * @flags: bitwise-OR of virDomainSnapshotCreateFlags
*
* Creates a new snapshot of a domain based on the snapshot xml
* contained in xmlDesc.
*
+ * If @flags is 0, the domain can be active, in which case the
+ * snapshot will be a system checkpoint (both disk state and runtime
+ * VM state such as RAM contents), where reverting to the snapshot is
+ * the same as resuming from hibernation (TCP connections may have
+ * timed out, but everything else picks up where it left off); or
+ * the domain can be inactive, in which case the snapshot includes
+ * just the disk state prior to booting. The newly created snapshot
+ * becomes current (see virDomainSnapshotCurrent()), and is a child
+ * of any previous current snapshot.
+ *
+ * If @flags includes VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE, then this
+ * is a request to reinstate snapshot metadata that was previously
+ * discarded, rather than creating a new snapshot. This can be used
+ * to recreate a snapshot hierarchy on a destination, then remove it
+ * on the source, in order to allow migration (since migration
+ * normally fails if snapshot metadata still remains on the source
+ * machine). When redefining snapshot metadata, the current snapshot
+ * will not be altered unless the VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT
+ * flag is also present. It is an error to request the
+ * VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT flag without
+ * VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE. On some hypervisors,
+ * redefining an existing snapshot can be used to alter host-specific
+ * portions of the domain XML to be used during revert (such as
+ * backing filenames associated with disk devices), but must not alter
+ * guest-visible layout. When redefining a snapshot name that does
+ * not exist, the hypervisor may validate that reverting to the
+ * snapshot appears to be possible (for example, disk images have
+ * snapshot contents by the requested name). Not all hypervisors
+ * support these flags.
+ *
+ * If @flags includes VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, then the
+ * domain's disk images are modified according to @xmlDesc, but then
+ * the just-created snapshot has its metadata deleted. This flag is
+ * incompatible with VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE.
+ *
* Returns an (opaque) virDomainSnapshotPtr on success, NULL on failure.
*/
virDomainSnapshotPtr
@@ -15607,6 +15642,19 @@ virDomainSnapshotCreateXML(virDomainPtr domain,
goto error;
}
+ if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT) &&
+ !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
+ virLibDomainError(VIR_ERR_INVALID_ARG,
+ _("use of current flag requires redefine flag"));
+ goto error;
+ }
+ if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) &&
+ (flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
+ virLibDomainError(VIR_ERR_INVALID_ARG,
+ _("redefine and no metadata flags are mutually
exclusive"));
+ goto error;
+ }
+
if (conn->driver->domainSnapshotCreateXML) {
virDomainSnapshotPtr ret;
ret = conn->driver->domainSnapshotCreateXML(domain, xmlDesc, flags);
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
index fc9739e..afe951c 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -5652,7 +5652,8 @@ vboxDomainSnapshotCreateXML(virDomainPtr dom,
PRInt32 result;
#endif
- virCheckFlags(0, NULL);
+ /* VBox has no snapshot metadata, so this flag is trivial. */
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
if (!(def = virDomainSnapshotDefParseString(xmlDesc, 1)))
goto cleanup;
--
1.7.4.4