[libvirt] [RFC]: Snapshot API

Hello, As some of you know, I've been working on a new snapshot API. This API is heavily based on DanB's earlier API proposed here: https://www.redhat.com/archives/libvir-list/2010-January/msg00626.html I've made some modifications to make it more libvirt-ish, and to add a couple of features I think it lacked. The full documentation is below. Any comments are appreciated. /* NOTE: struct _virDomainSnapshot is a private structure, ala * struct _virDomain. */ typedef struct _virDomainSnapshot virDomainSnapshot; /* Take a snapshot of the current VM state */ 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); /* Set this snapshot as the current one for a domain, to be * used next time domain is started */ int virDomainSnapshotActivate(virDomainSnapshotPtr snapshot, unsigned int flags); /* Deactivate 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 base image. With a DISCARD flag, it deletes the snapshot. MERGE * and DISCARD are mutually-exclusive. Note that this operation can * generally only happen when the domain is shut down, though this is * hypervisor-specific */ typedef enum { VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD, } virDomainSnapshotDeactivate; int virDomainSnapshotDeactivate(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> for you, the <creationdate> will be set to the current time+date, <description> will be empty, <state> will be "off", <compression> will be empty, and <parent> will be empty. If you do want to specify some fields during virDomainSnapshotCreateXML(), note that the only ones that are settable are <name>, <description>, <compression>, and <parent>; the rest are ignored, and filled in by the driver when the snapshot is actually created. NOTE: <parent> is used to create "trees" of snapshots, and may or may not be supported by individual hypervisor implementations. If <parent> is specified and the underlying hypervisor does not support it, an error will be thrown. NOTE: <compression> is used to compress snapshots, and may or may not be supported by individual hypervisor implementations. If <compression> is specified and the underlying hypervisor does not support it, an error will be thrown. <domainsnapshot> <name>XYZ</name> <creationdate>...</creationdate> <description> ....blah.... </description> <state>RUNNING</state> <domain> <uuid>XXXXX-XXXX-XXXX-XXXX-XXXXXXXXX</uuid> </domain> <compression>gzip</compression> <parent> <name>ABC</name> </parent> </domainsnapshot> The virsh commands will be: virsh snapshot-create [--compress] <dom> <xmlfile> virsh snapshot-list <dom> virsh snapshot-dumpxml <dom> <name> virsh snapshot-activate <dom> <snapshotname> virsh snapshot-deactivate <dom> <snapshotname> [--merge|--delete] -- Chris Lalancette

2010/3/23 Chris Lalancette <clalance@redhat.com>:
Hello, As some of you know, I've been working on a new snapshot API. This API is heavily based on DanB's earlier API proposed here:
https://www.redhat.com/archives/libvir-list/2010-January/msg00626.html
I've made some modifications to make it more libvirt-ish, and to add a couple of features I think it lacked. The full documentation is below. Any comments are appreciated.
/* NOTE: struct _virDomainSnapshot is a private structure, ala * struct _virDomain. */ typedef struct _virDomainSnapshot virDomainSnapshot;
/* Take a snapshot of the current VM state */ 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);
Shouldn't this be called virDomainNumOfSnapshots to be consistent with the naming or other num-of functions?
/* 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);
/* Set this snapshot as the current one for a domain, to be * used next time domain is started */ int virDomainSnapshotActivate(virDomainSnapshotPtr snapshot, unsigned int flags);
This delayed semantic cannot be implemented for ESX. ESX can revert to a snapshot immediately only. I think the same holds true for VirtualBox. Maybe I misunterstand this. What should happen if you call activate on a running domain?
/* Deactivate 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 base image. With a DISCARD flag, it deletes the snapshot. MERGE * and DISCARD are mutually-exclusive. Note that this operation can * generally only happen when the domain is shut down, though this is * hypervisor-specific */ typedef enum { VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD, } virDomainSnapshotDeactivate; int virDomainSnapshotDeactivate(virDomainSnapshotPtr snapshot, unsigned int flags);
I'm not sure if virDomainSnapshotDeactivate is a good name. Why would I deactivate a snapshot, but not merge/discard it? What's the use case for this?
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> for you, the <creationdate> will be set to the current time+date, <description> will be empty, <state> will be "off", <compression> will be empty, and <parent> will be empty. If you do want to specify some fields during virDomainSnapshotCreateXML(), note that the only ones that are settable are <name>, <description>, <compression>, and <parent>; the rest are ignored,
How can <parent> be settable? If I have snapshots A and B A -> B -> current state and I create a new snapshot C, then B will be the parent of C. A -> B -> C -> current state If I create another snapshot D now and specify A to be its parent, what's supposed to happen then? Matthias

On 03/23/2010 02:35 PM, Matthias Bolte wrote:
2010/3/23 Chris Lalancette <clalance@redhat.com>:
Hello, As some of you know, I've been working on a new snapshot API. This API is heavily based on DanB's earlier API proposed here:
https://www.redhat.com/archives/libvir-list/2010-January/msg00626.html
I've made some modifications to make it more libvirt-ish, and to add a couple of features I think it lacked. The full documentation is below. Any comments are appreciated.
/* NOTE: struct _virDomainSnapshot is a private structure, ala * struct _virDomain. */ typedef struct _virDomainSnapshot virDomainSnapshot;
/* Take a snapshot of the current VM state */ 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);
Shouldn't this be called virDomainNumOfSnapshots to be consistent with the naming or other num-of functions?
Gah. I struggled with this; I like the fact that all of the rest of them start with virDomainSnapshot; this one doesn't fit the mold. I don't care too much either way.
/* 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);
/* Set this snapshot as the current one for a domain, to be * used next time domain is started */ int virDomainSnapshotActivate(virDomainSnapshotPtr snapshot, unsigned int flags);
This delayed semantic cannot be implemented for ESX. ESX can revert to a snapshot immediately only. I think the same holds true for VirtualBox.
Maybe I misunterstand this. What should happen if you call activate on a running domain?
Ah, I see what you mean. I understood the intent from DanB's initial email differently. The way I understood it is to make this snapshot the current snapshot for a shut-off domain, so that when it is started, it is started with this snapshot. That way, you could choose from among a tree of snapshots as to which one you want to boot right now. If you ran this against a running guest, it would throw an error. Maybe DanB can tell us which of these interpretations is correct, though. Your point (about reverting to a state before the snapshot) is covered by deactivate (discussed below).
/* Deactivate 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 base image. With a DISCARD flag, it deletes the snapshot. MERGE * and DISCARD are mutually-exclusive. Note that this operation can * generally only happen when the domain is shut down, though this is * hypervisor-specific */ typedef enum { VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD, } virDomainSnapshotDeactivate; int virDomainSnapshotDeactivate(virDomainSnapshotPtr snapshot, unsigned int flags);
I'm not sure if virDomainSnapshotDeactivate is a good name.
I agree it's not a great name. I didn't like Dan's original proposal of "virDomainSnapshotDelete", though, since it doesn't exactly seem to fit the situation either. Any more suggestions for a name?
Why would I deactivate a snapshot, but not merge/discard it? What's the use case for this?
The use case I was thinking about mostly involved debugging (and comes from my experience debugging qemu guests). Say you took a snapshot of a guest, and after running for a while discovered some sort of bug in the guest software. You might then keep the memory image of that snapshot around so that you could run "crash" or "gdb" against it to extract some data. It's kind of an esoteric use-case, I'll admit, but I have found it somewhat useful in the past.
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> for you, the <creationdate> will be set to the current time+date, <description> will be empty, <state> will be "off", <compression> will be empty, and <parent> will be empty. If you do want to specify some fields during virDomainSnapshotCreateXML(), note that the only ones that are settable are <name>, <description>, <compression>, and <parent>; the rest are ignored,
How can <parent> be settable? If I have snapshots A and B
A -> B -> current state
and I create a new snapshot C, then B will be the parent of C.
A -> B -> C -> current state
If I create another snapshot D now and specify A to be its parent, what's supposed to happen then?
You are right, that doesn't make that much sense. I have to admit that the tree structure is the part I thought about least, so I'll take that part back. <parent> is just going to be an informational field about which snapshot was current (if any) when this one was created. -- Chris Lalancette

On 03/23/2010 01:23 PM, Chris Lalancette wrote:
} virDomainSnapshotDeactivate;
int virDomainSnapshotDeactivate(virDomainSnapshotPtr snapshot, unsigned int flags);
I'm not sure if virDomainSnapshotDeactivate is a good name. I agree it's not a great name. I didn't like Dan's original proposal of "virDomainSnapshotDelete", though, since it doesn't exactly seem to fit the situation either. Any more suggestions for a name?
I agree that Delete is misleading, but it kind of works (as long as you remember that in the merge case, the data being deleted is not the snapshot parameter that you passed to the function call, but the delta in state between the more-recent content that is being rolled back to the state it was earlier during the snapshot). Maybe some other ideas would work: virDomainSnapshotCleanup or virDomainSnapshotRecycle? After all, the goal of this API is to reduce the amount of storage pool being used to store snapshot images. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Tue, Mar 23, 2010 at 01:48:19PM -0600, Eric Blake wrote:
On 03/23/2010 01:23 PM, Chris Lalancette wrote:
} virDomainSnapshotDeactivate;
int virDomainSnapshotDeactivate(virDomainSnapshotPtr snapshot, unsigned int flags);
I'm not sure if virDomainSnapshotDeactivate is a good name. I agree it's not a great name. I didn't like Dan's original proposal of "virDomainSnapshotDelete", though, since it doesn't exactly seem to fit the situation either. Any more suggestions for a name?
I agree that Delete is misleading, but it kind of works (as long as you remember that in the merge case, the data being deleted is not the snapshot parameter that you passed to the function call, but the delta in state between the more-recent content that is being rolled back to the state it was earlier during the snapshot). Maybe some other ideas would work: virDomainSnapshotCleanup or virDomainSnapshotRecycle? After all, the goal of this API is to reduce the amount of storage pool being used to store snapshot images.
I like virDomainSnapshotCleanup() myself, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, Mar 23, 2010 at 01:48:19PM -0600, Eric Blake wrote:
On 03/23/2010 01:23 PM, Chris Lalancette wrote:
} virDomainSnapshotDeactivate;
int virDomainSnapshotDeactivate(virDomainSnapshotPtr snapshot, unsigned int flags);
I'm not sure if virDomainSnapshotDeactivate is a good name. I agree it's not a great name. I didn't like Dan's original proposal of "virDomainSnapshotDelete", though, since it doesn't exactly seem to fit the situation either. Any more suggestions for a name?
I agree that Delete is misleading, but it kind of works (as long as you remember that in the merge case, the data being deleted is not the snapshot parameter that you passed to the function call, but the delta in state between the more-recent content that is being rolled back to the state it was earlier during the snapshot). Maybe some other ideas would work: virDomainSnapshotCleanup or virDomainSnapshotRecycle? After all, the goal of this API is to reduce the amount of storage pool being used to store snapshot images.
The reason for calling this "Delete" is that we are deleting thue virDomainSnapshotPtr object instance - it ceases to exist after this operation is called. 'Delete' is not refering to the data itself, the flags determine what happens to the data. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

/* Return the number of snapshots for this domain */ int virDomainSnapshotNum(virDomainPtr domain, unsigned int flags);
Shouldn't this be called virDomainNumOfSnapshots to be consistent with the naming or other num-of functions?
Gah. I struggled with this; I like the fact that all of the rest of them start with virDomainSnapshot; this one doesn't fit the mold. I don't care too much either way.
virDomain*Snapshots for APIs that take a virDomainPtr seems consistent too.
/* Deactivate 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 base image. With a DISCARD flag, it deletes the snapshot. MERGE * and DISCARD are mutually-exclusive. Note that this operation can * generally only happen when the domain is shut down, though this is * hypervisor-specific */ typedef enum { VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD, } virDomainSnapshotDeactivate; int virDomainSnapshotDeactivate(virDomainSnapshotPtr snapshot, unsigned int flags);
I'm not sure if virDomainSnapshotDeactivate is a good name.
I agree it's not a great name. I didn't like Dan's original proposal of "virDomainSnapshotDelete", though, since it doesn't exactly seem to fit the situation either. Any more suggestions for a name?
Several things are not clear about this API to me too. :-) 1) Would discarding also discard all the snapshots depending on the discarded one. If so, what about a --force flag that you need to pass if the delete operation would delete other snapshots recursively? 2) Likewise, merging would invalidate all the other snapshots depending on the base image (and discard them). The same --force option then could apply as well. However, I think there is a fundamental difference between the two cases; only one of them modifies the base image I'm not sure that something that modifies the base image rightfully belongs into the virDomainSnapshot* namespace. So my proposal would be /* Start using the base image again. If snapshot != NULL, merge the given snapshot in the base image again. */ virDomainDisableSnapshots(virDomainPtr domain, virDomainSnapshotPtr snapshot, int flags); /* Discard the given snapshot and, if --force is given, all that depend on it. Fail if it is active. */ virDomainSnapshotDiscard(virDomainSnapshotPtr snapshot, int flags);
Why would I deactivate a snapshot, but not merge/discard it? What's the use case for this?
The use case I was thinking about mostly involved debugging (and comes from my experience debugging qemu guests). Say you took a snapshot of a guest, and after running for a while discovered some sort of bug in the guest software. You might then keep the memory image of that snapshot around so that you could run "crash" or "gdb" against it to extract some data. It's kind of an esoteric use-case, I'll admit, but I have found it somewhat useful in the past.
If your guest crashes in production (not just a kernel crash, even an application crash) and you want to restart it from the previous existing snapshot, you probably still want to keep the other snapshot around so that you can copy it to another machine, start it there, and do post-mortem debugging. In this case, however, you would likely activate another snapshot rather than deactivating the one that crashed. See below for another suggestion about how to handle this.
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/>".
Maybe it's worthwhile having a simple virDomainSnapshotCreate() API for this? (Or at least making the xml argument optional in virsh).
How can<parent> be settable? If I have snapshots A and B
A -> B -> current state
and I create a new snapshot C, then B will be the parent of C.
A -> B -> C -> current state
If I create another snapshot D now and specify A to be its parent, what's supposed to happen then?
You are right, that doesn't make that much sense. I have to admit that the tree structure is the part I thought about least, so I'll take that part back. <parent> is just going to be an informational field about which snapshot was current (if any) when this one was created.
If discarding a snapshot also discards the children, it would definitely make sense to be able to specify the parent. If you do not want to allow setting the parent, you can also add a flag --inactive to virsh snapshot-create that would create the snapshot without making it active. Then you would make <parent> an informational field about which snapshot was *active* when the new one was created. In the end the virsh commands would be virsh snapshot-create <dom> [<xmlfile>] [--compress] [--inactive] virsh snapshot-list <dom> virsh snapshot-dumpxml <dom> <name> virsh snapshot-activate <dom> <snapshotname> virsh snapshot-discard <dom> <snapshotname> [--force] virsh snapshot-disable <dom> [<snapshotname>] What do you think? Paolo

On Wed, Mar 24, 2010 at 09:52:51AM +0100, Paolo Bonzini wrote:
/* Return the number of snapshots for this domain */ int virDomainSnapshotNum(virDomainPtr domain, unsigned int flags);
Shouldn't this be called virDomainNumOfSnapshots to be consistent with the naming or other num-of functions?
Gah. I struggled with this; I like the fact that all of the rest of them start with virDomainSnapshot; this one doesn't fit the mold. I don't care too much either way.
virDomain*Snapshots for APIs that take a virDomainPtr seems consistent too.
/* Deactivate 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 base image. With a DISCARD flag, it deletes the snapshot. MERGE * and DISCARD are mutually-exclusive. Note that this operation can * generally only happen when the domain is shut down, though this is * hypervisor-specific */ typedef enum { VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD, } virDomainSnapshotDeactivate; int virDomainSnapshotDeactivate(virDomainSnapshotPtr snapshot, unsigned int flags);
I'm not sure if virDomainSnapshotDeactivate is a good name.
I agree it's not a great name. I didn't like Dan's original proposal of "virDomainSnapshotDelete", though, since it doesn't exactly seem to fit the situation either. Any more suggestions for a name?
Several things are not clear about this API to me too. :-)
1) Would discarding also discard all the snapshots depending on the discarded one. If so, what about a --force flag that you need to pass if the delete operation would delete other snapshots recursively?
Yes, if there were children of this snapshot they would be killed. Agreed, that we could use a flag to allow that behaviour to be controlled, either refusing to discard children, or forcing discard.
2) Likewise, merging would invalidate all the other snapshots depending on the base image (and discard them). The same --force option then could apply as well.
It would only discard snapshots depending on the snapshot being merge onto, eg in +-> F | A -> B -> C -> D | +-> G If you merged D onto C, then A, B, F & G would all still be valid: +-> F | A -> B -> C | +-> G If you merged C onto B, then F & G would be invalid, but D would still be valid A -> B ------> D
However, I think there is a fundamental difference between the two cases; only one of them modifies the base image I'm not sure that something that modifies the base image rightfully belongs into the virDomainSnapshot* namespace. So my proposal would be
/* Start using the base image again. If snapshot != NULL, merge the given snapshot in the base image again. */ virDomainDisableSnapshots(virDomainPtr domain, virDomainSnapshotPtr snapshot, int flags);
/* Discard the given snapshot and, if --force is given, all that depend on it. Fail if it is active. */ virDomainSnapshotDiscard(virDomainSnapshotPtr snapshot, int flags);
I don't see any need to special case the base image here. The main virDOmainSnapshotDelete() API already lets you discard all snapshots until you get to the base image - VMWare/VirtualBox already demonstrate this is sufficient. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On 03/24/2010 12:02 PM, Daniel P. Berrange wrote:
I don't see any need to special case the base image here. The main virDOmainSnapshotDelete() API already lets you discard all snapshots until you get to the base image - VMWare/VirtualBox already demonstrate this is sufficient.
Is this as efficient though? Discarding all snapshots could be reasonably expected to be O(1). If you say this is not a common operation, that's fine of course. Even without special casing the base image, I'm a bit uneasy that a virDomainSnapshot* API touches the base image. What do you think about leaving the merge operation as a virDomain* API, e.g. virDomainRebase? Paolo

On 03/24/2010 04:52 AM, Paolo Bonzini wrote:
/* Deactivate 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 base image. With a DISCARD flag, it deletes the snapshot. MERGE * and DISCARD are mutually-exclusive. Note that this operation can * generally only happen when the domain is shut down, though this is * hypervisor-specific */ typedef enum { VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD, } virDomainSnapshotDeactivate; int virDomainSnapshotDeactivate(virDomainSnapshotPtr snapshot, unsigned int flags);
I'm not sure if virDomainSnapshotDeactivate is a good name.
I agree it's not a great name. I didn't like Dan's original proposal of "virDomainSnapshotDelete", though, since it doesn't exactly seem to fit the situation either. Any more suggestions for a name?
Several things are not clear about this API to me too. :-)
1) Would discarding also discard all the snapshots depending on the discarded one. If so, what about a --force flag that you need to pass if the delete operation would delete other snapshots recursively?
Good thought. I'll add a VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD_FORCE flag (to be renamed later, but the semantic will be what you say).
2) Likewise, merging would invalidate all the other snapshots depending on the base image (and discard them). The same --force option then could apply as well.
Right, also a good idea, I'll also add VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE_FORCE.
However, I think there is a fundamental difference between the two cases; only one of them modifies the base image I'm not sure that something that modifies the base image rightfully belongs into the virDomainSnapshot* namespace. So my proposal would be
/* Start using the base image again. If snapshot != NULL, merge the given snapshot in the base image again. */ virDomainDisableSnapshots(virDomainPtr domain, virDomainSnapshotPtr snapshot, int flags);
/* Discard the given snapshot and, if --force is given, all that depend on it. Fail if it is active. */ virDomainSnapshotDiscard(virDomainSnapshotPtr snapshot, int flags);
Given Dan's alternate proposal of virDomainCreateWithSnapshot, I don't think this is necessary. That is, if you wanted to start a guest from it's base image, you would call "virDomainCreate". If you wanted to start a guest from a snapshot, you would call "virDomainCreateWithSnapshot". If you want to remove a snapshot, you would call virDomainSnapshotDeactivate. I agree that the fact that virDomainSnapshotDeactivate has the possibility to modify the base image makes it more dangerous than others, but it won't be the default and it is an integral part of snapshotting.
Why would I deactivate a snapshot, but not merge/discard it? What's the use case for this?
The use case I was thinking about mostly involved debugging (and comes from my experience debugging qemu guests). Say you took a snapshot of a guest, and after running for a while discovered some sort of bug in the guest software. You might then keep the memory image of that snapshot around so that you could run "crash" or "gdb" against it to extract some data. It's kind of an esoteric use-case, I'll admit, but I have found it somewhat useful in the past.
If your guest crashes in production (not just a kernel crash, even an application crash) and you want to restart it from the previous existing snapshot, you probably still want to keep the other snapshot around so that you can copy it to another machine, start it there, and do post-mortem debugging.
In this case, however, you would likely activate another snapshot rather than deactivating the one that crashed. See below for another suggestion about how to handle this.
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/>".
Maybe it's worthwhile having a simple virDomainSnapshotCreate() API for this? (Or at least making the xml argument optional in virsh).
Good point. I could allow virDomainSnapshotCreateXML to take a NULL pointer, which would be interpreted as "<domainsnapshot/>", but that doesn't seem to fit in with the rest of the libvirt API. I think I'll just allow virsh to take an optional XML file, which I'll then pass in as "<domainsnapshot/>".
How can<parent> be settable? If I have snapshots A and B
A -> B -> current state
and I create a new snapshot C, then B will be the parent of C.
A -> B -> C -> current state
If I create another snapshot D now and specify A to be its parent, what's supposed to happen then?
You are right, that doesn't make that much sense. I have to admit that the tree structure is the part I thought about least, so I'll take that part back. <parent> is just going to be an informational field about which snapshot was current (if any) when this one was created.
If discarding a snapshot also discards the children, it would definitely make sense to be able to specify the parent.
The problem, though, is what Mattias points out; there is no (easy) way that, given state C, I can get back to state A to make a new snapshot. I actually have to be at state A to take a new snapshot with a parent of A. I think this is a place where we have to make it manual; if you really want a new snapshot that is a child of A, you'll have to manually shutdown your domain, boot to snapshot A, then take a snapshot of A.
If you do not want to allow setting the parent, you can also add a flag --inactive to virsh snapshot-create that would create the snapshot without making it active. Then you would make <parent> an informational field about which snapshot was *active* when the new one was created.
That's more or less what the <parent> field is supposed to mean, although I'm not sure I understand your proposal about --inactive. How would you go about doing that? -- Chris Lalancette

On Wed, Mar 24, 2010 at 09:09:08AM -0400, Chris Lalancette wrote:
On 03/24/2010 04:52 AM, Paolo Bonzini wrote:
How can<parent> be settable? If I have snapshots A and B
A -> B -> current state
and I create a new snapshot C, then B will be the parent of C.
A -> B -> C -> current state
If I create another snapshot D now and specify A to be its parent, what's supposed to happen then?
You are right, that doesn't make that much sense. I have to admit that the tree structure is the part I thought about least, so I'll take that part back. <parent> is just going to be an informational field about which snapshot was current (if any) when this one was created.
If discarding a snapshot also discards the children, it would definitely make sense to be able to specify the parent.
The problem, though, is what Mattias points out; there is no (easy) way that, given state C, I can get back to state A to make a new snapshot. I actually have to be at state A to take a new snapshot with a parent of A. I think this is a place where we have to make it manual; if you really want a new snapshot that is a child of A, you'll have to manually shutdown your domain, boot to snapshot A, then take a snapshot of A.
This is something virDomainCreateAtSnapshot() should solve. If you have a series A -> B -> C And you do virDomainCreateAtSnapshot(dom, "A"), then you get 'D' A -> B -> C | \-> D B & C are still valid IIUC, this is how VMWare works & we essentially need our API to map to that since VirtualBox seems to follow the VMWare model too & there's no reason that QEMU can't too. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

2010/3/24 Daniel P. Berrange <berrange@redhat.com>:
On Wed, Mar 24, 2010 at 09:09:08AM -0400, Chris Lalancette wrote:
On 03/24/2010 04:52 AM, Paolo Bonzini wrote:
How can<parent> be settable? If I have snapshots A and B
A -> B -> current state
and I create a new snapshot C, then B will be the parent of C.
A -> B -> C -> current state
If I create another snapshot D now and specify A to be its parent, what's supposed to happen then?
You are right, that doesn't make that much sense. I have to admit that the tree structure is the part I thought about least, so I'll take that part back. <parent> is just going to be an informational field about which snapshot was current (if any) when this one was created.
If discarding a snapshot also discards the children, it would definitely make sense to be able to specify the parent.
The problem, though, is what Mattias points out; there is no (easy) way that, given state C, I can get back to state A to make a new snapshot. I actually have to be at state A to take a new snapshot with a parent of A. I think this is a place where we have to make it manual; if you really want a new snapshot that is a child of A, you'll have to manually shutdown your domain, boot to snapshot A, then take a snapshot of A.
This is something virDomainCreateAtSnapshot() should solve.
If you have a series
A -> B -> C
And you do virDomainCreateAtSnapshot(dom, "A"), then you get 'D'
A -> B -> C | \-> D
You mean you get D when you do a virDomainSnapshotCreateXML(dom, NULL) _after_ you've done a virDomainCreateAtSnapshot(dom, "A"), don't you?
B & C are still valid
IIUC, this is how VMWare works & we essentially need our API to map to that since VirtualBox seems to follow the VMWare model too & there's no reason that QEMU can't too.
Yes, that's how I understand the VMware and VirtualBox snapshot model. I'll do some testing to be really sure. Matthias

On Wed, Mar 24, 2010 at 02:42:30PM +0100, Matthias Bolte wrote:
2010/3/24 Daniel P. Berrange <berrange@redhat.com>:
On Wed, Mar 24, 2010 at 09:09:08AM -0400, Chris Lalancette wrote:
On 03/24/2010 04:52 AM, Paolo Bonzini wrote:
How can<parent> be settable? If I have snapshots A and B
A -> B -> current state
and I create a new snapshot C, then B will be the parent of C.
A -> B -> C -> current state
If I create another snapshot D now and specify A to be its parent, what's supposed to happen then?
You are right, that doesn't make that much sense. I have to admit that the tree structure is the part I thought about least, so I'll take that part back. <parent> is just going to be an informational field about which snapshot was current (if any) when this one was created.
If discarding a snapshot also discards the children, it would definitely make sense to be able to specify the parent.
The problem, though, is what Mattias points out; there is no (easy) way that, given state C, I can get back to state A to make a new snapshot. I actually have to be at state A to take a new snapshot with a parent of A. I think this is a place where we have to make it manual; if you really want a new snapshot that is a child of A, you'll have to manually shutdown your domain, boot to snapshot A, then take a snapshot of A.
This is something virDomainCreateAtSnapshot() should solve.
If you have a series
A -> B -> C
And you do virDomainCreateAtSnapshot(dom, "A"), then you get 'D'
A -> B -> C | \-> D
You mean you get D when you do a virDomainSnapshotCreateXML(dom, NULL) _after_ you've done a virDomainCreateAtSnapshot(dom, "A"), don't you?
Well I'll have to look up what VMWare does really, since their behaviour is what I intended Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On 03/24/2010 02:09 PM, Chris Lalancette wrote:
The problem, though, is what Mattias points out; there is no (easy) way that, given state C, I can get back to state A to make a new snapshot. I actually have to be at state A to take a new snapshot with a parent of A. I think this is a place where we have to make it manual; if you really want a new snapshot that is a child of A, you'll have to manually shutdown your domain, boot to snapshot A, then take a snapshot of A.
Yes, exactly. See my description of --inactive below.
If you do not want to allow setting the parent, you can also add a flag --inactive to virsh snapshot-create that would create the snapshot without making it active. Then you would make<parent> an informational field about which snapshot was*active* when the new one was created.
That's more or less what the<parent> field is supposed to mean, although I'm not sure I understand your proposal about --inactive. How would you go about doing that?
Say you were on snapshot A and the guest has a problem. The easiest fix is reverting to snapshot A, but you want to investigate it anyway. You create snapshot B with --inactive and, if you want, you can move the snapshot to another machine to activate it and look at it more calmly. If the problem reproduces, you can create another inactive snapshot, and so on. Alternatively, say the easiest fix is stopping and starting a daemon, but again you want to keep a snapshot to investigate it anyway. You can create the inactive snapshot B and stop/start the daemon _while the system is live and running under snapshot A_, i.e. without manually shutting down and rebooting. Is this clearer? Paolo

On 03/24/2010 10:40 AM, Paolo Bonzini wrote:
If you do not want to allow setting the parent, you can also add a flag --inactive to virsh snapshot-create that would create the snapshot without making it active. Then you would make<parent> an informational field about which snapshot was*active* when the new one was created.
That's more or less what the<parent> field is supposed to mean, although I'm not sure I understand your proposal about --inactive. How would you go about doing that?
Say you were on snapshot A and the guest has a problem. The easiest fix is reverting to snapshot A, but you want to investigate it anyway. You create snapshot B with --inactive and, if you want, you can move the snapshot to another machine to activate it and look at it more calmly.
If the problem reproduces, you can create another inactive snapshot, and so on.
Alternatively, say the easiest fix is stopping and starting a daemon, but again you want to keep a snapshot to investigate it anyway. You can create the inactive snapshot B and stop/start the daemon _while the system is live and running under snapshot A_, i.e. without manually shutting down and rebooting.
Is this clearer?
Much clearer, thank you. So you are still snapshotting the *current* image, but sort of storing it away for future reference. That's where my confusion was. This seems like a good debugging aid; the only question is whether the hypervisors can support this kind of thing. I guess we can always emulate it by taking a snapshot and then immediately reverting to the parent. -- Chris Lalancette

On Tue, Mar 23, 2010 at 03:23:36PM -0400, Chris Lalancette wrote:
On 03/23/2010 02:35 PM, Matthias Bolte wrote:
2010/3/23 Chris Lalancette <clalance@redhat.com>:
Hello, As some of you know, I've been working on a new snapshot API. This API is heavily based on DanB's earlier API proposed here:
https://www.redhat.com/archives/libvir-list/2010-January/msg00626.html
I've made some modifications to make it more libvirt-ish, and to add a couple of features I think it lacked. The full documentation is below. Any comments are appreciated.
/* NOTE: struct _virDomainSnapshot is a private structure, ala * struct _virDomain. */ typedef struct _virDomainSnapshot virDomainSnapshot;
/* Take a snapshot of the current VM state */ 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);
Shouldn't this be called virDomainNumOfSnapshots to be consistent with the naming or other num-of functions?
Gah. I struggled with this; I like the fact that all of the rest of them start with virDomainSnapshot; this one doesn't fit the mold. I don't care too much either way.
/* 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);
/* Set this snapshot as the current one for a domain, to be * used next time domain is started */ int virDomainSnapshotActivate(virDomainSnapshotPtr snapshot, unsigned int flags);
This delayed semantic cannot be implemented for ESX. ESX can revert to a snapshot immediately only. I think the same holds true for VirtualBox.
Maybe I misunterstand this. What should happen if you call activate on a running domain?
Ah, I see what you mean. I understood the intent from DanB's initial email differently. The way I understood it is to make this snapshot the current snapshot for a shut-off domain, so that when it is started, it is started with this snapshot. That way, you could choose from among a tree of snapshots as to which one you want to boot right now. If you ran this against a running guest, it would throw an error. Maybe DanB can tell us which of these interpretations is correct, though.
Actually, I don't think this makes sense even for QEMU. I think we just need an atomic API again virDomain that starts from a snapshot virDomainCreateAtSnapshot(virDomainPtr, virDomainSnapshotPtr snapshot);
/* Deactivate 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 base image. With a DISCARD flag, it deletes the snapshot. MERGE * and DISCARD are mutually-exclusive. Note that this operation can * generally only happen when the domain is shut down, though this is * hypervisor-specific */ typedef enum { VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD, } virDomainSnapshotDeactivate; int virDomainSnapshotDeactivate(virDomainSnapshotPtr snapshot, unsigned int flags);
I'm not sure if virDomainSnapshotDeactivate is a good name.
I agree it's not a great name. I didn't like Dan's original proposal of "virDomainSnapshotDelete", though, since it doesn't exactly seem to fit the situation either. Any more suggestions for a name?
Agreed, deactivate isn't a good name. This really is about deleting a virDomainSnapshotPtr object instance. The flags control what happens to the data associated with the snapshot, either the data is thrown away (DISCARD), or the data is merged into the earlier snapshot object instance (MERGE). So, I still think virDomainSnapshotDelete is the right name here.
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> for you, the <creationdate> will be set to the current time+date, <description> will be empty, <state> will be "off", <compression> will be empty, and <parent> will be empty. If you do want to specify some fields during virDomainSnapshotCreateXML(), note that the only ones that are settable are <name>, <description>, <compression>, and <parent>; the rest are ignored,
How can <parent> be settable? If I have snapshots A and B
A -> B -> current state
and I create a new snapshot C, then B will be the parent of C.
A -> B -> C -> current state
If I create another snapshot D now and specify A to be its parent, what's supposed to happen then?
You are right, that doesn't make that much sense. I have to admit that the tree structure is the part I thought about least, so I'll take that part back. <parent> is just going to be an informational field about which snapshot was current (if any) when this one was created.
Agreed, <parent> should just be a output only value. Only the name/description & compession really make sense. Everything else is automatically determined Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Tue, Mar 23, 2010 at 07:35:22PM +0100, Matthias Bolte wrote:
2010/3/23 Chris Lalancette <clalance@redhat.com>:
/* Return the number of snapshots for this domain */ int virDomainSnapshotNum(virDomainPtr domain, unsigned int flags);
Shouldn't this be called virDomainNumOfSnapshots to be consistent with the naming or other num-of functions?
Yeah that would be a bit nicer, not fundamental though :-)
/* 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);
/* Set this snapshot as the current one for a domain, to be * used next time domain is started */ int virDomainSnapshotActivate(virDomainSnapshotPtr snapshot, unsigned int flags);
This delayed semantic cannot be implemented for ESX. ESX can revert to a snapshot immediately only. I think the same holds true for VirtualBox.
Maybe I misunterstand this. What should happen if you call activate on a running domain?
I guess we really need to use the flags there, and check for the flag semantic in the driver. In ESX we will need a VIR_DOMAIN_SNAPSHOT_ACTIVATE_NOW flag to be passed In QEmu we will need a VIR_DOMAIN_SNAPSHOT_ACTIVATE_RESTART to be passed Or we split that as two different entry points as the semantic is fairly different. This may be a bit cleaner, for example if you think of a virsh command, virsh snap_activate --now foo snap1 virsh snap_activate --restart foo snap1 where the command without flags would be rejected because there is no common semantic, versus something like virsh snap_use foo snap1 virsh snap_restart foo snap1 where using snap_use on qemu would raise a unsupported or snap_restart on ESX. Semantic is so different, we can't use it without some flags or have virsh snap_activate foo snap1 fail while virsh snap_activate --restart foo snap1 would work, that's disturbing. So I really think we need 2 different entry point virDomainSnapshotActivateNow virDomainSnapshotActivateLater for example (and still with flags)
int virDomainSnapshotFree(virDomainSnapshotPtr snapshot);
Shouldn't we add something like virDomainSnapshotDestroy() too assuming the semantic of Free is just to discard the libvirt object but not remove the actual data. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On 03/24/2010 05:51 AM, Daniel Veillard wrote:
/* Set this snapshot as the current one for a domain, to be * used next time domain is started */ int virDomainSnapshotActivate(virDomainSnapshotPtr snapshot, unsigned int flags);
This delayed semantic cannot be implemented for ESX. ESX can revert to a snapshot immediately only. I think the same holds true for VirtualBox.
Maybe I misunterstand this. What should happen if you call activate on a running domain?
I guess we really need to use the flags there, and check for the flag semantic in the driver. In ESX we will need a VIR_DOMAIN_SNAPSHOT_ACTIVATE_NOW flag to be passed In QEmu we will need a VIR_DOMAIN_SNAPSHOT_ACTIVATE_RESTART to be passed
Or we split that as two different entry points as the semantic is fairly different. This may be a bit cleaner, for example if you think of a virsh command, virsh snap_activate --now foo snap1 virsh snap_activate --restart foo snap1
where the command without flags would be rejected because there is no common semantic, versus something like
virsh snap_use foo snap1 virsh snap_restart foo snap1
where using snap_use on qemu would raise a unsupported or snap_restart on ESX.
Semantic is so different, we can't use it without some flags or have virsh snap_activate foo snap1 fail while virsh snap_activate --restart foo snap1 would work, that's disturbing.
So I really think we need 2 different entry point
virDomainSnapshotActivateNow
virDomainSnapshotActivateLater
for example (and still with flags)
Yeah, this is the weak point of the whole thing. I actually think that I agree with Dan and Mattias now that we just need "virDomainSnapshotCreateWithSnapshot" API that starts this domain now against this particular snapshot. That way you don't have the (potentially confusing) semantic of activating a snapshot, and then it taking effect on the next reboot.
int virDomainSnapshotFree(virDomainSnapshotPtr snapshot);
Shouldn't we add something like virDomainSnapshotDestroy() too assuming the semantic of Free is just to discard the libvirt object but not remove the actual data.
Right, virDomainSnapshotFree() is just freeing up the libvirt object, not removing the data. The API that removes the data is the contended virDomainSnapshotDelete/virDomainSnapshotDeactivate... etc discussion. The name is honestly not that important at the moment; I'll probably leave it as Deactivate in my current patches and then we can come up with a final name once I post the patches. -- Chris Lalancette

Based on discussion, I've modified the snapshot API to the below. I've incorporated most of the semantic changes we talked about; the renaming of various API calls I've left for later, since it is a minor point. More comments 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); /* Start the guest "domain" from the snapshot "snapshot" */ int virDomainCreateWithSnapshot(virDomainPtr domain, virDomainSnapshotPtr snapshot, unsigned int flags); /* Deactivate 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 other 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 generally only happen when the domain is shut * down, though this is hypervisor-specific */ typedef enum { VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE_FORCE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD_FORCE, } virDomainSnapshotDeactivate; int virDomainSnapshotDeactivate(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> for you, the <creationdate> will be set to the current time+date, <description> will be empty, <state> will be "off", <compression> will be empty, 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>, <description>, and <compression>; the rest are ignored, and filled in by the driver when the snapshot is actually created. NOTE: <compression> is used to compress snapshots, and may or may not be supported by individual hypervisor implementations. If <compression> is specified and the underlying hypervisor does not support it, an error will be thrown. <domainsnapshot> <name>XYZ</name> <creationdate>...</creationdate> <description>...</description> <state>RUNNING</state> <domain> <uuid>XXXXX-XXXX-XXXX-XXXX-XXXXXXXXX</uuid> </domain> <compression>gzip</compression> <parent> <name>ABC</name> </parent> </domainsnapshot> The virsh commands will be: virsh snapshot-create [--compress] <dom> <xmlfile> virsh snapshot-list <dom> virsh snapshot-dumpxml <dom> <name> virsh create-with-snapshot <dom> <snapshotname> virsh snapshot-deactivate <dom> <snapshotname> [--merge|--delete|--mergeforce|--mergedelete] -- Chris Lalancette

On Wed, Mar 24, 2010 at 09:16:46AM -0400, Chris Lalancette wrote:
Based on discussion, I've modified the snapshot API to the below. I've incorporated most of the semantic changes we talked about; the renaming of various API calls I've left for later, since it is a minor point. More comments 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);
/* Start the guest "domain" from the snapshot "snapshot" */ int virDomainCreateWithSnapshot(virDomainPtr domain, virDomainSnapshotPtr snapshot, unsigned int flags);
/* Deactivate 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 other 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 generally only happen when the domain is shut * down, though this is hypervisor-specific */ typedef enum { VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE_FORCE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD_FORCE, } virDomainSnapshotDeactivate; int virDomainSnapshotDeactivate(virDomainSnapshotPtr snapshot, unsigned int flags);
This is still better as 'Delete'. Deactivate implies that the snapshot has a boolean state where it can switch between active & inactive, which is not the case here. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

2010/3/24 Chris Lalancette <clalance@redhat.com>:
Based on discussion, I've modified the snapshot API to the below. I've incorporated most of the semantic changes we talked about; the renaming of various API calls I've left for later, since it is a minor point. More comments 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);
/* Start the guest "domain" from the snapshot "snapshot" */ int virDomainCreateWithSnapshot(virDomainPtr domain, virDomainSnapshotPtr snapshot, unsigned int flags);
/* Deactivate 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 other 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 generally only happen when the domain is shut * down, though this is hypervisor-specific */ typedef enum { VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE_FORCE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD_FORCE, } virDomainSnapshotDeactivate; int virDomainSnapshotDeactivate(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> for you, the <creationdate> will be set to the current time+date, <description> will be empty, <state> will be "off", <compression> will be empty, 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>, <description>, and <compression>; the rest are ignored, and filled in by the driver when the snapshot is actually created. NOTE: <compression> is used to compress snapshots, and may or may not be supported by individual hypervisor implementations. If <compression> is specified and the underlying hypervisor does not support it, an error will be thrown.
<domainsnapshot> <name>XYZ</name> <creationdate>...</creationdate> <description>...</description> <state>RUNNING</state> <domain> <uuid>XXXXX-XXXX-XXXX-XXXX-XXXXXXXXX</uuid> </domain> <compression>gzip</compression> <parent> <name>ABC</name> </parent> </domainsnapshot>
The virsh commands will be: virsh snapshot-create [--compress] <dom> <xmlfile> virsh snapshot-list <dom> virsh snapshot-dumpxml <dom> <name> virsh create-with-snapshot <dom> <snapshotname>
It should be called start-with-snapshot. I'm not sure if this start-with-snapshot is a good idea, because I think this concept is not intuitive to the user. A typical lifecycle of a domain in the ESX or VirtualBox context may look like this: - define a new domain - start it - install the OS - create a snapshot A to have a backup of the state with a clean OS installation - do some work in the domain - shutdown the domain - start the domain again (in ESX or VirtualBox UIs this is done by the normal start button) The user expects to start the domain with the exact same state as at last shutdown. But with virsh if you use the normal start command as you normally do you'll get something different. In the context of ESX or VirtualBox I'm not even sure what the "base image" would be, is it the empty disk before OS installation?
virsh snapshot-deactivate <dom> <snapshotname> [--merge|--delete|--mergeforce|--mergedelete]
-- Chris Lalancette
Matthias

On Wed, Mar 24, 2010 at 02:34:41PM +0100, Matthias Bolte wrote:
2010/3/24 Chris Lalancette <clalance@redhat.com>:
Based on discussion, I've modified the snapshot API to the below. I've incorporated most of the semantic changes we talked about; the renaming of various API calls I've left for later, since it is a minor point. More comments 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);
/* Start the guest "domain" from the snapshot "snapshot" */ int virDomainCreateWithSnapshot(virDomainPtr domain, virDomainSnapshotPtr snapshot, unsigned int flags);
/* Deactivate 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 other 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 generally only happen when the domain is shut * down, though this is hypervisor-specific */ typedef enum { VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_MERGE_FORCE, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD, VIR_DOMAIN_SNAPSHOT_DEACTIVATE_DISCARD_FORCE, } virDomainSnapshotDeactivate; int virDomainSnapshotDeactivate(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> for you, the <creationdate> will be set to the current time+date, <description> will be empty, <state> will be "off", <compression> will be empty, 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>, <description>, and <compression>; the rest are ignored, and filled in by the driver when the snapshot is actually created. NOTE: <compression> is used to compress snapshots, and may or may not be supported by individual hypervisor implementations. If <compression> is specified and the underlying hypervisor does not support it, an error will be thrown.
<domainsnapshot> <name>XYZ</name> <creationdate>...</creationdate> <description>...</description> <state>RUNNING</state> <domain> <uuid>XXXXX-XXXX-XXXX-XXXX-XXXXXXXXX</uuid> </domain> <compression>gzip</compression> <parent> <name>ABC</name> </parent> </domainsnapshot>
The virsh commands will be: virsh snapshot-create [--compress] <dom> <xmlfile> virsh snapshot-list <dom> virsh snapshot-dumpxml <dom> <name> virsh create-with-snapshot <dom> <snapshotname>
It should be called start-with-snapshot.
I'm not sure if this start-with-snapshot is a good idea, because I think this concept is not intuitive to the user. A typical lifecycle of a domain in the ESX or VirtualBox context may look like this:
- define a new domain - start it - install the OS - create a snapshot A to have a backup of the state with a clean OS installation - do some work in the domain - shutdown the domain - start the domain again (in ESX or VirtualBox UIs this is done by the normal start button)
The user expects to start the domain with the exact same state as at last shutdown. But with virsh if you use the normal start command as you normally do you'll get something different. In the context of ESX or VirtualBox I'm not even sure what the "base image" would be, is it the empty disk before OS installation?
Essentially the normal 'start' operation should always start with the most recently used snapshot, if any. 'start-with-snapshot' is to be used where you want to switch a snapshot which isn't the most recently used. You never want to start with the base image, if you were previously running with a snapshot Danil -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On 03/24/2010 09:36 AM, Daniel P. Berrange wrote:
The virsh commands will be: virsh snapshot-create [--compress] <dom> <xmlfile> virsh snapshot-list <dom> virsh snapshot-dumpxml <dom> <name> virsh create-with-snapshot <dom> <snapshotname>
It should be called start-with-snapshot.
I'm not sure if this start-with-snapshot is a good idea, because I think this concept is not intuitive to the user. A typical lifecycle of a domain in the ESX or VirtualBox context may look like this:
- define a new domain - start it - install the OS - create a snapshot A to have a backup of the state with a clean OS installation - do some work in the domain - shutdown the domain - start the domain again (in ESX or VirtualBox UIs this is done by the normal start button)
The user expects to start the domain with the exact same state as at last shutdown. But with virsh if you use the normal start command as you normally do you'll get something different. In the context of ESX or VirtualBox I'm not even sure what the "base image" would be, is it the empty disk before OS installation?
Essentially the normal 'start' operation should always start with the most recently used snapshot, if any. 'start-with-snapshot' is to be used where you want to switch a snapshot which isn't the most recently used.
This is really the weakness in this API, actually. If you have the ability to have snapshots, and virDomainCreate() always starts with the "latest" snapshot, it's somewhat difficult for the user to discover which snapshot they are currently running from. I guess that's the use of the <state> field in the snapshot XML. The problem is that given a virDomainPtr, the only way to find the active snapshot is to iterate through all of the available ones looking for the "running" one, which isn't very nice. Maybe we should also add a field to the domain XML that points to the currently in-use snapshot, if any; that would nicely solve this problem, and also make it easier for the libvirt code to make sure that it is starting with the "latest" snapshot when it does virDomainCreate. -- Chris Lalancette
participants (6)
-
Chris Lalancette
-
Daniel P. Berrange
-
Daniel Veillard
-
Eric Blake
-
Matthias Bolte
-
Paolo Bonzini