[libvirt] [PATCH v6 8/9] backup: Introduce virDomainBackup APIs

Eric Blake eblake at redhat.com
Tue Mar 26 06:13:52 UTC 2019


Introduce a few more 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. 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 job id, which can also be queried by
virDomainListJobIds(), and this job id must be used for
virDomainBackupGetXMLDesc() and virDomainBackupEnd(). In the future,
we may also extend other jobs (migration as the default global job
impacting virDomainJobStats(), and the various block jobs) to all have
ids, where the existing APIs act like thin wrappers around more
powerful APIs that support a job id everywhere.

The full list of new API:
        virDomainBackupBegin;
        virDomainBackupEnd;
        virDomainBackupGetXMLDesc;
        virDomainListJobIds;
        virDomainSnapshotCreateXML2;

Signed-off-by: Eric Blake <eblake at redhat.com>
---
 include/libvirt/libvirt-domain-snapshot.h |   7 +-
 include/libvirt/libvirt-domain.h          |  53 +++-
 src/driver-hypervisor.h                   |  27 ++
 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                      | 285 +++++++++++++++++++++-
 src/libvirt_public.syms                   |   5 +
 tools/virsh-domain.c                      |   8 +-
 10 files changed, 463 insertions(+), 17 deletions(-)

diff --git a/include/libvirt/libvirt-domain-snapshot.h b/include/libvirt/libvirt-domain-snapshot.h
index 602e5def59..632e99c61a 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,11 @@ virDomainSnapshotPtr virDomainSnapshotCreateXML(virDomainPtr domain,
                                                 const char *xmlDesc,
                                                 unsigned int flags);

+virDomainSnapshotPtr virDomainSnapshotCreateXML2(virDomainPtr domain,
+                                                 const char *xmlDesc,
+                                                 const char *snapshotXml,
+                                                 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 94504e70a6..59fb645755 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
@@ -2420,6 +2420,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
@@ -3231,6 +3234,18 @@ int virDomainGetJobStats(virDomainPtr domain,
                          unsigned int flags);
 int virDomainAbortJob(virDomainPtr dom);

+typedef struct _virDomainJobId virDomainJobId;
+typedef virDomainJobId *virDomainJobIdPtr;
+struct _virDomainJobId {
+    /* One of virDomainJobType */
+    int type;
+
+    /* The job id */
+    int id;
+};
+int virDomainListJobIds(virDomainPtr dom, virDomainJobId **ids,
+                        unsigned int flags);
+
 typedef enum {
     VIR_DOMAIN_JOB_OPERATION_UNKNOWN = 0,
     VIR_DOMAIN_JOB_OPERATION_START = 1,
@@ -3241,6 +3256,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
@@ -3256,6 +3272,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:
  *
@@ -4080,7 +4104,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).
@@ -4876,4 +4901,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 e6efce1bfe..3cdd8a9031 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -729,6 +729,11 @@ typedef int
 typedef int
 (*virDrvDomainAbortJob)(virDomainPtr domain);

+typedef int
+(*virDrvDomainListJobIds)(virDomainPtr dom,
+                          virDomainJobId **ids,
+                          unsigned int flags);
+
 typedef int
 (*virDrvDomainMigrateGetMaxDowntime)(virDomainPtr domain,
                                      unsigned long long *downtime,
@@ -797,6 +802,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 +1387,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;

@@ -1527,6 +1549,7 @@ struct _virHypervisorDriver {
     virDrvDomainGetJobInfo domainGetJobInfo;
     virDrvDomainGetJobStats domainGetJobStats;
     virDrvDomainAbortJob domainAbortJob;
+    virDrvDomainListJobIds domainListJobIds;
     virDrvDomainMigrateGetMaxDowntime domainMigrateGetMaxDowntime;
     virDrvDomainMigrateSetMaxDowntime domainMigrateSetMaxDowntime;
     virDrvDomainMigrateGetCompressionCache domainMigrateGetCompressionCache;
@@ -1541,6 +1564,7 @@ struct _virHypervisorDriver {
     virDrvDomainManagedSaveGetXMLDesc domainManagedSaveGetXMLDesc;
     virDrvDomainManagedSaveDefineXML domainManagedSaveDefineXML;
     virDrvDomainSnapshotCreateXML domainSnapshotCreateXML;
+    virDrvDomainSnapshotCreateXML2 domainSnapshotCreateXML2;
     virDrvDomainSnapshotGetXMLDesc domainSnapshotGetXMLDesc;
     virDrvDomainSnapshotNum domainSnapshotNum;
     virDrvDomainSnapshotListNames domainSnapshotListNames;
@@ -1638,6 +1662,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 5f2b1f68b5..fc45d6c680 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1092,7 +1092,7 @@ VIR_ENUM_IMPL(virDomainOsDefFirmware,
  * <mirror> XML (remaining types are not two-phase). */
 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 1ff4962fc1..45d187099e 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -1,7 +1,7 @@
 /*
  * libvirt-domain.c: entry points for virDomainPtr APIs
  *
- * 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
@@ -8726,8 +8726,9 @@ virDomainIsUpdated(virDomainPtr dom)
  * @domain: a domain object
  * @info: pointer to a virDomainJobInfo structure allocated by the user
  *
- * Extract information about progress of a background job on a domain.
- * Will return an error if the domain is not active.
+ * Extract information about progress of the default background job
+ * (id 0) on a domain.  Will return an error if the domain is not
+ * active.
  *
  * This function returns a limited amount of information in comparison
  * to virDomainGetJobStats().
@@ -8775,13 +8776,13 @@ virDomainGetJobInfo(virDomainPtr domain, virDomainJobInfoPtr info)
  * @nparams: number of items in @params
  * @flags: bitwise-OR of virDomainGetJobStatsFlags
  *
- * Extract information about progress of a background job on a domain.
- * Will return an error if the domain is not active. The function returns
- * a superset of progress information provided by virDomainGetJobInfo.
- * Possible fields returned in @params are defined by VIR_DOMAIN_JOB_*
- * macros and new fields will likely be introduced in the future so callers
- * may receive fields that they do not understand in case they talk to a
- * newer server.
+ * Extract information about progress of the default background job
+ * (id 0) on a domain. Will return an error if the domain is not
+ * active. The function returns a superset of progress information
+ * provided by virDomainGetJobInfo().  Possible fields returned in
+ * @params are defined by VIR_DOMAIN_JOB_* macros and new fields will
+ * likely be introduced in the future so callers may receive fields
+ * that they do not understand in case they talk to a newer server.
  *
  * When @flags contains VIR_DOMAIN_JOB_STATS_COMPLETED, the function will
  * return statistics about a recently completed job. Specifically, this
@@ -8839,7 +8840,7 @@ virDomainGetJobStats(virDomainPtr domain,
  * virDomainAbortJob:
  * @domain: a domain object
  *
- * Requests that the current background job be aborted at the
+ * Requests that the current default background job (id 0) be aborted at the
  * soonest opportunity. In case the job is a migration in a post-copy mode,
  * virDomainAbortJob will report an error (see virDomainMigrateStartPostCopy
  * for more details).
@@ -8876,6 +8877,57 @@ virDomainAbortJob(virDomainPtr domain)
 }


+/**
+ * virDomainListJobIds:
+ * @domain: a domain object
+ * @ids: Pointer to a variable to store the array containing job ids or NULL
+ *       if the list is not required (just returns number of jobs).
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Collect a list of all background jobs, and return an allocated
+ * array of information about the type and id of each.
+ *
+ * The default background job (id 0, which is typically migration)
+ * might not be included in the list; for that, use
+ * virDomainJobStats(). The job id may be important to other APIs
+ * related to the job type; for example, a backup job id (created by
+ * virDomainBackupBegin()) is required for calling
+ * virDomainBackupEnd().
+ *
+ * Returns the number of jobs found or -1 and sets @ids to NULL in
+ * case of error. The caller is responsible for calling free() on
+ * @ids.
+ */
+int
+virDomainListJobIds(virDomainPtr domain,
+                    virDomainJobId **ids,
+                    unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    if (conn->driver->domainListJobIds) {
+        int ret;
+        ret = conn->driver->domainListJobIds(domain, ids, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
 /**
  * virDomainMigrateSetMaxDowntime:
  * @domain: a domain object
@@ -10341,6 +10393,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
@@ -12361,3 +12419,208 @@ 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 previously started with
+ *      virDomainBackupBegin()
+ * @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.
+ *
+ * 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 previously started with
+ *      virDomainBackupBegin()
+ * @flags: bitwise-OR of supported virDomainBackupEndFlags
+ *
+ * Conclude a point-in-time backup job @id on the given domain.
+ *
+ * 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 d026b33f53..d13df6bb67 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -817,6 +817,9 @@ LIBVIRT_4.10.0 {
 LIBVIRT_5.2.0 {
     global:
         virConnectGetStoragePoolCapabilities;
+        virDomainBackupBegin;
+        virDomainBackupEnd;
+        virDomainBackupGetXMLDesc;
         virDomainCheckpointCreateXML;
         virDomainCheckpointCurrent;
         virDomainCheckpointDelete;
@@ -833,6 +836,8 @@ LIBVIRT_5.2.0 {
         virDomainCheckpointRef;
         virDomainHasCurrentCheckpoint;
         virDomainListCheckpoints;
+        virDomainListJobIds;
+        virDomainSnapshotCreateXML2;
 } LIBVIRT_4.10.0;

 # .... define new API here using predicted next version number ....
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 01aa1bd017..bb3a6d5b6b 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -2561,7 +2561,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)
@@ -6064,7 +6066,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




More information about the libvir-list mailing list