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"
_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)
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)
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)
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)
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):
"""
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
: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`
"""
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')
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.
: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')
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')
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.
: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.
: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.
: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')
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)
# vim: expandtab smarttab shiftwidth=4 softtabstop=4
+import errno
import functools
import socket
import os
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()
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')
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:
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,
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()