Introduce a few new public APIs related to incremental backups. This
builds on the previous notion of a checkpoint (without an existing
checkpoint, the new API is a full backup, differing from
virDomainBlockCopy in the point of time chosen and in operation on
multiple disks at once); and also allows creation of a new checkpoint
at the same time as starting the backup (after all, an incremental
backup is only useful if it covers the state since the previous
backup). Snapshot creation is also a point in time at which creating
a checkpoint atomically can be useful; as checkpoints are independent
objects, it is not worth embedding <domaincheckpoint> inside
<domainsnapshot>, and therefore we need a more powerful version of
virDomainSnapshotCreateXML(), where we borrow from the naming pattern
of virDomainMigrate2() and friends.
A backup job also affects filtering a listing of domains, as well as
adding event reporting for signaling when a push model backup
completes (where the hypervisor creates the backup); note that the
pull model does not have an event (starting the backup lets a third
party access the data, and only the third party knows when it is
finished).
Since multiple backup jobs can be run in parallel in the future (well,
qemu doesn't support it yet, but we don't want to preclude the idea),
virDomainBackupBegin() returns a positive job id, and the id is also
visible in the backup XML. But until a future libvirt release adds a
bunch of APIs related to parallel job management where job ids will
actually matter, the documentation is also clear that job id 0 means
the 'currently running backup job' (provided one exists), for use in
virDomainBackupGetXMLDesc() and virDomainBackupEnd().
The full list of new APIs:
virDomainBackupBegin;
virDomainBackupEnd;
virDomainBackupGetXMLDesc;
virDomainSnapshotCreateXML2;
Signed-off-by: Eric Blake <eblake(a)redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
include/libvirt/libvirt-domain-snapshot.h | 8 +-
include/libvirt/libvirt-domain.h | 41 +++-
src/driver-hypervisor.h | 21 +++
src/qemu/qemu_blockjob.h | 1 +
examples/object-events/event-test.c | 3 +
src/conf/domain_conf.c | 2 +-
src/libvirt-domain-snapshot.c | 89 +++++++++
src/libvirt-domain.c | 219 ++++++++++++++++++++++
src/libvirt_public.syms | 4 +
tools/virsh-domain.c | 8 +-
10 files changed, 390 insertions(+), 6 deletions(-)
diff --git a/include/libvirt/libvirt-domain-snapshot.h
b/include/libvirt/libvirt-domain-snapshot.h
index 602e5def59..406ac5846c 100644
--- a/include/libvirt/libvirt-domain-snapshot.h
+++ b/include/libvirt/libvirt-domain-snapshot.h
@@ -3,7 +3,7 @@
* Summary: APIs for management of domain snapshots
* Description: Provides APIs for the management of domain snapshots
*
- * Copyright (C) 2006-2014 Red Hat, Inc.
+ * Copyright (C) 2006-2019 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
@@ -78,6 +78,12 @@ virDomainSnapshotPtr virDomainSnapshotCreateXML(virDomainPtr domain,
const char *xmlDesc,
unsigned int flags);
+/* Take a snapshot of the current VM state, possibly creating a checkpoint */
+virDomainSnapshotPtr virDomainSnapshotCreateXML2(virDomainPtr domain,
+ const char *xmlDesc,
+ const char *checkpointXml,
+ unsigned int flags);
+
typedef enum {
VIR_DOMAIN_SNAPSHOT_XML_SECURE = VIR_DOMAIN_XML_SECURE, /* dump security
sensitive information too */
} virDomainSnapshotXMLFlags;
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index fe9ff011fe..260148ff91 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -3,7 +3,7 @@
* Summary: APIs for management of domains
* Description: Provides APIs for the management of domains
*
- * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006-2019 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
@@ -2434,6 +2434,9 @@ typedef enum {
* exists as long as sync is active */
VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT = 4,
+ /* Backup (virDomainBackupBegin), job exists until virDomainBackupEnd */
+ VIR_DOMAIN_BLOCK_JOB_TYPE_BACKUP = 5,
+
# ifdef VIR_ENUM_SENTINELS
VIR_DOMAIN_BLOCK_JOB_TYPE_LAST
# endif
@@ -3255,6 +3258,7 @@ typedef enum {
VIR_DOMAIN_JOB_OPERATION_SNAPSHOT = 6,
VIR_DOMAIN_JOB_OPERATION_SNAPSHOT_REVERT = 7,
VIR_DOMAIN_JOB_OPERATION_DUMP = 8,
+ VIR_DOMAIN_JOB_OPERATION_BACKUP = 9,
# ifdef VIR_ENUM_SENTINELS
VIR_DOMAIN_JOB_OPERATION_LAST
@@ -3270,6 +3274,14 @@ typedef enum {
*/
# define VIR_DOMAIN_JOB_OPERATION "operation"
+/**
+ * VIR_DOMAIN_JOB_ID:
+ *
+ * virDomainGetJobStats field: the id of the job (so far, only for jobs
+ * started by virDomainBackupBegin()), as VIR_TYPED_PARAM_INT.
+ */
+# define VIR_DOMAIN_JOB_ID "id"
+
/**
* VIR_DOMAIN_JOB_TIME_ELAPSED:
*
@@ -4094,7 +4106,8 @@ typedef void
(*virConnectDomainEventMigrationIterationCallback)(virConnectPtr co
* @nparams: size of the params array
* @opaque: application specific data
*
- * This callback occurs when a job (such as migration) running on the domain
+ * This callback occurs when a job (such as migration or push-model
+ * virDomainBackupBegin()) running on the domain
* is completed. The params array will contain statistics of the just completed
* job as virDomainGetJobStats would return. The callback must not free @params
* (the array will be freed once the callback finishes).
@@ -4890,4 +4903,28 @@ int virDomainGetLaunchSecurityInfo(virDomainPtr domain,
int *nparams,
unsigned int flags);
+typedef enum {
+ VIR_DOMAIN_BACKUP_BEGIN_NO_METADATA = (1 << 0), /* Make checkpoint without
+ remembering it */
+ VIR_DOMAIN_BACKUP_BEGIN_QUIESCE = (1 << 1), /* use guest agent to
+ quiesce all mounted
+ file systems within
+ the domain */
+} virDomainBackupBeginFlags;
+
+/* Begin an incremental backup job, possibly creating a checkpoint. */
+int virDomainBackupBegin(virDomainPtr domain, const char *diskXml,
+ const char *checkpointXml, unsigned int flags);
+
+/* Learn about an ongoing backup job. */
+char *virDomainBackupGetXMLDesc(virDomainPtr domain, int id,
+ unsigned int flags);
+
+typedef enum {
+ VIR_DOMAIN_BACKUP_END_ABORT = (1 << 0), /* Abandon a push model backup */
+} virDomainBackupEndFlags;
+
+/* Complete (or abort) an incremental backup job. */
+int virDomainBackupEnd(virDomainPtr domain, int id, unsigned int flags);
+
#endif /* LIBVIRT_DOMAIN_H */
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index 49b676dbbb..6a0cc709d6 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -797,6 +797,12 @@ typedef virDomainSnapshotPtr
const char *xmlDesc,
unsigned int flags);
+typedef virDomainSnapshotPtr
+(*virDrvDomainSnapshotCreateXML2)(virDomainPtr domain,
+ const char *xmlDesc,
+ const char *checkpointXml,
+ unsigned int flags);
+
typedef char *
(*virDrvDomainSnapshotGetXMLDesc)(virDomainSnapshotPtr snapshot,
unsigned int flags);
@@ -1376,6 +1382,17 @@ typedef int
(*virDrvDomainCheckpointDelete)(virDomainCheckpointPtr checkpoint,
unsigned int flags);
+typedef int
+(*virDrvDomainBackupBegin)(virDomainPtr domain, const char *diskXml,
+ const char *checkpointXml, unsigned int flags);
+
+typedef char *
+(*virDrvDomainBackupGetXMLDesc)(virDomainPtr domain, int id,
+ unsigned int flags);
+
+typedef int
+(*virDrvDomainBackupEnd)(virDomainPtr domain, int id, unsigned int flags);
+
typedef struct _virHypervisorDriver virHypervisorDriver;
typedef virHypervisorDriver *virHypervisorDriverPtr;
@@ -1541,6 +1558,7 @@ struct _virHypervisorDriver {
virDrvDomainManagedSaveGetXMLDesc domainManagedSaveGetXMLDesc;
virDrvDomainManagedSaveDefineXML domainManagedSaveDefineXML;
virDrvDomainSnapshotCreateXML domainSnapshotCreateXML;
+ virDrvDomainSnapshotCreateXML2 domainSnapshotCreateXML2;
virDrvDomainSnapshotGetXMLDesc domainSnapshotGetXMLDesc;
virDrvDomainSnapshotNum domainSnapshotNum;
virDrvDomainSnapshotListNames domainSnapshotListNames;
@@ -1638,6 +1656,9 @@ struct _virHypervisorDriver {
virDrvDomainCheckpointIsCurrent domainCheckpointIsCurrent;
virDrvDomainCheckpointHasMetadata domainCheckpointHasMetadata;
virDrvDomainCheckpointDelete domainCheckpointDelete;
+ virDrvDomainBackupBegin domainBackupBegin;
+ virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc;
+ virDrvDomainBackupEnd domainBackupEnd;
};
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index c7325c6daf..95f53dde16 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -55,6 +55,7 @@ typedef enum {
QEMU_BLOCKJOB_TYPE_COPY = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY,
QEMU_BLOCKJOB_TYPE_COMMIT = VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT,
QEMU_BLOCKJOB_TYPE_ACTIVE_COMMIT = VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT,
+ QEMU_BLOCKJOB_TYPE_BACKUP = VIR_DOMAIN_BLOCK_JOB_TYPE_BACKUP,
/* Additional enum values local to qemu */
QEMU_BLOCKJOB_TYPE_INTERNAL,
QEMU_BLOCKJOB_TYPE_LAST
diff --git a/examples/object-events/event-test.c b/examples/object-events/event-test.c
index fcf4492470..98337ad185 100644
--- a/examples/object-events/event-test.c
+++ b/examples/object-events/event-test.c
@@ -891,6 +891,9 @@ blockJobTypeToStr(int type)
case VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT:
return "active layer block commit";
+
+ case VIR_DOMAIN_BLOCK_JOB_TYPE_BACKUP:
+ return "backup";
}
return "unknown";
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 51aa48f421..3c5d369586 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1211,7 +1211,7 @@ VIR_ENUM_IMPL(virDomainOsDefFirmware,
VIR_ENUM_DECL(virDomainBlockJob);
VIR_ENUM_IMPL(virDomainBlockJob,
VIR_DOMAIN_BLOCK_JOB_TYPE_LAST,
- "", "", "copy", "",
"active-commit",
+ "", "", "copy", "",
"active-commit", "",
);
VIR_ENUM_IMPL(virDomainMemoryModel,
diff --git a/src/libvirt-domain-snapshot.c b/src/libvirt-domain-snapshot.c
index 0c8023d9f6..2a50a84417 100644
--- a/src/libvirt-domain-snapshot.c
+++ b/src/libvirt-domain-snapshot.c
@@ -202,6 +202,10 @@ virDomainSnapshotGetConnect(virDomainSnapshotPtr snapshot)
* block copy operation; in that case, use virDomainBlockJobAbort()
* to stop the block copy first.
*
+ * To create a checkpoint object that coincides with the snapshot, in
+ * order to facilitate later incremental backups from the time of the
+ * snapshot, use virDomainSnapshotCreateXML2().
+ *
* virDomainSnapshotFree should be used to free the resources after the
* snapshot object is no longer needed.
*
@@ -251,6 +255,91 @@ virDomainSnapshotCreateXML(virDomainPtr domain,
}
+/**
+ * virDomainSnapshotCreateXML2:
+ * @domain: a domain object
+ * @xmlDesc: string containing an XML description of the domain snapshot
+ * @checkpointXml: description of a checkpoint to create or NULL
+ * @flags: bitwise-OR of virDomainSnapshotCreateFlags
+ *
+ * Creates a new snapshot of a domain based on the snapshot xml
+ * contained in xmlDesc, with a top-level element <domainsnapshot>.
+ *
+ * The @checkpointXml parameter is optional; if non-NULL, then libvirt
+ * behaves as if virDomainCheckpointCreateXML() were called to create
+ * a checkpoint atomically covering the same point in time as the
+ * snapshot, using @checkpointXml and forwarding flags
+ * VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE and
+ * VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA. The creation of a new
+ * checkpoint allows for future incremental backups from the time of
+ * the snapshot. Note that some hypervisors may require a particular
+ * disk format, such as qcow2, in order to take advantage of
+ * checkpoints, while allowing arbitrary formats if checkpoints are
+ * not involved. This parameter is incompatible with the flag
+ * VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE.
+ *
+ * See virDomainSnapshotCreateXML() for the description of individual
+ * flags and general behavior.
+ *
+ * virDomainSnapshotFree() should be used to free the resources after
+ * the snapshot object is no longer needed.
+ *
+ * Returns an (opaque) new virDomainSnapshotPtr on success or NULL on
+ * failure.
+ */
+virDomainSnapshotPtr
+virDomainSnapshotCreateXML2(virDomainPtr domain,
+ const char *xmlDesc,
+ const char *checkpointXml,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(domain, "xmlDesc=%s, checkpointXml=%s, flags=0x%x",
+ xmlDesc, checkpointXml, flags);
+
+ virResetLastError();
+
+ virCheckDomainReturn(domain, NULL);
+ conn = domain->conn;
+
+ virCheckNonNullArgGoto(xmlDesc, error);
+ virCheckReadOnlyGoto(conn->flags, error);
+
+ VIR_REQUIRE_FLAG_GOTO(VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT,
+ VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE,
+ error);
+
+ VIR_EXCLUSIVE_FLAGS_GOTO(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE,
+ VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA,
+ error);
+ VIR_EXCLUSIVE_FLAGS_GOTO(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE,
+ VIR_DOMAIN_SNAPSHOT_CREATE_HALT,
+ error);
+
+ if (checkpointXml && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
+ virReportInvalidArg(checkpointXml, "%s",
+ _("Cannot create checkpoint when redefining "
+ "snapshot"));
+ goto error;
+ }
+
+ if (conn->driver->domainSnapshotCreateXML2) {
+ virDomainSnapshotPtr ret;
+ ret = conn->driver->domainSnapshotCreateXML2(domain, xmlDesc,
+ checkpointXml, flags);
+ if (!ret)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+ error:
+ virDispatchError(conn);
+ return NULL;
+}
+
+
/**
* virDomainSnapshotGetXMLDesc:
* @snapshot: a domain snapshot object
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 44438c3be8..67ae2a9ecd 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -10351,6 +10351,12 @@ virDomainBlockRebase(virDomainPtr dom, const char *disk,
* over the destination format, the ability to copy to a destination that
* is not a local file, and the possibility of additional tuning parameters.
*
+ * The copy created by this API is not finalized until the job ends,
+ * and does not lend itself to incremental backups (beyond what
+ * VIR_DOMAIN_BLOCK_COPY_SHALLOW provides) nor to third-party control
+ * over the data being copied. For those features, use
+ * virDomainBackupBegin().
+ *
* Returns 0 if the operation has started, -1 on failure.
*/
int
@@ -12373,3 +12379,216 @@ int virDomainGetLaunchSecurityInfo(virDomainPtr domain,
virDispatchError(domain->conn);
return -1;
}
+
+
+/**
+ * virDomainBackupBegin:
+ * @domain: a domain object
+ * @diskXml: description of storage to utilize and expose during
+ * the backup, or NULL
+ * @checkpointXml: description of a checkpoint to create or NULL
+ * @flags: bitwise-OR of supported virDomainBackupBeginFlags
+ *
+ * Start a point-in-time backup job for the specified disks of a
+ * running domain.
+ *
+ * A backup job is mutually exclusive with domain migration
+ * (particularly when the job sets up an NBD export, since it is not
+ * possible to tell any NBD clients about a server migrating between
+ * hosts). For now, backup jobs are also mutually exclusive with any
+ * other block job on the same device, although this restriction may
+ * be lifted in a future release. Progress of the backup job can be
+ * tracked via virDomainGetJobStats(). The job remains active until a
+ * subsequent call to virDomainBackupEnd(), even if it no longer has
+ * anything to copy.
+ *
+ * This API differs from virDomainBlockCopy() because it can grab the
+ * state of more than one disk in parallel, and because the state is
+ * captured as of the start of the job, rather than the end.
+ *
+ * There are two fundamental backup approaches. The first, called a
+ * push model, instructs the hypervisor to copy the state of the guest
+ * disk to the designated storage destination (which may be on the
+ * local file system or a network device). In this mode, the
+ * hypervisor writes the content of the guest disk to the destination,
+ * then emits VIR_DOMAIN_EVENT_ID_JOB_COMPLETED when the backup is
+ * either complete or failed (the backup image is invalid if the job
+ * fails or virDomainBackupEnd() is used prior to the event being
+ * emitted).
+ *
+ * The second, called a pull model, instructs the hypervisor to expose
+ * the state of the guest disk over an NBD export. A third-party
+ * client can then connect to this export and read whichever portions
+ * of the disk it desires. In this mode, there is no event; libvirt
+ * has to be informed via virDomainBackupEnd() when the third-party
+ * NBD client is done and the backup resources can be released.
+ *
+ * The @diskXml parameter is optional but usually provided and
+ * contains details about the backup in the top-level element
+ * <domainbackup> , including which backup mode to use, whether the
+ * backup is incremental from a previous checkpoint, which disks
+ * participate in the backup, the destination for a push model backup,
+ * and the temporary storage and NBD server details for a pull model
+ * backup. If omitted, the backup attempts to default to a push mode
+ * full backup of all disks, where libvirt generates a filename for
+ * each disk by appending a suffix of a timestamp in seconds since the
+ * Epoch. virDomainBackupGetXMLDesc() can be called to learn actual
+ * values selected. For more information, see
+ * formatcheckpoint.html#BackupAttributes.
+ *
+ * The @checkpointXml parameter is optional; if non-NULL, then libvirt
+ * behaves as if virDomainCheckpointCreateXML() were called to create
+ * a checkpoint atomically covering the same point in time as the
+ * backup, using @checkpointXml and forwarding flags
+ * VIR_DOMAIN_BACKUP_BEGIN_QUIESCE and
+ * VIR_DOMAIN_BACKUP_BEGIN_NO_METADATA. The creation of a new
+ * checkpoint allows for future incremental backups. Note that some
+ * hypervisors may require a particular disk format, such as qcow2, in
+ * order to take advantage of checkpoints, while allowing arbitrary
+ * formats if checkpoints are not involved.
+ *
+ * Returns a non-negative job id on success or negative on failure.
+ * This id is then passed to virDomainBackupGetXMLDesc() and
+ * virDomainBackupEnd(); it can also be obtained from
+ * virDomainListJobIds(). This operation returns quickly, such that a
+ * user can choose to start a backup job between virDomainFSFreeze()
+ * and virDomainFSThaw() in order to create the backup while guest I/O
+ * is quiesced.
+ */
+int
+virDomainBackupBegin(virDomainPtr domain,
+ const char *diskXml,
+ const char *checkpointXml,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(domain, "diskXml=%s, checkpointXml=%s, flags=0x%x",
+ NULLSTR(diskXml), NULLSTR(checkpointXml), flags);
+
+ virResetLastError();
+
+ virCheckDomainReturn(domain, -1);
+ conn = domain->conn;
+
+ virCheckReadOnlyGoto(conn->flags, error);
+ if (flags & VIR_DOMAIN_BACKUP_BEGIN_NO_METADATA)
+ virCheckNonNullArgGoto(checkpointXml, error);
+
+ if (conn->driver->domainBackupBegin) {
+ int ret;
+ ret = conn->driver->domainBackupBegin(domain, diskXml, checkpointXml,
+ flags);
+ if (!ret)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+ error:
+ virDispatchError(conn);
+ return -1;
+}
+
+
+/**
+ * virDomainBackupGetXMLDesc:
+ * @domain: a domain object
+ * @id: the id of an active backup job
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * In some cases, a user can start a backup job without supplying all
+ * details and rely on libvirt to fill in the rest (for example,
+ * selecting the port used for an NBD export). This API can then be
+ * used to learn what default values were chosen. At present, none of
+ * the information provided is security sensitive.
+ *
+ * @id can either be the return value of a previous
+ * virDomainBackupBegin() or the value 0 to select the current backup
+ * job (the latter usage is an error if the hypervisor supports
+ * parallel jobs and has more than one running).
+ *
+ * Returns a NUL-terminated UTF-8 encoded XML instance or NULL in
+ * case of error. The caller must free() the returned value.
+ */
+char *
+virDomainBackupGetXMLDesc(virDomainPtr domain, int id, unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(domain, "id=%d, flags=0x%x", id, flags);
+
+ virResetLastError();
+
+ virCheckDomainReturn(domain, NULL);
+ conn = domain->conn;
+
+ virCheckNonNegativeArgGoto(id, error);
+
+ if (conn->driver->domainBackupGetXMLDesc) {
+ char *ret;
+ ret = conn->driver->domainBackupGetXMLDesc(domain, id, flags);
+ if (!ret)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+ error:
+ virDispatchError(conn);
+ return NULL;
+}
+
+
+/**
+ * virDomainBackupEnd:
+ * @domain: a domain object
+ * @id: the id of an active backup job
+ * @flags: bitwise-OR of supported virDomainBackupEndFlags
+ *
+ * Conclude a point-in-time backup job of the given domain.
+ *
+ * @id can either be the return value of a previous
+ * virDomainBackupBegin() or the value 0 to select the current backup
+ * job (the latter usage is an error if the hypervisor supports
+ * parallel jobs and has more than one running).
+ *
+ * If the backup job uses the push model, but the event marking that
+ * all data has been copied has not yet been emitted, then the command
+ * fails unless @flags includes VIR_DOMAIN_BACKUP_END_ABORT. If the
+ * event has been issued, or if the backup uses the pull model, the
+ * flag has no effect.
+ *
+ * Returns 1 if the backup job completed successfully (the backup
+ * destination file in a push model is consistent), 0 if the job was
+ * aborted successfully (only when VIR_DOMAIN_BACKUP_END_ABORT is
+ * passed; the destination file is unusable), and -1 on failure.
+ */
+int
+virDomainBackupEnd(virDomainPtr domain, int id, unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(domain, "id=%d, flags=0x%x", id, flags);
+
+ virResetLastError();
+
+ virCheckDomainReturn(domain, -1);
+ conn = domain->conn;
+
+ virCheckReadOnlyGoto(conn->flags, error);
+ virCheckNonNegativeArgGoto(id, error);
+
+ if (conn->driver->domainBackupEnd) {
+ int ret;
+ ret = conn->driver->domainBackupEnd(domain, id, flags);
+ if (!ret)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+ error:
+ virDispatchError(conn);
+ return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index a54804682e..46668dcb0f 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -821,6 +821,9 @@ LIBVIRT_5.2.0 {
LIBVIRT_5.3.0 {
global:
+ virDomainBackupBegin;
+ virDomainBackupEnd;
+ virDomainBackupGetXMLDesc;
virDomainCheckpointCreateXML;
virDomainCheckpointCurrent;
virDomainCheckpointDelete;
@@ -837,6 +840,7 @@ LIBVIRT_5.3.0 {
virDomainCheckpointRef;
virDomainHasCurrentCheckpoint;
virDomainListAllCheckpoints;
+ virDomainSnapshotCreateXML2;
} LIBVIRT_5.2.0;
# .... define new API here using predicted next version number ....
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index da57d96d1a..3ac470fe59 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -2562,7 +2562,9 @@ VIR_ENUM_IMPL(virshDomainBlockJob,
N_("Block Pull"),
N_("Block Copy"),
N_("Block Commit"),
- N_("Active Block Commit"));
+ N_("Active Block Commit"),
+ N_("Backup"),
+);
static const char *
virshDomainBlockJobToString(int type)
@@ -6069,7 +6071,9 @@ VIR_ENUM_IMPL(virshDomainJobOperation,
N_("Outgoing migration"),
N_("Snapshot"),
N_("Snapshot revert"),
- N_("Dump"));
+ N_("Dump"),
+ N_("Backup"),
+);
static const char *
virshDomainJobOperationToString(int op)
--
2.20.1