[libvirt] [PATCH v9 13/13] backup: Add virDomainCheckpointIsCurrent API

Eric Blake eblake at redhat.com
Sun Jul 7 03:56:13 UTC 2019


It is possible, but tedious, to tell if a checkpoint is current by
parsing XML. As this operation may be performed with some frequency,
it is worth an additional API (comparable to the existing
virDomainCheckpointGetParent that duplicates what can be learned from
XML, or the counterpart virDomainSnapshotIsCurrent although snapshots
don't currently expose whether they are current in public XML).

Signed-off-by: Eric Blake <eblake at redhat.com>
---
 include/libvirt/libvirt-domain-checkpoint.h |  4 +++
 src/driver-hypervisor.h                     |  5 +++
 src/libvirt-domain-checkpoint.c             | 38 +++++++++++++++++++++
 src/libvirt_public.syms                     |  1 +
 src/qemu/qemu_driver.c                      | 28 +++++++++++++++
 src/remote/remote_driver.c                  |  1 +
 src/remote/remote_protocol.x                | 18 +++++++++-
 src/remote_protocol-structs                 |  8 +++++
 src/test/test_driver.c                      | 25 ++++++++++++++
 tools/virsh-checkpoint.c                    | 21 +++---------
 10 files changed, 132 insertions(+), 17 deletions(-)

diff --git a/include/libvirt/libvirt-domain-checkpoint.h b/include/libvirt/libvirt-domain-checkpoint.h
index b2d5c5758b..b03e0f8328 100644
--- a/include/libvirt/libvirt-domain-checkpoint.h
+++ b/include/libvirt/libvirt-domain-checkpoint.h
@@ -127,6 +127,10 @@ virDomainCheckpointPtr virDomainCheckpointLookupByName(virDomainPtr domain,
 virDomainCheckpointPtr virDomainCheckpointGetParent(virDomainCheckpointPtr checkpoint,
                                                     unsigned int flags);

+/* Determine if a checkpoint is current */
+int virDomainCheckpointIsCurrent(virDomainCheckpointPtr checkpoint,
+                                 unsigned int flags);
+
 /* Delete a checkpoint */
 typedef enum {
     VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN      = (1 << 0), /* Also delete children */
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index c1632ae4c6..395b710a26 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -1355,6 +1355,10 @@ typedef virDomainCheckpointPtr
 (*virDrvDomainCheckpointGetParent)(virDomainCheckpointPtr checkpoint,
                                    unsigned int flags);

+typedef int
+(*virDrvDomainCheckpointIsCurrent)(virDomainCheckpointPtr checkpoint,
+                                   unsigned int flags);
+
 typedef int
 (*virDrvDomainCheckpointDelete)(virDomainCheckpointPtr checkpoint,
                                 unsigned int flags);
@@ -1617,4 +1621,5 @@ struct _virHypervisorDriver {
     virDrvDomainCheckpointLookupByName domainCheckpointLookupByName;
     virDrvDomainCheckpointGetParent domainCheckpointGetParent;
     virDrvDomainCheckpointDelete domainCheckpointDelete;
+    virDrvDomainCheckpointIsCurrent domainCheckpointIsCurrent;
 };
diff --git a/src/libvirt-domain-checkpoint.c b/src/libvirt-domain-checkpoint.c
index ab82d8422b..e1fd81ede0 100644
--- a/src/libvirt-domain-checkpoint.c
+++ b/src/libvirt-domain-checkpoint.c
@@ -471,6 +471,44 @@ virDomainCheckpointGetParent(virDomainCheckpointPtr checkpoint,
 }


+/**
+ * virDomainCheckpointIsCurrent:
+ * @checkpoint: a checkpoint object
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Determine if the given checkpoint is the domain's current checkpoint.  See
+ * also virDomainCheckpointCurrent().
+ *
+ * Returns 1 if current, 0 if not current, or -1 on error.
+ */
+int
+virDomainCheckpointIsCurrent(virDomainCheckpointPtr checkpoint,
+                             unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DEBUG("checkpoint=%p, flags=0x%x", checkpoint, flags);
+
+    virResetLastError();
+
+    virCheckDomainCheckpointReturn(checkpoint, -1);
+    conn = checkpoint->domain->conn;
+
+    if (conn->driver->domainCheckpointIsCurrent) {
+        int ret;
+        ret = conn->driver->domainCheckpointIsCurrent(checkpoint, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
 /**
  * virDomainCheckpointDelete:
  * @checkpoint: the checkpoint to remove
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 54256b6317..6401916a81 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -846,6 +846,7 @@ LIBVIRT_5.6.0 {
         virDomainCheckpointGetName;
         virDomainCheckpointGetParent;
         virDomainCheckpointGetXMLDesc;
+        virDomainCheckpointIsCurrent;
         virDomainCheckpointListAllChildren;
         virDomainCheckpointLookupByName;
         virDomainCheckpointRef;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b37307abc7..4131367245 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -17328,6 +17328,33 @@ qemuDomainCheckpointGetParent(virDomainCheckpointPtr checkpoint,
 }


+static int
+qemuDomainCheckpointIsCurrent(virDomainCheckpointPtr checkpoint,
+                              unsigned int flags)
+{
+    virDomainObjPtr vm;
+    int ret = -1;
+    virDomainMomentObjPtr chk = NULL;
+
+    virCheckFlags(0, -1);
+
+    if (!(vm = qemuDomObjFromCheckpoint(checkpoint)))
+        return -1;
+
+    if (virDomainCheckpointIsCurrentEnsureACL(checkpoint->domain->conn, vm->def) < 0)
+        goto cleanup;
+
+    if (!(chk = qemuCheckObjFromCheckpoint(vm, checkpoint)))
+        goto cleanup;
+
+    ret = chk == virDomainCheckpointGetCurrent(vm->checkpoints);
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return ret;
+}
+
+
 static char *
 qemuDomainCheckpointGetXMLDesc(virDomainCheckpointPtr checkpoint,
                                unsigned int flags)
@@ -23174,6 +23201,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
     .domainCheckpointLookupByName = qemuDomainCheckpointLookupByName, /* 5.6.0 */
     .domainCheckpointGetParent = qemuDomainCheckpointGetParent, /* 5.6.0 */
     .domainCheckpointDelete = qemuDomainCheckpointDelete, /* 5.6.0 */
+    .domainCheckpointIsCurrent = qemuDomainCheckpointIsCurrent, /* 5.6.0 */
 };


diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 72c2336b7a..9145aa91ff 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -8596,6 +8596,7 @@ static virHypervisorDriver hypervisor_driver = {
     .domainCheckpointLookupByName = remoteDomainCheckpointLookupByName, /* 5.6.0 */
     .domainCheckpointGetParent = remoteDomainCheckpointGetParent, /* 5.6.0 */
     .domainCheckpointDelete = remoteDomainCheckpointDelete, /* 5.6.0 */
+    .domainCheckpointIsCurrent = remoteDomainCheckpointIsCurrent, /* 5.6.0 */
 };

 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 2f91bd1921..a2bd30360f 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3718,6 +3718,15 @@ struct remote_domain_checkpoint_get_parent_ret {
     remote_nonnull_domain_checkpoint parent;
 };

+struct remote_domain_checkpoint_is_current_args {
+    remote_nonnull_domain_checkpoint checkpoint;
+    unsigned int flags;
+};
+
+struct remote_domain_checkpoint_is_current_ret {
+    int current;
+};
+
 struct remote_domain_checkpoint_delete_args {
     remote_nonnull_domain_checkpoint checkpoint;
     unsigned int flags;
@@ -6584,5 +6593,12 @@ enum remote_procedure {
      * @generate: both
      * @acl: domain:checkpoint
      */
-    REMOTE_PROC_DOMAIN_CHECKPOINT_DELETE = 417
+    REMOTE_PROC_DOMAIN_CHECKPOINT_DELETE = 417,
+
+    /**
+     * @generate: both
+     * @priority: high
+     * @acl: domain:read
+     */
+    REMOTE_PROC_DOMAIN_CHECKPOINT_IS_CURRENT = 418
 };
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index a42b4a9671..ba4337b1bd 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -3101,6 +3101,13 @@ struct remote_domain_checkpoint_get_parent_args {
 struct remote_domain_checkpoint_get_parent_ret {
         remote_nonnull_domain_checkpoint parent;
 };
+struct remote_domain_checkpoint_is_current_args {
+        remote_nonnull_domain_checkpoint checkpoint;
+        u_int                      flags;
+};
+struct remote_domain_checkpoint_is_current_ret {
+        int                        current;
+};
 struct remote_domain_checkpoint_delete_args {
         remote_nonnull_domain_checkpoint checkpoint;
         u_int                      flags;
@@ -3523,4 +3530,5 @@ enum remote_procedure {
         REMOTE_PROC_DOMAIN_CHECKPOINT_LOOKUP_BY_NAME = 415,
         REMOTE_PROC_DOMAIN_CHECKPOINT_GET_PARENT = 416,
         REMOTE_PROC_DOMAIN_CHECKPOINT_DELETE = 417,
+        REMOTE_PROC_DOMAIN_CHECKPOINT_IS_CURRENT = 418,
 };
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index ddc8867bdd..0c3505b038 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -7880,6 +7880,30 @@ testDomainCheckpointGetXMLDesc(virDomainCheckpointPtr checkpoint,
 }


+static int
+testDomainCheckpointIsCurrent(virDomainCheckpointPtr checkpoint,
+                              unsigned int flags)
+{
+    virDomainObjPtr vm = NULL;
+    int ret = -1;
+    virDomainMomentObjPtr chk = NULL;
+
+    virCheckFlags(0, -1);
+
+    if (!(vm = testDomObjFromCheckpoint(checkpoint)))
+        return -1;
+
+    if (!(chk = testCheckObjFromCheckpoint(vm, checkpoint)))
+        goto cleanup;
+
+    ret = chk == virDomainCheckpointGetCurrent(vm->checkpoints);
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return ret;
+}
+
+
 static int
 testDomainCheckpointDelete(virDomainCheckpointPtr checkpoint,
                            unsigned int flags)
@@ -8076,6 +8100,7 @@ static virHypervisorDriver testHypervisorDriver = {
     .domainCheckpointLookupByName = testDomainCheckpointLookupByName, /* 5.6.0 */
     .domainCheckpointGetParent = testDomainCheckpointGetParent, /* 5.6.0 */
     .domainCheckpointDelete = testDomainCheckpointDelete, /* 5.6.0 */
+    .domainCheckpointIsCurrent = testDomainCheckpointIsCurrent, /* 5.6.0 */
 };

 static virNetworkDriver testNetworkDriver = {
diff --git a/tools/virsh-checkpoint.c b/tools/virsh-checkpoint.c
index 8200687f8a..a2d34f2102 100644
--- a/tools/virsh-checkpoint.c
+++ b/tools/virsh-checkpoint.c
@@ -522,9 +522,6 @@ cmdCheckpointInfo(vshControl *ctl,
     virDomainCheckpointPtr checkpoint = NULL;
     const char *name;
     char *parent = NULL;
-    char *xml = NULL;
-    xmlDocPtr xmldoc = NULL;
-    xmlXPathContextPtr ctxt = NULL;
     bool ret = false;
     int count;
     unsigned int flags;
@@ -542,17 +539,12 @@ cmdCheckpointInfo(vshControl *ctl,
     vshPrint(ctl, "%-15s %s\n", _("Domain:"), virDomainGetName(dom));

     /* Determine if checkpoint is current.  */
-    xml = virDomainCheckpointGetXMLDesc(checkpoint,
-                                        VIR_DOMAIN_CHECKPOINT_XML_NO_DOMAIN);
-    if (!xml)
-        goto cleanup;
-
-    xmldoc = virXMLParseStringCtxt(xml, _("(domain_checkpoint)"), &ctxt);
-    if (!xmldoc)
-        goto cleanup;
-
-    if (virXPathInt("string(/domaincheckpoint/current)", ctxt, &current) < 0)
+    current = virDomainCheckpointIsCurrent(checkpoint, 0);
+    if (current < 0) {
+        vshError(ctl, "%s",
+                 _("unexpected problem querying checkpoint state"));
         goto cleanup;
+    }
     vshPrint(ctl, "%-15s %s\n", _("Current:"),
              current > 0 ? _("yes") : _("no"));

@@ -583,9 +575,6 @@ cmdCheckpointInfo(vshControl *ctl,
     ret = true;

  cleanup:
-    xmlXPathFreeContext(ctxt);
-    xmlFreeDoc(xmldoc);
-    VIR_FREE(xml);
     VIR_FREE(parent);
     virshDomainCheckpointFree(checkpoint);
     virshDomainFree(dom);
-- 
2.20.1




More information about the libvir-list mailing list