]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
pybind/rbd: async API for creating mirror snapshots
authorMykola Golub <mgolub@suse.com>
Wed, 21 Oct 2020 12:38:31 +0000 (13:38 +0100)
committerJason Dillaman <dillaman@redhat.com>
Wed, 10 Feb 2021 18:37:15 +0000 (13:37 -0500)
Signed-off-by: Mykola Golub <mgolub@suse.com>
(cherry picked from commit d1571ed2743f97280a2f3a2a70fff59e0cafc0b9)

Conflicts:
src/pybind/rbd/rbd.pyx: trival resolution re: quiesce flags

src/pybind/rbd/rbd.pyx
src/test/pybind/test_rbd.py

index 70d032b478913f4e30940ad47466f0bf5aef6f9c..be4b94452fcbefe6559b3da0fdd3de622ea50293 100644 (file)
@@ -603,6 +603,9 @@ cdef extern from "rbd/librbd.h" nogil:
     int rbd_mirror_image_demote(rbd_image_t image)
     int rbd_mirror_image_resync(rbd_image_t image)
     int rbd_mirror_image_create_snapshot(rbd_image_t image, uint64_t *snap_id)
+    int rbd_aio_mirror_image_create_snapshot(rbd_image_t image, uint32_t flags,
+                                             uint64_t *snap_id,
+                                             rbd_completion_t c)
     int rbd_mirror_image_get_info(rbd_image_t image,
                                   rbd_mirror_image_info_t *mirror_image_info,
                                   size_t info_size)
@@ -4831,8 +4834,6 @@ written." % (self.name, ret, length))
         """
         Create mirror snapshot.
 
-        :param force: ignore mirror snapshot limit
-        :type force: bool
         :returns: int - the snapshot Id
         """
         cdef:
@@ -4844,6 +4845,54 @@ written." % (self.name, ret, length))
                           self.name)
         return snap_id
 
+    @requires_not_closed
+    def aio_mirror_image_create_snapshot(self, flags, oncomplete):
+        """
+        Asynchronously create mirror snapshot.
+
+        Raises :class:`InvalidArgument` if the image is not in mirror
+        snapshot mode.
+
+        oncomplete will be called with the created snap ID as
+        well as the completion:
+
+        oncomplete(completion, snap_id)
+
+        :param flags: create snapshot flags
+        :type flags: int
+        :param oncomplete: what to do when the read is complete
+        :type oncomplete: completion
+        :returns: :class:`Completion` - the completion object
+        :raises: :class:`InvalidArgument`
+        """
+        cdef:
+            uint32_t _flags = flags
+            Completion completion
+
+        def oncomplete_(completion_v):
+            cdef Completion _completion_v = completion_v
+            return_value = _completion_v.get_return_value()
+            snap_id = <object>(<uint64_t *>_completion_v.buf)[0] \
+                if return_value >= 0 else None
+            return oncomplete(_completion_v, snap_id)
+
+        completion = self.__get_completion(oncomplete_)
+        completion.buf = PyBytes_FromStringAndSize(NULL, sizeof(uint64_t))
+        try:
+            completion.__persist()
+            with nogil:
+                ret = rbd_aio_mirror_image_create_snapshot(self.image, _flags,
+                                                           <uint64_t *>completion.buf,
+                                                           completion.rbd_comp)
+            if ret < 0:
+                raise make_ex(ret, 'error creating mirror snapshot for image %s' %
+                              self.name)
+        except:
+            completion.__unpersist()
+            raise
+
+        return completion
+
     @requires_not_closed
     def mirror_image_get_info(self):
         """
index 428466c16f80c05ad10bb58344d4810e9070c017..21910078737801c4fdaf8b12ad1e0d757e9ebee7 100644 (file)
@@ -2161,6 +2161,39 @@ class TestMirroring(object):
         self.rbd.mirror_peer_remove(ioctx, peer2_uuid)
         self.image.mirror_image_promote(False)
 
+    def test_aio_mirror_image_create_snapshot(self):
+        peer_uuid = self.rbd.mirror_peer_add(ioctx, "cluster", "client")
+        self.rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE)
+        self.image.mirror_image_disable(False)
+        self.image.mirror_image_enable(RBD_MIRROR_IMAGE_MODE_SNAPSHOT)
+
+        snaps = list(self.image.list_snaps())
+        eq(1, len(snaps))
+        snap = snaps[0]
+        eq(snap['namespace'], RBD_SNAP_NAMESPACE_TYPE_MIRROR)
+        eq(RBD_SNAP_MIRROR_STATE_PRIMARY, snap['mirror']['state'])
+
+        # this is a list so that the local cb() can modify it
+        snap_id = [None]
+        def cb(_, _snap_id):
+            snap_id[0] = _snap_id
+
+        comp = self.image.aio_mirror_image_create_snapshot(0, cb)
+        comp.wait_for_complete_and_cb()
+        assert_not_equal(snap_id[0], None)
+        eq(comp.get_return_value(), 0)
+        eq(sys.getrefcount(comp), 2)
+
+        snaps = list(self.image.list_snaps())
+        eq(2, len(snaps))
+        snap = snaps[1]
+        eq(snap['id'], snap_id[0])
+        eq(snap['namespace'], RBD_SNAP_NAMESPACE_TYPE_MIRROR)
+        eq(RBD_SNAP_MIRROR_STATE_PRIMARY, snap['mirror']['state'])
+        eq([peer_uuid], snap['mirror']['mirror_peer_uuids'])
+
+        self.rbd.mirror_peer_remove(ioctx, peer_uuid)
+
 class TestTrash(object):
 
     def setUp(self):