The design of the API's went through many iterations, until we finally settled on an API that seems to fit the snapshot model of most of the hypervisors pretty well. To take a snapshot, virDomainSnapshotCreateXML() is used with an appropriate virDomainPtr and snapshot XML. The snapshot XML looks like:
<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>
However, when creating a snapshot, only the <name> and <description> tags are settable by the user. All of the other fields are ignored and filled in by the libvirt driver at the time the snapshot is actually created. The <domainsnapshot> XML is pretty straightforward, but I'll describe the fields here.
<name> is a unique identifier for this snapshot for this domain. It's what will be used later on to lookup the snapshot to perform operations with it or on it. If the <name> is not specified at snapshot creation time, then libvirt will make one up.
<creationdate> is the time, in seconds since the Unix epoch, that the snapshot was created at. This is read-only and is automatically filled in by libvirt when the snapshot is created.
<description> is a user-editable field that can contain any unique identifying information the user wants to store along with the snapshot. If this is blank at snapshot creation time, it remains empty.
<state> is the state of the domain (running, offline, paused, etc) at the time the snapshot was taken. When a user reverts to a particular snapshot, the domain's state will be set to this state.
<domain><uuid> is the UUID corresponding to the domain that this snapshot is taken against.
<parent><name> is the name of the parent of this snapshot (if any). This tracks the parent/child relationship in "trees" of snapshots. It is important information to know when deleting snapshots, as deleting a parent snapshot has interesting repercussions for children (see virDomainSnapshotDelete() below).
Once you've created a snapshot, you can lookup the snapshot by name, query all of the snapshots for a domain, or get the currently running snapshot for a domain. At some point in the future, the user will probably want to revert back to the snapshot he has taken. To do this, a handle to the domain snapshot must be obtained with virDomainSnapshotLookupByName(). Once the handle is obtained, the domain can be reverted to the point-in-time of that snapshot by calling virDomainRevertToSnapshot(). This is pretty cool to see in action; the domain is running along, and the moment virDomainRevertToSnapshot() is called, the domain instantly travels back to the past!
Finally, I'll talk a bit about deleting snapshots. Once a user is done using a snapshot, they may want to delete that snapshot. In the simple case of a snapshot without children, a call to virDomainSnapshotDelete() will remove all traces of the snapshot. If a snapshot does have children, then things get more interesting. First, if the VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN flag is passed to virDomainSnapshotDelete(), then the current snapshot and all children of this snapshot are deleted. Second, if VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN is *not* passed, but this snapshot does have children, then all changes that are present in the to-be-deleted parent are automatically merged into the children. If you think about it, this is necessary to keep the children viable.
That's some of the fun stuff going on in libvirt. If you have questions, comments, or problems with this feature, please feel free to contact the libvirt mailing list at libvirt-users@redhat.com or libvirt-devel@redhat.com.