]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
pybind/rbd: flatten, remove, trash_remove, migration progress callback
authorJason Dillaman <dillaman@redhat.com>
Mon, 15 Jul 2019 21:35:37 +0000 (17:35 -0400)
committerJason Dillaman <dillaman@redhat.com>
Sun, 18 Aug 2019 20:47:06 +0000 (16:47 -0400)
This callback can be used to track progress and also to attempt to cancel
the operation while it's in-progress by returning a negative error code
from the callback.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
(cherry picked from commit 6dc8249c7ba2553acb686a2462de93239f1f07b4)

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

index 993f4b86a2e687085b93f05f6b0a2d4a6e3f4ba5..7db18d9d23c14e5dfcb6869e551852fbb154a921 100644 (file)
@@ -53,6 +53,9 @@ cdef extern from "rados/librados.h":
     enum:
         _LIBRADOS_SNAP_HEAD "LIBRADOS_SNAP_HEAD"
 
+cdef extern from "rbd/librbd.h":
+    ctypedef int (*librbd_progress_fn_t)(uint64_t offset, uint64_t total, void* ptr)
+
 cdef extern from "rbd/librbd.h" nogil:
     enum:
         _RBD_FEATURE_LAYERING "RBD_FEATURE_LAYERING"
@@ -261,7 +264,6 @@ cdef extern from "rbd/librbd.h" nogil:
         _RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS "RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS"
 
     ctypedef void (*rbd_callback_t)(rbd_completion_t cb, void *arg)
-    ctypedef int (*librbd_progress_fn_t)(uint64_t offset, uint64_t total, void* ptr)
 
     void rbd_version(int *major, int *minor, int *extra)
 
@@ -295,7 +297,8 @@ cdef extern from "rbd/librbd.h" nogil:
     int rbd_clone3(rados_ioctx_t p_ioctx, const char *p_name,
                    const char *p_snapname, rados_ioctx_t c_ioctx,
                    const char *c_name, rbd_image_options_t c_opts)
-    int rbd_remove(rados_ioctx_t io, const char *name)
+    int rbd_remove_with_progress(rados_ioctx_t io, const char *name,
+                                 librbd_progress_fn_t cb, void *cbdata)
     int rbd_rename(rados_ioctx_t src_io_ctx, const char *srcname,
                    const char *destname)
 
@@ -308,15 +311,26 @@ cdef extern from "rbd/librbd.h" nogil:
     void rbd_trash_list_cleanup(rbd_trash_image_info_t *trash_entries,
                                 size_t num_entries)
     int rbd_trash_purge(rados_ioctx_t io, time_t expire_ts, float threshold)
-    int rbd_trash_remove(rados_ioctx_t io, const char *id, int force)
+    int rbd_trash_remove_with_progress(rados_ioctx_t io, const char *id,
+                                       int force, librbd_progress_fn_t cb,
+                                       void *cbdata)
     int rbd_trash_restore(rados_ioctx_t io, const char *id, const char *name)
 
     int rbd_migration_prepare(rados_ioctx_t io_ctx, const char *image_name,
-                              rados_ioctx_t dest_io_ctx, const char *dest_image_name,
+                              rados_ioctx_t dest_io_ctx,
+                              const char *dest_image_name,
                               rbd_image_options_t opts)
-    int rbd_migration_execute(rados_ioctx_t io_ctx, const char *image_name)
-    int rbd_migration_commit(rados_ioctx_t io_ctx, const char *image_name)
-    int rbd_migration_abort(rados_ioctx_t io_ctx, const char *image_name)
+    int rbd_migration_execute_with_progress(rados_ioctx_t io_ctx,
+                                            const char *image_name,
+                                            librbd_progress_fn_t cb,
+                                            void *cbdata)
+    int rbd_migration_commit_with_progress(rados_ioctx_t io_ctx,
+                                           const char *image_name,
+                                           librbd_progress_fn_t cb,
+                                           void *cbdata)
+    int rbd_migration_abort_with_progress(rados_ioctx_t io_ctx,
+                                          const char *image_name,
+                                          librbd_progress_fn_t cb, void *cbdata)
     int rbd_migration_status(rados_ioctx_t io_ctx, const char *image_name,
                              rbd_image_migration_status_t *status,
                              size_t status_size)
@@ -452,7 +466,8 @@ cdef extern from "rbd/librbd.h" nogil:
     int rbd_snap_get_trash_namespace(rbd_image_t image, uint64_t snap_id,
                                      char *original_name, size_t max_length)
 
-    int rbd_flatten(rbd_image_t image)
+    int rbd_flatten_with_progress(rbd_image_t image, librbd_progress_fn_t cb,
+                                  void *cbdata)
     int rbd_sparsify(rbd_image_t image, size_t sparse_size)
     int rbd_rebuild_object_map(rbd_image_t image, librbd_progress_fn_t cb,
                                void *cbdata)
@@ -821,7 +836,10 @@ cdef make_ex(ret, msg, exception_map=errno_to_exception):
 cdef rados_ioctx_t convert_ioctx(rados.Ioctx ioctx) except? NULL:
     return <rados_ioctx_t>ioctx.io
 
-cdef int no_op_progress_callback(uint64_t offset, uint64_t total, void* ptr) nogil:
+cdef int progress_callback(uint64_t offset, uint64_t total, void* ptr) with gil:
+    return (<object>ptr)(offset, total)
+
+cdef int no_op_progress_callback(uint64_t offset, uint64_t total, void* ptr):
     return 0
 
 def cstr(val, name, encoding="utf-8", opt=False):
@@ -1183,7 +1201,7 @@ class RBD(object):
         """
         return ImageIterator(ioctx)
 
-    def remove(self, ioctx, name):
+    def remove(self, ioctx, name, on_progress=None):
         """
         Delete an RBD image. This may take a long time, since it does
         not return until every object that comprises the image has
@@ -1197,6 +1215,8 @@ class RBD(object):
         :type ioctx: :class:`rados.Ioctx`
         :param name: the name of the image to remove
         :type name: str
+        :param on_progress: optional progress callback function
+        :type on_progress: callback function
         :raises: :class:`ImageNotFound`, :class:`ImageBusy`,
                  :class:`ImageHasSnapshots`
         """
@@ -1204,8 +1224,13 @@ class RBD(object):
         cdef:
             rados_ioctx_t _ioctx = convert_ioctx(ioctx)
             char *_name = name
+            librbd_progress_fn_t _prog_cb = &no_op_progress_callback
+            void *_prog_arg = NULL
+        if on_progress:
+            _prog_cb = &progress_callback
+            _prog_arg = <void *>on_progress
         with nogil:
-            ret = rbd_remove(_ioctx, _name)
+            ret = rbd_remove_with_progress(_ioctx, _name, _prog_cb, _prog_arg)
         if ret != 0:
             raise make_ex(ret, 'error removing image')
 
@@ -1287,7 +1312,7 @@ class RBD(object):
         if ret != 0:
             raise make_ex(ret, 'error purging images from trash')
 
-    def trash_remove(self, ioctx, image_id, force=False):
+    def trash_remove(self, ioctx, image_id, force=False, on_progress=None):
         """
         Delete an RBD image from trash. If image deferment time has not
         expired :class:`PermissionError` is raised.
@@ -1298,6 +1323,8 @@ class RBD(object):
         :type image_id: str
         :param force: force remove even if deferment time has not expired
         :type force: bool
+        :param on_progress: optional progress callback function
+        :type on_progress: callback function
         :raises: :class:`ImageNotFound`, :class:`PermissionError`
         """
         image_id = cstr(image_id, 'image_id')
@@ -1305,8 +1332,14 @@ class RBD(object):
             rados_ioctx_t _ioctx = convert_ioctx(ioctx)
             char *_image_id = image_id
             int _force = force
+            librbd_progress_fn_t _prog_cb = &no_op_progress_callback
+            void *_prog_arg = NULL
+        if on_progress:
+            _prog_cb = &progress_callback
+            _prog_arg = <void *>on_progress
         with nogil:
-            ret = rbd_trash_remove(_ioctx, _image_id, _force)
+            ret = rbd_trash_remove_with_progress(_ioctx, _image_id, _force,
+                                                 _prog_cb, _prog_arg)
         if ret != 0:
             raise make_ex(ret, 'error deleting image from trash')
 
@@ -1451,7 +1484,7 @@ class RBD(object):
         if ret < 0:
             raise make_ex(ret, 'error migrating image %s' % (image_name))
 
-    def migration_execute(self, ioctx, image_name):
+    def migration_execute(self, ioctx, image_name, on_progress=None):
         """
         Execute a prepared RBD image migration.
 
@@ -1459,18 +1492,26 @@ class RBD(object):
         :type ioctx: :class:`rados.Ioctx`
         :param image_name: the name of the image
         :type image_name: str
+        :param on_progress: optional progress callback function
+        :type on_progress: callback function
         :raises: :class:`ImageNotFound`
         """
         image_name = cstr(image_name, 'image_name')
         cdef:
             rados_ioctx_t _ioctx = convert_ioctx(ioctx)
             char *_image_name = image_name
+            librbd_progress_fn_t _prog_cb = &no_op_progress_callback
+            void *_prog_arg = NULL
+        if on_progress:
+            _prog_cb = &progress_callback
+            _prog_arg = <void *>on_progress
         with nogil:
-            ret = rbd_migration_execute(_ioctx, _image_name)
+            ret = rbd_migration_execute_with_progress(_ioctx, _image_name,
+                                                      _prog_cb, _prog_arg)
         if ret != 0:
             raise make_ex(ret, 'error aborting migration')
 
-    def migration_commit(self, ioctx, image_name):
+    def migration_commit(self, ioctx, image_name, on_progress=None):
         """
         Commit an executed RBD image migration.
 
@@ -1478,18 +1519,26 @@ class RBD(object):
         :type ioctx: :class:`rados.Ioctx`
         :param image_name: the name of the image
         :type image_name: str
+        :param on_progress: optional progress callback function
+        :type on_progress: callback function
         :raises: :class:`ImageNotFound`
         """
         image_name = cstr(image_name, 'image_name')
         cdef:
             rados_ioctx_t _ioctx = convert_ioctx(ioctx)
             char *_image_name = image_name
+            librbd_progress_fn_t _prog_cb = &no_op_progress_callback
+            void *_prog_arg = NULL
+        if on_progress:
+            _prog_cb = &progress_callback
+            _prog_arg = <void *>on_progress
         with nogil:
-            ret = rbd_migration_commit(_ioctx, _image_name)
+            ret = rbd_migration_commit_with_progress(_ioctx, _image_name,
+                                                     _prog_cb, _prog_arg)
         if ret != 0:
             raise make_ex(ret, 'error aborting migration')
 
-    def migration_abort(self, ioctx, image_name):
+    def migration_abort(self, ioctx, image_name, on_progress=None):
         """
         Cancel a previously started but interrupted migration.
 
@@ -1497,14 +1546,22 @@ class RBD(object):
         :type ioctx: :class:`rados.Ioctx`
         :param image_name: the name of the image
         :type image_name: str
+        :param on_progress: optional progress callback function
+        :type on_progress: callback function
         :raises: :class:`ImageNotFound`
         """
         image_name = cstr(image_name, 'image_name')
         cdef:
             rados_ioctx_t _ioctx = convert_ioctx(ioctx)
             char *_image_name = image_name
+            librbd_progress_fn_t _prog_cb = &no_op_progress_callback
+            void *_prog_arg = NULL
+        if on_progress:
+            _prog_cb = &progress_callback
+            _prog_arg = <void *>on_progress
         with nogil:
-            ret = rbd_migration_abort(_ioctx, _image_name)
+            ret = rbd_migration_abort_with_progress(_ioctx, _image_name,
+                                                    _prog_cb, _prog_arg)
         if ret != 0:
             raise make_ex(ret, 'error aborting migration')
 
@@ -3725,12 +3782,20 @@ written." % (self.name, ret, length))
             raise make_ex(ret, 'error getting modify timestamp for image: %s' % (self.name))
         return datetime.fromtimestamp(timestamp.tv_sec)
 
-    def flatten(self):
+    def flatten(self, on_progress=None):
         """
         Flatten clone image (copy all blocks from parent to child)
+        :param on_progress: optional progress callback function
+        :type on_progress: callback function
         """
+        cdef:
+            librbd_progress_fn_t _prog_cb = &no_op_progress_callback
+            void *_prog_arg = NULL
+        if on_progress:
+            _prog_cb = &progress_callback
+            _prog_arg = <void *>on_progress
         with nogil:
-            ret = rbd_flatten(self.image)
+            ret = rbd_flatten_with_progress(self.image, _prog_cb, _prog_arg)
         if ret < 0:
             raise make_ex(ret, "error flattening %s" % self.name)
 
index 1035ae319db510d330b9a159000035955c757950..f18918a3f114a2858ab5ed2836d83ab0b5db36f3 100644 (file)
@@ -1,4 +1,5 @@
 # vim: expandtab smarttab shiftwidth=4 softtabstop=4
+import errno
 import functools
 import socket
 import os
@@ -324,6 +325,24 @@ def test_list():
         image_id = image.id()
     eq([{'id': image_id, 'name': image_name}], list(RBD().list2(ioctx)))
 
+@with_setup(create_image)
+def test_remove_with_progress():
+    d = {'received_callback': False}
+    def progress_cb(current, total):
+        d['received_callback'] = True
+        return 0
+
+    RBD().remove(ioctx, image_name, on_progress=progress_cb)
+    eq(True, d['received_callback'])
+
+@with_setup(create_image)
+def test_remove_canceled():
+    def progress_cb(current, total):
+        return -errno.ESHUTDOWN
+
+    assert_raises(ConnectionShutdown, RBD().remove, ioctx, image_name,
+                  on_progress=progress_cb)
+
 @with_setup(create_image, remove_image)
 def test_rename():
     rbd = RBD()
@@ -1519,6 +1538,22 @@ class TestClone(object):
         self.clone.remove_snap('snap2')
         self.rbd.remove(ioctx, clone_name3)
 
+    def test_flatten_with_progress(self):
+        d = {'received_callback': False}
+        def progress_cb(current, total):
+            d['received_callback'] = True
+            return 0
+
+        global ioctx
+        global features
+        clone_name = get_temp_image_name()
+        self.rbd.clone(ioctx, image_name, 'snap1', ioctx, clone_name,
+                       features, 0)
+        with Image(ioctx, clone_name) as clone:
+            clone.flatten(on_progress=progress_cb)
+        self.rbd.remove(ioctx, clone_name)
+        eq(True, d['received_callback'])
+
     def test_resize_flatten_multi_level(self):
         self.clone.create_snap('snap2')
         self.clone.protect_snap('snap2')
@@ -1919,6 +1954,20 @@ class TestTrash(object):
         RBD().trash_move(ioctx, image_name, 0)
         RBD().trash_remove(ioctx, image_id)
 
+    def test_remove_with_progress(self):
+        d = {'received_callback': False}
+        def progress_cb(current, total):
+            d['received_callback'] = True
+            return 0
+
+        create_image()
+        with Image(ioctx, image_name) as image:
+            image_id = image.id()
+
+        RBD().trash_move(ioctx, image_name, 0)
+        RBD().trash_remove(ioctx, image_id, on_progress=progress_cb)
+        eq(True, d['received_callback'])
+
     def test_get(self):
         create_image()
         with Image(ioctx, image_name) as image:
@@ -2165,6 +2214,24 @@ class TestMigration(object):
         RBD().migration_commit(ioctx, image_name)
         remove_image()
 
+    def test_migration_with_progress(self):
+        d = {'received_callback': False}
+        def progress_cb(current, total):
+            d['received_callback'] = True
+            return 0
+
+        create_image()
+        RBD().migration_prepare(ioctx, image_name, ioctx, image_name, features=63,
+                                order=23, stripe_unit=1<<23, stripe_count=1,
+                                data_pool=None)
+        RBD().migration_execute(ioctx, image_name, on_progress=progress_cb)
+        eq(True, d['received_callback'])
+        d['received_callback'] = False
+
+        RBD().migration_commit(ioctx, image_name, on_progress=progress_cb)
+        eq(True, d['received_callback'])
+        remove_image()
+
     def test_migrate_abort(self):
         create_image()
         RBD().migration_prepare(ioctx, image_name, ioctx, image_name, features=63,
@@ -2172,3 +2239,17 @@ class TestMigration(object):
                                 data_pool=None)
         RBD().migration_abort(ioctx, image_name)
         remove_image()
+
+    def test_migrate_abort_with_progress(self):
+        d = {'received_callback': False}
+        def progress_cb(current, total):
+            d['received_callback'] = True
+            return 0
+
+        create_image()
+        RBD().migration_prepare(ioctx, image_name, ioctx, image_name, features=63,
+                                order=23, stripe_unit=1<<23, stripe_count=1,
+                                data_pool=None)
+        RBD().migration_abort(ioctx, image_name, on_progress=progress_cb)
+        eq(True, d['received_callback'])
+        remove_image()