From: Mykola Golub Date: Wed, 21 Oct 2020 12:38:31 +0000 (+0100) Subject: pybind/rbd: async API for creating mirror snapshots X-Git-Tag: v15.2.10~36^2~6 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=6f8780f2686eea7a3d23a8809c62f35bf7cfe88d;p=ceph.git pybind/rbd: async API for creating mirror snapshots Signed-off-by: Mykola Golub (cherry picked from commit d1571ed2743f97280a2f3a2a70fff59e0cafc0b9) Conflicts: src/pybind/rbd/rbd.pyx: trival resolution re: quiesce flags --- diff --git a/src/pybind/rbd/rbd.pyx b/src/pybind/rbd/rbd.pyx index 70d032b478913..be4b94452fcbe 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -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 = (_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, + 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): """ diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index 428466c16f80c..2191007873780 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -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):