/*
* libvirt-domain-snapshot.c: entry points for virDomainSnapshotPtr APIs
*
* Copyright (C) 2006-2014 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*/
#include
#include "datatypes.h"
#include "virlog.h"
VIR_LOG_INIT("libvirt.domain-snapshot");
#define VIR_FROM_THIS VIR_FROM_DOMAIN_SNAPSHOT
/**
* virDomainSnapshotGetName:
* @snapshot: a snapshot object
*
* Get the public name for that snapshot
*
* Returns a pointer to the name or NULL, the string need not be deallocated
* as its lifetime will be the same as the snapshot object.
*/
const char *
virDomainSnapshotGetName(virDomainSnapshotPtr snapshot)
{
VIR_DEBUG("snapshot=%p", snapshot);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, NULL);
return snapshot->name;
}
/**
* virDomainSnapshotGetDomain:
* @snapshot: a snapshot object
*
* Provides the domain pointer associated with a snapshot. The
* reference counter on the domain is not increased by this
* call.
*
* WARNING: When writing libvirt bindings in other languages, do not use this
* function. Instead, store the domain and the snapshot object together.
*
* Returns the domain or NULL.
*/
virDomainPtr
virDomainSnapshotGetDomain(virDomainSnapshotPtr snapshot)
{
VIR_DEBUG("snapshot=%p", snapshot);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, NULL);
return snapshot->domain;
}
/**
* virDomainSnapshotGetConnect:
* @snapshot: a snapshot object
*
* Provides the connection pointer associated with a snapshot. The
* reference counter on the connection is not increased by this
* call.
*
* WARNING: When writing libvirt bindings in other languages, do not use this
* function. Instead, store the connection and the snapshot object together.
*
* Returns the connection or NULL.
*/
virConnectPtr
virDomainSnapshotGetConnect(virDomainSnapshotPtr snapshot)
{
VIR_DEBUG("snapshot=%p", snapshot);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, NULL);
return snapshot->domain->conn;
}
/**
* virDomainSnapshotCreateXML:
* @domain: a domain object
* @xmlDesc: string containing an XML description of the domain
* @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.
*
* If @flags includes VIR_DOMAIN_SNAPSHOT_CREATE_HALT, then the domain
* will be inactive after the snapshot completes, regardless of whether
* it was active before; otherwise, a running domain will still be
* running after the snapshot. This flag is invalid on transient domains,
* and is incompatible with VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE.
*
* If @flags includes VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, then the domain
* is not paused while creating the snapshot. This increases the size
* of the memory dump file, but reduces downtime of the guest while
* taking the snapshot. Some hypervisors only support this flag during
* external checkpoints.
*
* If @flags includes VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY, then the
* snapshot will be limited to the disks described in @xmlDesc, and no
* VM state will be saved. For an active guest, the disk image may be
* inconsistent (as if power had been pulled), and specifying this
* with the VIR_DOMAIN_SNAPSHOT_CREATE_HALT flag risks data loss.
*
* If @flags includes VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE, then the
* libvirt will attempt to use guest agent to freeze and thaw all
* file systems in use within domain OS. However, if the guest agent
* is not present, an error is thrown. Moreover, this flag requires
* VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY to be passed as well.
*
* By default, if the snapshot involves external files, and any of the
* destination files already exist as a non-empty regular file, the
* snapshot is rejected to avoid losing contents of those files.
* However, if @flags includes VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT,
* then the destination files must be pre-created manually with
* the correct image format and metadata including backing store path
* (this allows a management app to pre-create files with relative backing
* file names, rather than the default of creating with absolute backing
* file names). Note that only the file specified in the snapshot XML is
* inserted as a snapshot thus setting incorrect metadata in the pre-created
* image may lead to the VM being unable to start or other block jobs may fail.
*
* Be aware that although libvirt prefers to report errors up front with
* no other effect, some hypervisors have certain types of failures where
* the overall command can easily fail even though the guest configuration
* was partially altered (for example, if a disk snapshot request for two
* disks fails on the second disk, but the first disk alteration cannot be
* rolled back). If this API call fails, it is therefore normally
* necessary to follow up with virDomainGetXMLDesc() and check each disk
* to determine if any partial changes occurred. However, if @flags
* contains VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC, then libvirt guarantees
* that this command will not alter any disks unless the entire set of
* changes can be done atomically, making failure recovery simpler (note
* that it is still possible to fail after disks have changed, but only
* in the much rarer cases of running out of memory or disk space).
*
* Some hypervisors may prevent this operation if there is a current
* block copy operation; in that case, use virDomainBlockJobAbort()
* to stop the block copy first.
*
* virDomainSnapshotFree should be used to free the resources after the
* snapshot object is no longer needed.
*
* Returns an (opaque) virDomainSnapshotPtr on success, NULL on failure.
*/
virDomainSnapshotPtr
virDomainSnapshotCreateXML(virDomainPtr domain,
const char *xmlDesc,
unsigned int flags)
{
virConnectPtr conn;
VIR_DOMAIN_DEBUG(domain, "xmlDesc=%s, flags=%x", xmlDesc, flags);
virResetLastError();
virCheckDomainReturn(domain, NULL);
conn = domain->conn;
virCheckNonNullArgGoto(xmlDesc, error);
virCheckReadOnlyGoto(conn->flags, error);
if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT) &&
!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
virReportInvalidArg(flags, "%s",
_("use of 'current' flag in requires 'redefine' flag"));
goto error;
}
if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) &&
(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
virReportInvalidArg(flags, "%s",
_("'redefine' and 'no metadata' flags in are mutually exclusive"));
goto error;
}
if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) &&
(flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
virReportInvalidArg(flags, "%s",
_("'redefine' and 'halt' flags are mutually exclusive"));
goto error;
}
if (conn->driver->domainSnapshotCreateXML) {
virDomainSnapshotPtr ret;
ret = conn->driver->domainSnapshotCreateXML(domain, xmlDesc, flags);
if (!ret)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return NULL;
}
/**
* virDomainSnapshotGetXMLDesc:
* @snapshot: a domain snapshot object
* @flags: bitwise-OR of subset of virDomainXMLFlags
*
* Provide an XML description of the domain snapshot.
*
* No security-sensitive data will be included unless @flags contains
* VIR_DOMAIN_XML_SECURE; this flag is rejected on read-only
* connections. For this API, @flags should not contain either
* VIR_DOMAIN_XML_INACTIVE or VIR_DOMAIN_XML_UPDATE_CPU.
*
* Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
* the caller must free() the returned value.
*/
char *
virDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
unsigned int flags)
{
virConnectPtr conn;
VIR_DEBUG("snapshot=%p, flags=%x", snapshot, flags);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, NULL);
conn = snapshot->domain->conn;
if ((conn->flags & VIR_CONNECT_RO) && (flags & VIR_DOMAIN_XML_SECURE)) {
virReportError(VIR_ERR_OPERATION_DENIED, "%s",
_("virDomainSnapshotGetXMLDesc with secure flag"));
goto error;
}
if (conn->driver->domainSnapshotGetXMLDesc) {
char *ret;
ret = conn->driver->domainSnapshotGetXMLDesc(snapshot, flags);
if (!ret)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return NULL;
}
/**
* virDomainSnapshotNum:
* @domain: a domain object
* @flags: bitwise-OR of supported virDomainSnapshotListFlags
*
* Provides the number of domain snapshots for this domain.
*
* By default, this command covers all snapshots; it is also possible to
* limit things to just snapshots with no parents, when @flags includes
* VIR_DOMAIN_SNAPSHOT_LIST_ROOTS. Additional filters are provided in
* groups, where each group contains bits that describe mutually exclusive
* attributes of a snapshot, and where all bits within a group describe
* all possible snapshots. Some hypervisors might reject explicit bits
* from a group where the hypervisor cannot make a distinction. For a
* group supported by a given hypervisor, the behavior when no bits of a
* group are set is identical to the behavior when all bits in that group
* are set. When setting bits from more than one group, it is possible to
* select an impossible combination, in that case a hypervisor may return
* either 0 or an error.
*
* The first group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_LEAVES and
* VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES, to filter based on snapshots that
* have no further children (a leaf snapshot).
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_METADATA and
* VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA, for filtering snapshots based on
* whether they have metadata that would prevent the removal of the last
* reference to a domain.
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_INACTIVE,
* VIR_DOMAIN_SNAPSHOT_LIST_ACTIVE, and VIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY,
* for filtering snapshots based on what domain state is tracked by the
* snapshot.
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL and
* VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL, for filtering snapshots based on
* whether the snapshot is stored inside the disk images or as
* additional files.
*
* Returns the number of domain snapshots found or -1 in case of error.
*/
int
virDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
{
virConnectPtr conn;
VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
virResetLastError();
virCheckDomainReturn(domain, -1);
conn = domain->conn;
if (conn->driver->domainSnapshotNum) {
int ret = conn->driver->domainSnapshotNum(domain, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virDomainSnapshotListNames:
* @domain: a domain object
* @names: array to collect the list of names of snapshots
* @nameslen: size of @names
* @flags: bitwise-OR of supported virDomainSnapshotListFlags
*
* Collect the list of domain snapshots for the given domain, and store
* their names in @names. The value to use for @nameslen can be determined
* by virDomainSnapshotNum() with the same @flags.
*
* By default, this command covers all snapshots; it is also possible to
* limit things to just snapshots with no parents, when @flags includes
* VIR_DOMAIN_SNAPSHOT_LIST_ROOTS. Additional filters are provided in
* groups, where each group contains bits that describe mutually exclusive
* attributes of a snapshot, and where all bits within a group describe
* all possible snapshots. Some hypervisors might reject explicit bits
* from a group where the hypervisor cannot make a distinction. For a
* group supported by a given hypervisor, the behavior when no bits of a
* group are set is identical to the behavior when all bits in that group
* are set. When setting bits from more than one group, it is possible to
* select an impossible combination, in that case a hypervisor may return
* either 0 or an error.
*
* The first group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_LEAVES and
* VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES, to filter based on snapshots that
* have no further children (a leaf snapshot).
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_METADATA and
* VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA, for filtering snapshots based on
* whether they have metadata that would prevent the removal of the last
* reference to a domain.
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_INACTIVE,
* VIR_DOMAIN_SNAPSHOT_LIST_ACTIVE, and VIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY,
* for filtering snapshots based on what domain state is tracked by the
* snapshot.
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL and
* VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL, for filtering snapshots based on
* whether the snapshot is stored inside the disk images or as
* additional files.
*
* Note that this command is inherently racy: another connection can
* define a new snapshot between a call to virDomainSnapshotNum() and
* this call. You are only guaranteed that all currently defined
* snapshots were listed if the return is less than @nameslen. Likewise,
* you should be prepared for virDomainSnapshotLookupByName() to fail when
* converting a name from this call into a snapshot object, if another
* connection deletes the snapshot in the meantime. For more control over
* the results, see virDomainListAllSnapshots().
*
* Returns the number of domain snapshots found or -1 in case of error.
* The caller is responsible to call free() for each member of the array.
*/
int
virDomainSnapshotListNames(virDomainPtr domain, char **names, int nameslen,
unsigned int flags)
{
virConnectPtr conn;
VIR_DOMAIN_DEBUG(domain, "names=%p, nameslen=%d, flags=%x",
names, nameslen, flags);
virResetLastError();
virCheckDomainReturn(domain, -1);
conn = domain->conn;
virCheckNonNullArgGoto(names, error);
virCheckNonNegativeArgGoto(nameslen, error);
if (conn->driver->domainSnapshotListNames) {
int ret = conn->driver->domainSnapshotListNames(domain, names,
nameslen, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virDomainListAllSnapshots:
* @domain: a domain object
* @snaps: pointer to variable to store the array containing snapshot objects,
* or NULL if the list is not required (just returns number of
* snapshots)
* @flags: bitwise-OR of supported virDomainSnapshotListFlags
*
* Collect the list of domain snapshots for the given domain, and allocate
* an array to store those objects. This API solves the race inherent in
* virDomainSnapshotListNames().
*
* By default, this command covers all snapshots; it is also possible to
* limit things to just snapshots with no parents, when @flags includes
* VIR_DOMAIN_SNAPSHOT_LIST_ROOTS. Additional filters are provided in
* groups, where each group contains bits that describe mutually exclusive
* attributes of a snapshot, and where all bits within a group describe
* all possible snapshots. Some hypervisors might reject explicit bits
* from a group where the hypervisor cannot make a distinction. For a
* group supported by a given hypervisor, the behavior when no bits of a
* group are set is identical to the behavior when all bits in that group
* are set. When setting bits from more than one group, it is possible to
* select an impossible combination, in that case a hypervisor may return
* either 0 or an error.
*
* The first group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_LEAVES and
* VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES, to filter based on snapshots that
* have no further children (a leaf snapshot).
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_METADATA and
* VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA, for filtering snapshots based on
* whether they have metadata that would prevent the removal of the last
* reference to a domain.
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_INACTIVE,
* VIR_DOMAIN_SNAPSHOT_LIST_ACTIVE, and VIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY,
* for filtering snapshots based on what domain state is tracked by the
* snapshot.
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL and
* VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL, for filtering snapshots based on
* whether the snapshot is stored inside the disk images or as
* additional files.
*
* Returns the number of domain snapshots found or -1 and sets @snaps to
* NULL in case of error. On success, the array stored into @snaps is
* guaranteed to have an extra allocated element set to NULL but not included
* in the return count, to make iteration easier. The caller is responsible
* for calling virDomainSnapshotFree() on each array element, then calling
* free() on @snaps.
*/
int
virDomainListAllSnapshots(virDomainPtr domain, virDomainSnapshotPtr **snaps,
unsigned int flags)
{
virConnectPtr conn;
VIR_DOMAIN_DEBUG(domain, "snaps=%p, flags=%x", snaps, flags);
virResetLastError();
if (snaps)
*snaps = NULL;
virCheckDomainReturn(domain, -1);
conn = domain->conn;
if (conn->driver->domainListAllSnapshots) {
int ret = conn->driver->domainListAllSnapshots(domain, snaps, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virDomainSnapshotNumChildren:
* @snapshot: a domain snapshot object
* @flags: bitwise-OR of supported virDomainSnapshotListFlags
*
* Provides the number of child snapshots for this domain snapshot.
*
* By default, this command covers only direct children; it is also possible
* to expand things to cover all descendants, when @flags includes
* VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS. Also, some filters are provided in
* groups, where each group contains bits that describe mutually exclusive
* attributes of a snapshot, and where all bits within a group describe
* all possible snapshots. Some hypervisors might reject explicit bits
* from a group where the hypervisor cannot make a distinction. For a
* group supported by a given hypervisor, the behavior when no bits of a
* group are set is identical to the behavior when all bits in that group
* are set. When setting bits from more than one group, it is possible to
* select an impossible combination, in that case a hypervisor may return
* either 0 or an error.
*
* The first group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_LEAVES and
* VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES, to filter based on snapshots that
* have no further children (a leaf snapshot).
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_METADATA and
* VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA, for filtering snapshots based on
* whether they have metadata that would prevent the removal of the last
* reference to a domain.
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_INACTIVE,
* VIR_DOMAIN_SNAPSHOT_LIST_ACTIVE, and VIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY,
* for filtering snapshots based on what domain state is tracked by the
* snapshot.
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL and
* VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL, for filtering snapshots based on
* whether the snapshot is stored inside the disk images or as
* additional files.
*
* Returns the number of domain snapshots found or -1 in case of error.
*/
int
virDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot, unsigned int flags)
{
virConnectPtr conn;
VIR_DEBUG("snapshot=%p, flags=%x", snapshot, flags);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, -1);
conn = snapshot->domain->conn;
if (conn->driver->domainSnapshotNumChildren) {
int ret = conn->driver->domainSnapshotNumChildren(snapshot, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virDomainSnapshotListChildrenNames:
* @snapshot: a domain snapshot object
* @names: array to collect the list of names of snapshots
* @nameslen: size of @names
* @flags: bitwise-OR of supported virDomainSnapshotListFlags
*
* Collect the list of domain snapshots that are children of the given
* snapshot, and store their names in @names. The value to use for
* @nameslen can be determined by virDomainSnapshotNumChildren() with
* the same @flags.
*
* By default, this command covers only direct children; it is also possible
* to expand things to cover all descendants, when @flags includes
* VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS. Also, some filters are provided in
* groups, where each group contains bits that describe mutually exclusive
* attributes of a snapshot, and where all bits within a group describe
* all possible snapshots. Some hypervisors might reject explicit bits
* from a group where the hypervisor cannot make a distinction. For a
* group supported by a given hypervisor, the behavior when no bits of a
* group are set is identical to the behavior when all bits in that group
* are set. When setting bits from more than one group, it is possible to
* select an impossible combination, in that case a hypervisor may return
* either 0 or an error.
*
* The first group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_LEAVES and
* VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES, to filter based on snapshots that
* have no further children (a leaf snapshot).
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_METADATA and
* VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA, for filtering snapshots based on
* whether they have metadata that would prevent the removal of the last
* reference to a domain.
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_INACTIVE,
* VIR_DOMAIN_SNAPSHOT_LIST_ACTIVE, and VIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY,
* for filtering snapshots based on what domain state is tracked by the
* snapshot.
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL and
* VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL, for filtering snapshots based on
* whether the snapshot is stored inside the disk images or as
* additional files.
*
* Returns the number of domain snapshots found or -1 in case of error.
* Note that this command is inherently racy: another connection can
* define a new snapshot between a call to virDomainSnapshotNumChildren()
* and this call. You are only guaranteed that all currently defined
* snapshots were listed if the return is less than @nameslen. Likewise,
* you should be prepared for virDomainSnapshotLookupByName() to fail when
* converting a name from this call into a snapshot object, if another
* connection deletes the snapshot in the meantime. For more control over
* the results, see virDomainSnapshotListAllChildren().
*
* Returns the number of domain snapshots found or -1 in case of error.
* The caller is responsible to call free() for each member of the array.
*/
int
virDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
char **names, int nameslen,
unsigned int flags)
{
virConnectPtr conn;
VIR_DEBUG("snapshot=%p, names=%p, nameslen=%d, flags=%x",
snapshot, names, nameslen, flags);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, -1);
conn = snapshot->domain->conn;
virCheckNonNullArgGoto(names, error);
virCheckNonNegativeArgGoto(nameslen, error);
if (conn->driver->domainSnapshotListChildrenNames) {
int ret = conn->driver->domainSnapshotListChildrenNames(snapshot,
names,
nameslen,
flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virDomainSnapshotListAllChildren:
* @snapshot: a domain snapshot object
* @snaps: pointer to variable to store the array containing snapshot objects,
* or NULL if the list is not required (just returns number of
* snapshots)
* @flags: bitwise-OR of supported virDomainSnapshotListFlags
*
* Collect the list of domain snapshots that are children of the given
* snapshot, and allocate an array to store those objects. This API solves
* the race inherent in virDomainSnapshotListChildrenNames().
*
* By default, this command covers only direct children; it is also possible
* to expand things to cover all descendants, when @flags includes
* VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS. Also, some filters are provided in
* groups, where each group contains bits that describe mutually exclusive
* attributes of a snapshot, and where all bits within a group describe
* all possible snapshots. Some hypervisors might reject explicit bits
* from a group where the hypervisor cannot make a distinction. For a
* group supported by a given hypervisor, the behavior when no bits of a
* group are set is identical to the behavior when all bits in that group
* are set. When setting bits from more than one group, it is possible to
* select an impossible combination, in that case a hypervisor may return
* either 0 or an error.
*
* The first group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_LEAVES and
* VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES, to filter based on snapshots that
* have no further children (a leaf snapshot).
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_METADATA and
* VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA, for filtering snapshots based on
* whether they have metadata that would prevent the removal of the last
* reference to a domain.
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_INACTIVE,
* VIR_DOMAIN_SNAPSHOT_LIST_ACTIVE, and VIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY,
* for filtering snapshots based on what domain state is tracked by the
* snapshot.
*
* The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL and
* VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL, for filtering snapshots based on
* whether the snapshot is stored inside the disk images or as
* additional files.
*
* Returns the number of domain snapshots found or -1 and sets @snaps to
* NULL in case of error. On success, the array stored into @snaps is
* guaranteed to have an extra allocated element set to NULL but not included
* in the return count, to make iteration easier. The caller is responsible
* for calling virDomainSnapshotFree() on each array element, then calling
* free() on @snaps.
*/
int
virDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
virDomainSnapshotPtr **snaps,
unsigned int flags)
{
virConnectPtr conn;
VIR_DEBUG("snapshot=%p, snaps=%p, flags=%x", snapshot, snaps, flags);
virResetLastError();
if (snaps)
*snaps = NULL;
virCheckDomainSnapshotReturn(snapshot, -1);
conn = snapshot->domain->conn;
if (conn->driver->domainSnapshotListAllChildren) {
int ret = conn->driver->domainSnapshotListAllChildren(snapshot, snaps,
flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virDomainSnapshotLookupByName:
* @domain: a domain object
* @name: name for the domain snapshot
* @flags: extra flags; not used yet, so callers should always pass 0
*
* Try to lookup a domain snapshot based on its name.
*
* Returns a domain snapshot object or NULL in case of failure. If the
* domain snapshot cannot be found, then the VIR_ERR_NO_DOMAIN_SNAPSHOT
* error is raised.
*/
virDomainSnapshotPtr
virDomainSnapshotLookupByName(virDomainPtr domain,
const char *name,
unsigned int flags)
{
virConnectPtr conn;
VIR_DOMAIN_DEBUG(domain, "name=%s, flags=%x", name, flags);
virResetLastError();
virCheckDomainReturn(domain, NULL);
conn = domain->conn;
virCheckNonNullArgGoto(name, error);
if (conn->driver->domainSnapshotLookupByName) {
virDomainSnapshotPtr dom;
dom = conn->driver->domainSnapshotLookupByName(domain, name, flags);
if (!dom)
goto error;
return dom;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return NULL;
}
/**
* virDomainHasCurrentSnapshot:
* @domain: pointer to the domain object
* @flags: extra flags; not used yet, so callers should always pass 0
*
* Determine if the domain has a current snapshot.
*
* Returns 1 if such snapshot exists, 0 if it doesn't, -1 on error.
*/
int
virDomainHasCurrentSnapshot(virDomainPtr domain, unsigned int flags)
{
virConnectPtr conn;
VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
virResetLastError();
virCheckDomainReturn(domain, -1);
conn = domain->conn;
if (conn->driver->domainHasCurrentSnapshot) {
int ret = conn->driver->domainHasCurrentSnapshot(domain, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virDomainSnapshotCurrent:
* @domain: a domain object
* @flags: extra flags; not used yet, so callers should always pass 0
*
* Get the current snapshot for a domain, if any.
*
* virDomainSnapshotFree should be used to free the resources after the
* snapshot object is no longer needed.
*
* Returns a domain snapshot object or NULL in case of failure. If the
* current domain snapshot cannot be found, then the VIR_ERR_NO_DOMAIN_SNAPSHOT
* error is raised.
*/
virDomainSnapshotPtr
virDomainSnapshotCurrent(virDomainPtr domain,
unsigned int flags)
{
virConnectPtr conn;
VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
virResetLastError();
virCheckDomainReturn(domain, NULL);
conn = domain->conn;
if (conn->driver->domainSnapshotCurrent) {
virDomainSnapshotPtr snap;
snap = conn->driver->domainSnapshotCurrent(domain, flags);
if (!snap)
goto error;
return snap;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return NULL;
}
/**
* virDomainSnapshotGetParent:
* @snapshot: a snapshot object
* @flags: extra flags; not used yet, so callers should always pass 0
*
* Get the parent snapshot for @snapshot, if any.
*
* virDomainSnapshotFree should be used to free the resources after the
* snapshot object is no longer needed.
*
* Returns a domain snapshot object or NULL in case of failure. If the
* given snapshot is a root (no parent), then the VIR_ERR_NO_DOMAIN_SNAPSHOT
* error is raised.
*/
virDomainSnapshotPtr
virDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
unsigned int flags)
{
virConnectPtr conn;
VIR_DEBUG("snapshot=%p, flags=%x", snapshot, flags);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, NULL);
conn = snapshot->domain->conn;
if (conn->driver->domainSnapshotGetParent) {
virDomainSnapshotPtr snap;
snap = conn->driver->domainSnapshotGetParent(snapshot, flags);
if (!snap)
goto error;
return snap;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return NULL;
}
/**
* virDomainSnapshotIsCurrent:
* @snapshot: a snapshot object
* @flags: extra flags; not used yet, so callers should always pass 0
*
* Determine if the given snapshot is the domain's current snapshot. See
* also virDomainHasCurrentSnapshot().
*
* Returns 1 if current, 0 if not current, or -1 on error.
*/
int
virDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
unsigned int flags)
{
virConnectPtr conn;
VIR_DEBUG("snapshot=%p, flags=%x", snapshot, flags);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, -1);
conn = snapshot->domain->conn;
if (conn->driver->domainSnapshotIsCurrent) {
int ret;
ret = conn->driver->domainSnapshotIsCurrent(snapshot, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virDomainSnapshotHasMetadata:
* @snapshot: a snapshot object
* @flags: extra flags; not used yet, so callers should always pass 0
*
* Determine if the given snapshot is associated with libvirt metadata
* that would prevent the deletion of the domain.
*
* Returns 1 if the snapshot has metadata, 0 if the snapshot exists without
* help from libvirt, or -1 on error.
*/
int
virDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
unsigned int flags)
{
virConnectPtr conn;
VIR_DEBUG("snapshot=%p, flags=%x", snapshot, flags);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, -1);
conn = snapshot->domain->conn;
if (conn->driver->domainSnapshotHasMetadata) {
int ret;
ret = conn->driver->domainSnapshotHasMetadata(snapshot, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virDomainRevertToSnapshot:
* @snapshot: a domain snapshot object
* @flags: bitwise-OR of virDomainSnapshotRevertFlags
*
* Revert the domain to a given snapshot.
*
* Normally, the domain will revert to the same state the domain was
* in while the snapshot was taken (whether inactive, running, or
* paused), except that disk snapshots default to reverting to
* inactive state. Including VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING in
* @flags overrides the snapshot state to guarantee a running domain
* after the revert; or including VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED in
* @flags guarantees a paused domain after the revert. These two
* flags are mutually exclusive. While a persistent domain does not
* need either flag, it is not possible to revert a transient domain
* into an inactive state, so transient domains require the use of one
* of these two flags.
*
* Reverting to any snapshot discards all configuration changes made since
* the last snapshot. Additionally, reverting to a snapshot from a running
* domain is a form of data loss, since it discards whatever is in the
* guest's RAM at the time. Since the very nature of keeping snapshots
* implies the intent to roll back state, no additional confirmation is
* normally required for these lossy effects.
*
* However, there are two particular situations where reverting will
* be refused by default, and where @flags must include
* VIR_DOMAIN_SNAPSHOT_REVERT_FORCE to acknowledge the risks. 1) Any
* attempt to revert to a snapshot that lacks the metadata to perform
* ABI compatibility checks (generally the case for snapshots that
* lack a full when listed by virDomainSnapshotGetXMLDesc(),
* such as those created prior to libvirt 0.9.5). 2) Any attempt to
* revert a running domain to an active state that requires starting a
* new hypervisor instance rather than reusing the existing hypervisor
* (since this would terminate all connections to the domain, such as
* such as VNC or Spice graphics) - this condition arises from active
* snapshots that are provably ABI incomaptible, as well as from
* inactive snapshots with a @flags request to start the domain after
* the revert.
*
* Returns 0 if the creation is successful, -1 on error.
*/
int
virDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
unsigned int flags)
{
virConnectPtr conn;
VIR_DEBUG("snapshot=%p, flags=%x", snapshot, flags);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, -1);
conn = snapshot->domain->conn;
virCheckReadOnlyGoto(conn->flags, error);
if ((flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
(flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) {
virReportInvalidArg(flags, "%s",
_("running and paused flags are mutually exclusive"));
goto error;
}
if (conn->driver->domainRevertToSnapshot) {
int ret = conn->driver->domainRevertToSnapshot(snapshot, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virDomainSnapshotDelete:
* @snapshot: a domain snapshot object
* @flags: bitwise-OR of supported virDomainSnapshotDeleteFlags
*
* Delete the snapshot.
*
* If @flags is 0, then just this snapshot is deleted, and changes
* from this snapshot are automatically merged into children
* snapshots. If @flags includes VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN,
* then this snapshot and any descendant snapshots are deleted. If
* @flags includes VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, then any
* descendant snapshots are deleted, but this snapshot remains. These
* two flags are mutually exclusive.
*
* If @flags includes VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, then
* any snapshot metadata tracked by libvirt is removed while keeping
* the snapshot contents intact; if a hypervisor does not require any
* libvirt metadata to track snapshots, then this flag is silently
* ignored.
*
* Returns 0 if the selected snapshot(s) were successfully deleted,
* -1 on error.
*/
int
virDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
unsigned int flags)
{
virConnectPtr conn;
VIR_DEBUG("snapshot=%p, flags=%x", snapshot, flags);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, -1);
conn = snapshot->domain->conn;
virCheckReadOnlyGoto(conn->flags, error);
if ((flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN) &&
(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
virReportInvalidArg(flags, "%s",
_("children and children_only flags are mutually exclusive"));
goto error;
}
if (conn->driver->domainSnapshotDelete) {
int ret = conn->driver->domainSnapshotDelete(snapshot, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virDomainSnapshotRef:
* @snapshot: the snapshot to hold a reference on
*
* Increment the reference count on the snapshot. For each
* additional call to this method, there shall be a corresponding
* call to virDomainSnapshotFree to release the reference count, once
* the caller no longer needs the reference to this object.
*
* This method is typically useful for applications where multiple
* threads are using a connection, and it is required that the
* connection and domain remain open until all threads have finished
* using the snapshot. ie, each new thread using a snapshot would
* increment the reference count.
*
* Returns 0 in case of success and -1 in case of failure.
*/
int
virDomainSnapshotRef(virDomainSnapshotPtr snapshot)
{
VIR_DEBUG("snapshot=%p, refs=%d", snapshot,
snapshot ? snapshot->object.u.s.refs : 0);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, -1);
virObjectRef(snapshot);
return 0;
}
/**
* virDomainSnapshotFree:
* @snapshot: a domain snapshot object
*
* Free the domain snapshot object. The snapshot itself is not modified.
* The data structure is freed and should not be used thereafter.
*
* Returns 0 in case of success and -1 in case of failure.
*/
int
virDomainSnapshotFree(virDomainSnapshotPtr snapshot)
{
VIR_DEBUG("snapshot=%p", snapshot);
virResetLastError();
virCheckDomainSnapshotReturn(snapshot, -1);
virObjectUnref(snapshot);
return 0;
}