Hello,
After our discussions about the snapshot API last week, I went ahead and implemented
quite a bit of the API. I also went back to the ESX, Virtualbox, and QEMU API's to
try and make sure our API's matched up. What's below is my revised API based on
that survey. Following my revised API are notes that I took regarding how the
libvirt API matches up to the various API's, and some questions about semantics that
I had while doing the survey. More comments and questions are welcome.
/* NOTE: struct _virDomainSnapshot is a private structure, ala
* struct _virDomain.
*/
typedef struct _virDomainSnapshot virDomainSnapshot;
/* Take a snapshot of the current VM state. Throws an error if
* the VM is not currently running */
virDomainSnapshotPtr virDomainSnapshotCreateXML(virDomainPtr domain,
const char *xmlDesc,
unsigned int flags);
/* Dump the XML of a snapshot */
/* NOTE: see below for proposed XML */
char *virDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
unsigned int flags);
/* Return the number of snapshots for this domain */
int virDomainSnapshotNum(virDomainPtr domain, unsigned int flags);
/* Get the names of all snapshots for this domain */
int virDomainListSnapshotNames(virDomainPtr domain, char **names, int nameslen,
unsigned int flags);
/* Get a handle to a named snapshot */
virDomainSnapshotPtr virDomainSnapshotLookupByName(virDomainPtr domain,
const char *name,
unsigned int flags);
/* Get a handle to the current in-use snapshot for the domain */
virDomainSnapshotPtr virDomainSnapshotCurrent(virDomainPtr domain,
unsigned int flags);
/* Start the guest from the snapshot "snapshot" */
int virDomainCreateFromSnapshot(virDomainSnapshotPtr snapshot,
unsigned int flags);
/* Rename the snapshot */
/* Do we really need this? In theory we could use
* virsh snapshot-edit <domain> <name> and then detect
* name changes, but that will require a UUID, which may
* or may not be overkill
*/
int virDomainSnapshotRename(virDomainSnapshotPtr snapshot,
char *newname,
unsigned int flags);
/* Delete a snapshot - with no flags, the snapshot is not used anymore,
* but also not removed. With a MERGE flag, it merges the snapshot into
* the parent snapshot (or the base image, if there is no parent snapshot).
* Note that if other snapshots would be discarded because of this
* MERGE action, this operation will fail. If that is really what is intended,
* use MERGE_FORCE.
*
* With a DISCARD flag, it deletes the snapshot. Note that if children snapshots
* would be discarded because of this delete action, this operation will
* fail. If this is really what is intended, use DISCARD_FORCE.
*
* MERGE, MERGE_FORCE, DISCARD, and DISCARD_FORCE are mutually-exclusive.
*
* Note that this operation can happen when the domain is running or shut
* down, though this is hypervisor specific */
typedef enum {
VIR_DOMAIN_SNAPSHOT_DELETE_MERGE,
VIR_DOMAIN_SNAPSHOT_DELETE_MERGE_FORCE,
VIR_DOMAIN_SNAPSHOT_DELETE_DISCARD,
VIR_DOMAIN_SNAPSHOT_DELETE_DISCARD_FORCE,
} virDomainSnapshotDelete;
int virDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
unsigned int flags);
int virDomainSnapshotFree(virDomainSnapshotPtr snapshot);
NOTE: During snapshot creation, *none* of the fields are required. That is,
you can call virDomainSnapshotCreateXML() with an XML of
"<domainsnapshot/>".
In this case, the individual driver will make up a <name> and <uuid> for you,
the <creationdate> will be set to the current time+date, <description> will
be
empty, <state> will be the current state of the VM, and <parent> will
be set to the current snapshot (if any). If you do want to specify some
fields during virDomainSnapshotCreateXML(), note that the only ones that are
settable are <name>, <uuid>, and <description>;
the rest are ignored, and filled in by the driver when the snapshot is
actually created.
NOTE: <state> refers to the state of the VM when the snapshot was taken.
<domainsnapshot>
<name>XYZ</name>
<creationdate>...</creationdate>
<description>...</description>
<state>RUNNING</state>
<domain>
<uuid>XXXXX-XXXX-XXXX-XXXX-XXXXXXXXX</uuid>
</domain>
<parent>
<name>ABC</name>
</parent>
</domainsnapshot>
The virsh commands will be:
virsh snapshot-create <dom> <xmlfile>
virsh snapshot-list <dom>
virsh snapshot-dumpxml <dom> <name>
virsh start-with-snapshot <dom> <snapshotname>
virsh snapshot-delete <dom> <snapshotname>
[--merge|--mergeforce|--delete|--deleteforce]
virsh snapshot-delete-all <dom>
Possible issues:
1) I don't see a way to support "managed" save/restore and snapshotting
with
this API. I think we'll have to have a separate API for managed save/restore.
2) What is the semantic for deleting snapshots from a running domain?
Virtualbox seems to not allow you to manipulate snapshots while the domain is
running. Qemu does allow this, but it's currently unclear what the exact
semantics are. VMware seems to allow manipulation of snapshots while the
domain is running.
3) Do we need a snapshot UUID? Virtualbox allows you to have multiple snapshots
with the same name, differentiated by UUID. Confusingly, they also have a
"FindByName" method that returns the first depth-first search snapshot that
matches
a given name. For qemu, if you specify the same name twice it overwrites the previous
one with the new one. I don't know what ESX does here.
Mapping of our interface to various hypervisors:
+-------------------------------+-----------------+-------------------+------------------------------+
| Libvirt | Qemu | Virtualbox | ESX
|
+-------------------------------+-----------------+-------------------+------------------------------+
| virDomainSnapshotCreateXML | monitor command | takeSnapshot |
CreateSnapshot_task |
| | "savevm"; if | Snapshots can | takes a
name, description, |
| | snapshot name | be taken on | memory
(true/false) and |
| | is already in | powered off, | quiesce
(true/false). |
| | use, replaces | saved, running, | What does
"memory" mean? |
| | the previous | or paused VMs. | Should we model
"quiesce" |
| | snapshot. Also | The snapshot is | Trees of snapshots
are |
| | qemu-img | always taken | supported. What
happens |
| | snapshot -c can | against the | on a duplicate
name? What |
| | be used to | current snapshot. | state(s) can a VM
be in |
| | create a | What happens on | when calling this?
Does |
| | disk-only | a duplicate | a VM get paused
when this |
| | snapshot. What | name? Trees of | is called?
|
| | happens if the | snapshots are |
|
| | VM is running | not currently |
|
| | when you do | supported. |
|
| | this? Trees of | Taking a snapshot |
|
| | snapshots seem | of a running VM |
|
| | to be supported | pauses the VM |
|
| | VM gets paused | before taking the |
|
| | while this is | snapshot. |
|
| | happening. What | |
|
| | states can the | |
|
| | VM be in? | |
|
+-------------------------------+-----------------+-------------------+------------------------------+
| virDomainSnapshotGetXMLDesc | Libvirt qemu | GetId | VirtualMachine
object-> |
| | snapshot | GetDescription | snapshot->
rootSnapshotList |
| | metadata | GetTimeStamp | [i].createTime
|
| | | GetParent | .description
|
| | | GetCurrentSnapshot| .name
|
| | | | .id
|
| | | | .state
|
| | | | .quiesced
|
| | | | .vm
|
+-------------------------------+-----------------+-------------------+------------------------------+
| virDomainSnapshotNum | Libvirt qemu | GetSnapshotCount | VirtualMachine
object-> |
| | snapshot | | snapshot->
rootSnapshotList |
| | metadata | |
|
+-------------------------------+-----------------+-------------------+------------------------------+
| virDomainListSnapshotNames | Libvirt qemu | GetSnapshotCount | VirtualMachine
object-> |
| | snapshot | GetChildren | snapshot->
rootSnapshotList |
| | metadata, or | |
|
| | listvm monitor | |
|
| | command or | |
|
| | qemu-img | |
|
| | snapshot -l | |
|
| | <file>. If the | |
|
| | VM has multiple | |
|
| | disks and the | |
|
| | disks have | |
|
| | different | |
|
| | snapshots, what | |
|
| | do you do? | |
|
+-------------------------------+-----------------+-------------------+------------------------------+
| virDomainSnapshotLookupByName | " | findSnapshot |
VirtualMachine object-> |
| | | Takes a name and | snapshot->
rootSnapshotList |
| | | returns a |
|
| | | snapshot object. |
|
| | | In case of |
|
| | | multiple snapshots|
|
| | | with the same |
|
| | | name, it returns |
|
| | | the first object |
|
| | | from a depth |
|
| | | first search. |
|
+-------------------------------+-----------------+-------------------+------------------------------+
| virDomainCreateFromSnapshot | qemu-img | restoreSnapshot |
RevertToSnapshot_Task |
| | snapshot -a | Takes a snapshot | Changes execution
state |
| | <snapname> | object, and | of VM to
state of this |
| | <file>. What | resets the VM's |
snapshot. Takes a |
| | happens if the | state to that of | snapshot object,
an |
| | VM has multiple | the snapshot. | optional host, and
|
| | files with | If this is a | suppressPowerOn,
which |
| | different | snapshot taken | forces the VM to
the off |
| | snapshots? | against a running | state regardless
of the |
| | | machine, then the | state when the
snapshot |
| | | memory is | was taken.
Implies that |
| | | restored as well. | without this flag,
VM |
| | | Does *not* start | starts in whatever
|
| | | the VM. The VM | <state> was
when snapshot |
| | | must be off for | was taken.
|
| | | this operation to |
|
| | | succeed. |
|
+-------------------------------+-----------------+-------------------+------------------------------+
| virDomainSnapshotDelete | monitor command | deleteSnapshot |
RemoveSnapshot_Task |
| | "delvm". What | deletes the | removes
this snapshot and |
| | happens if the | specified | deletes any
associated |
| | snapshot is in | snapshot. Takes | storage. Operates
on a |
| | use? What | an ID. The VM |
VirtualMachineSnapshot |
| | states can the | must be off. | object. What
states can |
| | VM be in? Also | Differences to | the VM be in?
What |
| | qemu-img | children | happens if this
snapshot |
| | snapshot -d | snapshots will be | is in-use? What
happens |
| | <name> <file> | merged with the | to
parents and children? |
| | command can be | children to keep |
|
| | used. What | children valid. |
|
| | happens if the | Parent for this |
|
| | disk is in-use? | snapshot will |
|
| | What happens to | become parent of |
|
| | parents and | any children |
|
| | children? | snapshots. |
|
| | How do we | |
|
| | handle merges? | |
|
+-------------------------------+-----------------+-------------------+------------------------------+
| virDomainSnapshotCurrent | Libvirt qemu | currentSnapshot | VirtualMachine
object-> |
| | snapshot | | snapshot->
currentSnapshot |
| | metadata | |
|
+-------------------------------+-----------------+-------------------+------------------------------+
| virDomainSnapshotRename | Libvirt qemu | ISnapshot->name | RenameSnapshot
|
| | snapshot | |
|
| | metadata | |
|
+-------------------------------+-----------------+-------------------+------------------------------+
| virDomainSnapshotDelete with | Libvirt qemu | deleteSnapshot |
RemoveAllSnapshots_Task |
| DISCARD_FORCE flag against | snapshot | with manual depth |
|
| root snapshot | metadata | deletion of |
|
| | | children |
|
+-------------------------------+-----------------+-------------------+------------------------------+
| | | |
RevertToCurrentSnapshot_Task |
+-------------------------------+-----------------+-------------------+------------------------------+
Attribute mapping:
+----------------+----------+-------------+----------------------------+
| Libvirt | Qemu | Virtualbox | ESX |
+----------------+----------+-------------+----------------------------+
| <name> | TAG | name | name |
+----------------+----------+-------------+----------------------------+
| <creationdate> | DATE | timeStamp | createTime |
+----------------+----------+-------------+----------------------------+
| <description> | Libvirt | description | description |
| | qemu | | |
| | metadata | | |
+----------------+----------+-------------+----------------------------+
| <state> | Libvirt | online | state (this is the *power* |
| | qemu | | state of the VM when this |
| | metadata | | snapshot was taken) |
+----------------+----------+-------------+----------------------------+
| <domain><uuid> | Libvirt | machine | vm |
| | qemu | | |
| | metadata | | |
+----------------+----------+-------------+----------------------------+
| <parent><name> | Libvirt | parent | N/A |
| | qemu | | |
| | metadata | | |
+----------------+----------+-------------+----------------------------+
| N/A | N/A | id (uuid) | id |
+----------------+----------+-------------+----------------------------+
| N/A | N/A | children | childSnapshotList |
+----------------+----------+-------------+----------------------------+
| N/A | N/A | N/A | memory |
+----------------+----------+-------------+----------------------------+
| N/A | N/A | N/A | quiesced |
+----------------+----------+-------------+----------------------------+
| N/A | N/A | N/A | backupManifest |
+----------------+----------+-------------+----------------------------+
| N/A | N/A | N/A | replaySupported |
+----------------+----------+-------------+----------------------------+
--
Chris Lalancette