[libvirt] [python PATCH v7] Add virDomainCheckpoint APIs

Eric Blake eblake at redhat.com
Wed Mar 27 10:09:27 UTC 2019


Copies heavily from existing virDomainSnapshot handling, regarding
what special cases the generator has to be taught and what overrides
need to be written.

Signed-off-by: Eric Blake <eblake at redhat.com>
---

Python counterparts to my incremental backup patches. An earlier
version was already reviewed by Dan; the main diff here is the
addition of virDomainSnapshotCreateXML2 handling.

 HACKING                                 |  2 +
 MANIFEST.in                             |  1 +
 generator.py                            | 37 ++++++++--
 libvirt-override-api.xml                | 12 ++++
 libvirt-override-virDomain.py           | 13 ++++
 libvirt-override-virDomainCheckpoint.py | 19 +++++
 libvirt-override.c                      | 96 +++++++++++++++++++++++++
 sanitytest.py                           | 11 +--
 typewrappers.c                          | 13 ++++
 typewrappers.h                          | 10 +++
 10 files changed, 206 insertions(+), 8 deletions(-)
 create mode 100644 libvirt-override-virDomainCheckpoint.py

diff --git a/HACKING b/HACKING
index 6eeb9e6..39e7cd3 100644
--- a/HACKING
+++ b/HACKING
@@ -28,6 +28,8 @@ hand written source files
    the virConnect class
  - libvirt-override-virDomain.py - high level overrides in
    the virDomain class
+ - libvirt-override-virDomainCheckpoint.py - high level overrides in
+   the virDomainCheckpoint class
  - libvirt-override-virDomainSnapshot.py - high level overrides in
    the virDomainSnapshot class
  - libvirt-override-virStoragePool.py - high level overrides in
diff --git a/MANIFEST.in b/MANIFEST.in
index b6788f4..5d2f559 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -23,6 +23,7 @@ include libvirt-override.c
 include libvirt-override.py
 include libvirt-override-virConnect.py
 include libvirt-override-virDomain.py
+include libvirt-override-virDomainCheckpoint.py
 include libvirt-override-virDomainSnapshot.py
 include libvirt-override-virStoragePool.py
 include libvirt-override-virStream.py
diff --git a/generator.py b/generator.py
index ffa3ce5..a16f9b1 100755
--- a/generator.py
+++ b/generator.py
@@ -35,6 +35,7 @@ libvirt_headers = [
     "libvirt",
     "libvirt-common",
     "libvirt-domain",
+    "libvirt-domain-checkpoint",
     "libvirt-domain-snapshot",
     "libvirt-event",
     "libvirt-host",
@@ -364,6 +365,10 @@ py_types = {
     'virStream *':  ('O', "virStream", "virStreamPtr", "virStreamPtr"),
     'const virStream *':  ('O', "virStream", "virStreamPtr", "virStreamPtr"),

+    'virDomainCheckpointPtr':  ('O', "virDomainCheckpoint", "virDomainCheckpointPtr", "virDomainCheckpointPtr"),
+    'virDomainCheckpoint *':  ('O', "virDomainCheckpoint", "virDomainCheckpointPtr", "virDomainCheckpointPtr"),
+    'const virDomainCheckpoint *':  ('O', "virDomainCheckpoint", "virDomainCheckpointPtr", "virDomainCheckpointPtr"),
+
     'virDomainSnapshotPtr':  ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
     'virDomainSnapshot *':  ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
     'const virDomainSnapshot *':  ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
@@ -536,6 +541,8 @@ skip_function = (
     'virSaveLastError', # We have our own python error wrapper
     'virFreeError', # Only needed if we use virSaveLastError
     'virConnectListAllDomains', # overridden in virConnect.py
+    'virDomainListAllCheckpoints', # overridden in virDomain.py
+    'virDomainCheckpointListAllChildren', # overridden in virDomainCheckpoint.py
     'virDomainListAllSnapshots', # overridden in virDomain.py
     'virDomainSnapshotListAllChildren', # overridden in virDomainSnapshot.py
     'virConnectListAllStoragePools', # overridden in virConnect.py
@@ -582,6 +589,7 @@ skip_function = (
     "virStoragePoolRef",
     "virStorageVolRef",
     "virStreamRef",
+    "virDomainCheckpointRef",
     "virDomainSnapshotRef",

     # This functions shouldn't be called via the bindings (and even the docs
@@ -594,6 +602,8 @@ skip_function = (
     "virNWFilterGetConnect",
     "virStoragePoolGetConnect",
     "virStorageVolGetConnect",
+    "virDomainCheckpointGetConnect",
+    "virDomainCheckpointGetDomain",
     "virDomainSnapshotGetConnect",
     "virDomainSnapshotGetDomain",

@@ -1023,6 +1033,8 @@ classes_type = {
     "virStream *": ("._o", "virStream(self, _obj=%s)", "virStream"),
     "virConnectPtr": ("._o", "virConnect(_obj=%s)", "virConnect"),
     "virConnect *": ("._o", "virConnect(_obj=%s)", "virConnect"),
+    "virDomainCheckpointPtr": ("._o", "virDomainCheckpoint(self,_obj=%s)", "virDomainCheckpoint"),
+    "virDomainCheckpoint *": ("._o", "virDomainCheckpoint(self, _obj=%s)", "virDomainCheckpoint"),
     "virDomainSnapshotPtr": ("._o", "virDomainSnapshot(self,_obj=%s)", "virDomainSnapshot"),
     "virDomainSnapshot *": ("._o", "virDomainSnapshot(self, _obj=%s)", "virDomainSnapshot"),
 }
@@ -1031,7 +1043,7 @@ primary_classes = ["virDomain", "virNetwork", "virInterface",
                    "virStoragePool", "virStorageVol",
                    "virConnect", "virNodeDevice", "virSecret",
                    "virNWFilter", "virNWFilterBinding",
-                   "virStream", "virDomainSnapshot"]
+                   "virStream", "virDomainCheckpoint", "virDomainSnapshot"]

 classes_destructors = {
     "virDomain": "virDomainFree",
@@ -1043,6 +1055,7 @@ classes_destructors = {
     "virSecret": "virSecretFree",
     "virNWFilter": "virNWFilterFree",
     "virNWFilterBinding": "virNWFilterBindingFree",
+    "virDomainCheckpoint": "virDomainCheckpointFree",
     "virDomainSnapshot": "virDomainSnapshotFree",
     # We hand-craft __del__ for this one
     #"virStream": "virStreamFree",
@@ -1053,6 +1066,7 @@ class_skip_connect_impl = {
 }

 class_domain_impl = {
+    "virDomainCheckpoint": True,
     "virDomainSnapshot": True,
 }

@@ -1171,6 +1185,18 @@ def nameFixup(name, classe, type, file):
     elif name[0:12] == "virDomainGet":
         func = name[12:]
         func = func[0:1].lower() + func[1:]
+    elif name[0:31] == "virDomainCheckpointLookupByName":
+        func = name[9:]
+        func = func[0:1].lower() + func[1:]
+    elif name[0:28] == "virDomainCheckpointCreateXML":
+        func = name[9:]
+        func = func[0:1].lower() + func[1:]
+    elif name[0:26] == "virDomainCheckpointCurrent":
+        func = name[9:]
+        func = func[0:1].lower() + func[1:]
+    elif name[0:19] == "virDomainCheckpoint":
+        func = name[19:]
+        func = func[0:1].lower() + func[1:]
     elif name[0:29] == "virDomainSnapshotLookupByName":
         func = name[9:]
         func = func[0:1].lower() + func[1:]
@@ -1183,6 +1209,9 @@ def nameFixup(name, classe, type, file):
     elif name[0:20] == "virDomainSnapshotNum":
         func = name[9:]
         func = func[0:1].lower() + func[1:]
+    elif name[0:27] == "virDomainSnapshotCreateXML2":
+        func = name[9:]
+        func = func[0:1].lower() + func[1:]
     elif name[0:26] == "virDomainSnapshotCreateXML":
         func = name[9:]
         func = func[0:1].lower() + func[1:]
@@ -1501,7 +1530,7 @@ def buildWrappers(module):
                               "virStorageVol", "virNodeDevice", "virSecret","virStream",
                               "virNWFilter", "virNWFilterBinding" ]:
                 classes.write("    def __init__(self, conn, _obj=None):\n")
-            elif classname in [ 'virDomainSnapshot' ]:
+            elif classname in [ "virDomainCheckpoint", "virDomainSnapshot" ]:
                 classes.write("    def __init__(self, dom, _obj=None):\n")
             else:
                 classes.write("    def __init__(self, _obj=None):\n")
@@ -1513,7 +1542,7 @@ def buildWrappers(module):
                 classes.write("        self._conn = conn\n" + \
                               "        if not isinstance(conn, virConnect):\n" + \
                               "            self._conn = conn._conn\n")
-            elif classname in [ "virDomainSnapshot" ]:
+            elif classname in [ "virDomainCheckpoint", "virDomainSnapshot" ]:
                 classes.write("        self._dom = dom\n")
                 classes.write("        self._conn = dom.connect()\n")
             classes.write("        if type(_obj).__name__ not in [\"PyCapsule\", \"PyCObject\"]:\n")
@@ -1641,7 +1670,7 @@ def buildWrappers(module):
                                 classes.write(
                      "        if ret is None:raise libvirtError('%s() failed', vol=self)\n" %
                                               (name))
-                            elif classname == "virDomainSnapshot":
+                            elif classname in [ "virDomainCheckpoint", "virDomainSnapshot"]:
                                 classes.write(
                      "        if ret is None:raise libvirtError('%s() failed', dom=self._dom)\n" %
                                               (name))
diff --git a/libvirt-override-api.xml b/libvirt-override-api.xml
index 7f578e0..1edf0c5 100644
--- a/libvirt-override-api.xml
+++ b/libvirt-override-api.xml
@@ -576,6 +576,18 @@
       <arg name='flags' type='unsigned int' info='flags'/>
       <return type='int' info="0 on success, -1 on error"/>
     </function>
+    <function name='virDomainListAllCheckpoints' file='python'>
+      <info>returns the list of checkpoints for the given domain</info>
+      <arg name='dom' type='virDomainPtr' info='pointer to the domain'/>
+      <arg name='flags' type='unsigned int' info='flags'/>
+      <return type='char *' info='the list of checkpoints or None in case of error'/>
+    </function>
+    <function name='virDomainCheckpointListAllChildren' file='python'>
+      <info>collect the list of child checkpoint names for the given checkpoint</info>
+      <arg name='checkpoint' type='virDomainCheckpointPtr' info='pointer to the checkpoint'/>
+      <arg name='flags' type='unsigned int' info='flags'/>
+      <return type='char *' info='the list of checkpoints or None in case of error'/>
+    </function>
     <function name='virDomainGetBlockJobInfo' file='python'>
       <info>Get progress information for a block job</info>
       <arg name='dom' type='virDomainPtr' info='pointer to the domain'/>
diff --git a/libvirt-override-virDomain.py b/libvirt-override-virDomain.py
index 7c417b8..7ce34f1 100644
--- a/libvirt-override-virDomain.py
+++ b/libvirt-override-virDomain.py
@@ -11,6 +11,19 @@
         return retlist


+    def listAllCheckpoints(self, flags=0):
+        """List all checkpoints and returns a list of checkpoint objects"""
+        ret = libvirtmod.virDomainListAllCheckpoints(self._o, flags)
+        if ret is None:
+            raise libvirtError("virDomainListAllCheckpoints() failed", conn=self)
+
+        retlist = list()
+        for chkptr in ret:
+            retlist.append(virDomainCheckpoint(self, _obj=chkptr))
+
+        return retlist
+
+
     def createWithFiles(self, files, flags=0):
         """Launch a defined domain. If the call succeeds the domain moves from the
         defined to the running domains pools.
diff --git a/libvirt-override-virDomainCheckpoint.py b/libvirt-override-virDomainCheckpoint.py
new file mode 100644
index 0000000..371b0fd
--- /dev/null
+++ b/libvirt-override-virDomainCheckpoint.py
@@ -0,0 +1,19 @@
+    def getConnect(self):
+        """Get the connection that owns the domain that a checkpoint was created for"""
+        return self.connect()
+
+    def getDomain(self):
+        """Get the domain that a checkpoint was created for"""
+        return self.domain()
+
+    def listAllChildren(self, flags=0):
+        """List all child checkpoints and returns a list of checkpoint objects"""
+        ret = libvirtmod.virDomainCheckpointListAllChildren(self._o, flags)
+        if ret is None:
+            raise libvirtError("virDomainCheckpointListAllChildren() failed", conn=self)
+
+        retlist = list()
+        for chkptr in ret:
+            retlist.append(virDomainCheckpoint(self, _obj=chkptr))
+
+        return retlist
diff --git a/libvirt-override.c b/libvirt-override.c
index c5e2908..777f533 100644
--- a/libvirt-override.c
+++ b/libvirt-override.c
@@ -2325,6 +2325,98 @@ libvirt_virConnectListDefinedDomains(PyObject *self ATTRIBUTE_UNUSED,
     goto cleanup;
 }

+#if LIBVIR_CHECK_VERSION(5, 1, 0)
+static PyObject *
+libvirt_virDomainListAllCheckpoints(PyObject *self ATTRIBUTE_UNUSED,
+                                    PyObject *args)
+{
+    PyObject *py_retval = NULL;
+    virDomainCheckpointPtr *chks = NULL;
+    int c_retval;
+    ssize_t i;
+    virDomainPtr dom;
+    PyObject *pyobj_dom;
+    unsigned int flags;
+
+    if (!PyArg_ParseTuple(args, (char *)"OI:virDomainListAllCheckpoints",
+                          &pyobj_dom, &flags))
+        return NULL;
+    dom = (virDomainPtr) PyvirDomain_Get(pyobj_dom);
+
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+    c_retval = virDomainListAllCheckpoints(dom, &chks, flags);
+    LIBVIRT_END_ALLOW_THREADS;
+
+    if (c_retval < 0)
+        return VIR_PY_NONE;
+
+    if (!(py_retval = PyList_New(c_retval)))
+        goto cleanup;
+
+    for (i = 0; i < c_retval; i++) {
+        VIR_PY_LIST_SET_GOTO(py_retval, i,
+                             libvirt_virDomainCheckpointPtrWrap(chks[i]), error);
+        chks[i] = NULL;
+    }
+
+ cleanup:
+    for (i = 0; i < c_retval; i++)
+        if (chks[i])
+            virDomainCheckpointFree(chks[i]);
+    VIR_FREE(chks);
+    return py_retval;
+
+ error:
+    Py_CLEAR(py_retval);
+    goto cleanup;
+}
+
+static PyObject *
+libvirt_virDomainCheckpointListAllChildren(PyObject *self ATTRIBUTE_UNUSED,
+                                           PyObject *args)
+{
+    PyObject *py_retval = NULL;
+    virDomainCheckpointPtr *chks = NULL;
+    int c_retval;
+    ssize_t i;
+    virDomainCheckpointPtr parent;
+    PyObject *pyobj_parent;
+    unsigned int flags;
+
+    if (!PyArg_ParseTuple(args, (char *)"OI:virDomainCheckpointListAllChildren",
+                          &pyobj_parent, &flags))
+        return NULL;
+    parent = (virDomainCheckpointPtr) PyvirDomainCheckpoint_Get(pyobj_parent);
+
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+    c_retval = virDomainCheckpointListAllChildren(parent, &chks, flags);
+    LIBVIRT_END_ALLOW_THREADS;
+
+    if (c_retval < 0)
+        return VIR_PY_NONE;
+
+    if (!(py_retval = PyList_New(c_retval)))
+        goto cleanup;
+
+    for (i = 0; i < c_retval; i++) {
+        VIR_PY_LIST_SET_GOTO(py_retval, i,
+                             libvirt_virDomainCheckpointPtrWrap(chks[i]), error);
+        chks[i] = NULL;
+    }
+
+ cleanup:
+    for (i = 0; i < c_retval; i++)
+        if (chks[i])
+            virDomainCheckpointFree(chks[i]);
+    VIR_FREE(chks);
+    return py_retval;
+
+ error:
+    Py_CLEAR(py_retval);
+    goto cleanup;
+}
+#endif /* LIBVIR_CHECK_VERSION(5, 1, 0) */
+
 static PyObject *
 libvirt_virDomainSnapshotListNames(PyObject *self ATTRIBUTE_UNUSED,
                                    PyObject *args)
@@ -10100,6 +10192,10 @@ static PyMethodDef libvirtMethods[] = {
 #if LIBVIR_CHECK_VERSION(1, 0, 3)
     {(char *) "virDomainGetJobStats", libvirt_virDomainGetJobStats, METH_VARARGS, NULL},
 #endif /* LIBVIR_CHECK_VERSION(1, 0, 3) */
+#if LIBVIR_CHECK_VERSION(5, 1, 0)
+    {(char *) "virDomainListAllCheckpoints", libvirt_virDomainListAllCheckpoints, METH_VARARGS, NULL},
+    {(char *) "virDomainCheckpointListAllChildren", libvirt_virDomainCheckpointListAllChildren, METH_VARARGS, NULL},
+#endif /* LIBVIR_CHECK_VERSION(5, 1, 0) */
     {(char *) "virDomainSnapshotListNames", libvirt_virDomainSnapshotListNames, METH_VARARGS, NULL},
 #if LIBVIR_CHECK_VERSION(0, 9, 13)
     {(char *) "virDomainListAllSnapshots", libvirt_virDomainListAllSnapshots, METH_VARARGS, NULL},
diff --git a/sanitytest.py b/sanitytest.py
index 68dde6b..b044231 100644
--- a/sanitytest.py
+++ b/sanitytest.py
@@ -249,13 +249,13 @@ for name in sorted(basicklassmap):
     # Remove 'Get' prefix from most APIs, except those in virConnect
     # and virDomainSnapshot namespaces which stupidly used a different
     # convention which we now can't fix without breaking API
-    if func[0:3] == "Get" and klass not in ["virConnect", "virDomainSnapshot", "libvirt"]:
+    if func[0:3] == "Get" and klass not in ["virConnect", "virDomainCheckpoint", "virDomainSnapshot", "libvirt"]:
         if func not in ["GetCPUStats", "GetTime"]:
             func = func[3:]

     # The object creation and lookup APIs all have to get re-mapped
     # into the parent class
-    if func in ["CreateXML", "CreateLinux", "CreateXMLWithFiles",
+    if func in ["CreateXML", "CreateXML2", "CreateLinux", "CreateXMLWithFiles",
                 "DefineXML", "CreateXMLFrom", "LookupByUUID",
                 "LookupByUUIDString", "LookupByVolume" "LookupByName",
                 "LookupByID", "LookupByName", "LookupByKey", "LookupByPath",
@@ -266,7 +266,7 @@ for name in sorted(basicklassmap):
         if klass != "virDomain":
             func = klass[3:] + func

-        if klass == "virDomainSnapshot":
+        if klass in [ "virDomainCheckpoint", "virDomainSnapshot"]:
             klass = "virDomain"
             func = func[6:]
         elif klass == "virStorageVol" and func in ["StorageVolCreateXMLFrom", "StorageVolCreateXML"]:
@@ -297,10 +297,13 @@ for name in sorted(basicklassmap):
     if func[0:6] == "Change":
         klass = "virConnect"

-    # Need to special case the snapshot APIs
+    # Need to special case the checkpoint and snapshot APIs
     if klass == "virDomainSnapshot" and func in ["Current", "ListNames", "Num"]:
         klass = "virDomain"
         func = "snapshot" + func
+    elif klass == "virDomainCheckpoint" and func == "Current":
+        klass = "virDomain"
+        func = "checkpoint" + func

     # Names should start with lowercase letter...
     func = func[0:1].lower() + func[1:]
diff --git a/typewrappers.c b/typewrappers.c
index 9ba14b4..cd7a70b 100644
--- a/typewrappers.c
+++ b/typewrappers.c
@@ -568,6 +568,19 @@ libvirt_virStreamPtrWrap(virStreamPtr node)
     return ret;
 }

+PyObject *
+libvirt_virDomainCheckpointPtrWrap(virDomainCheckpointPtr node)
+{
+    PyObject *ret;
+
+    if (node == NULL) {
+        return VIR_PY_NONE;
+    }
+
+    ret = libvirt_buildPyObject(node, "virDomainCheckpointPtr", NULL);
+    return ret;
+}
+
 PyObject *
 libvirt_virDomainSnapshotPtrWrap(virDomainSnapshotPtr node)
 {
diff --git a/typewrappers.h b/typewrappers.h
index 4423774..198397b 100644
--- a/typewrappers.h
+++ b/typewrappers.h
@@ -128,6 +128,15 @@ typedef struct {
 } PyvirStream_Object;


+#define PyvirDomainCheckpoint_Get(v) (((v) == Py_None) ? NULL : \
+        (((PyvirDomainCheckpoint_Object *)(v))->obj))
+
+typedef struct {
+    PyObject_HEAD
+    virDomainCheckpointPtr obj;
+} PyvirDomainCheckpoint_Object;
+
+
 #define PyvirDomainSnapshot_Get(v) (((v) == Py_None) ? NULL : \
         (((PyvirDomainSnapshot_Object *)(v))->obj))

@@ -204,6 +213,7 @@ PyObject * libvirt_virSecretPtrWrap(virSecretPtr node);
 PyObject * libvirt_virNWFilterPtrWrap(virNWFilterPtr node);
 PyObject * libvirt_virNWFilterBindingPtrWrap(virNWFilterBindingPtr node);
 PyObject * libvirt_virStreamPtrWrap(virStreamPtr node);
+PyObject * libvirt_virDomainCheckpointPtrWrap(virDomainCheckpointPtr node);
 PyObject * libvirt_virDomainSnapshotPtrWrap(virDomainSnapshotPtr node);


-- 
2.20.1




More information about the libvir-list mailing list