Skip to content

Commit

Permalink
pybind/rbd: expose RBD_IMAGE_OPTION_FLATTEN option
Browse files Browse the repository at this point in the history
It takes effect with deep_copy() and migration_prepare().

Fixes: https://tracker.ceph.com/issues/65624
Signed-off-by: Ilya Dryomov <[email protected]>
  • Loading branch information
idryomov committed May 6, 2024
1 parent 39fafe7 commit 39f207f
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 2 deletions.
2 changes: 2 additions & 0 deletions PendingReleaseNotes
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ CephFS: Disallow delegating preallocated inode ranges to clients. Config
* RBD: `RBD_IMAGE_OPTION_CLONE_FORMAT` option has been exposed in Python
bindings via `clone_format` optional parameter to `clone`, `deep_copy` and
`migration_prepare` methods.
* RBD: `RBD_IMAGE_OPTION_FLATTEN` option has been exposed in Python bindings via
`flatten` optional parameter to `deep_copy` and `migration_prepare` methods.

>=18.0.0

Expand Down
1 change: 1 addition & 0 deletions src/pybind/rbd/c_rbd.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ cdef extern from "rbd/librbd.h" nogil:
_RBD_IMAGE_OPTION_STRIPE_UNIT "RBD_IMAGE_OPTION_STRIPE_UNIT"
_RBD_IMAGE_OPTION_STRIPE_COUNT "RBD_IMAGE_OPTION_STRIPE_COUNT"
_RBD_IMAGE_OPTION_DATA_POOL "RBD_IMAGE_OPTION_DATA_POOL"
_RBD_IMAGE_OPTION_FLATTEN "RBD_IMAGE_OPTION_FLATTEN"
_RBD_IMAGE_OPTION_CLONE_FORMAT "RBD_IMAGE_OPTION_CLONE_FORMAT"

RBD_MAX_BLOCK_NAME_SIZE
Expand Down
1 change: 1 addition & 0 deletions src/pybind/rbd/mock_rbd.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ cdef nogil:
_RBD_IMAGE_OPTION_STRIPE_UNIT "RBD_IMAGE_OPTION_STRIPE_UNIT"
_RBD_IMAGE_OPTION_STRIPE_COUNT "RBD_IMAGE_OPTION_STRIPE_COUNT"
_RBD_IMAGE_OPTION_DATA_POOL "RBD_IMAGE_OPTION_DATA_POOL"
_RBD_IMAGE_OPTION_FLATTEN "RBD_IMAGE_OPTION_FLATTEN"
_RBD_IMAGE_OPTION_CLONE_FORMAT "RBD_IMAGE_OPTION_CLONE_FORMAT"

RBD_MAX_BLOCK_NAME_SIZE
Expand Down
13 changes: 11 additions & 2 deletions src/pybind/rbd/rbd.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ RBD_IMAGE_OPTION_ORDER = _RBD_IMAGE_OPTION_ORDER
RBD_IMAGE_OPTION_STRIPE_UNIT = _RBD_IMAGE_OPTION_STRIPE_UNIT
RBD_IMAGE_OPTION_STRIPE_COUNT = _RBD_IMAGE_OPTION_STRIPE_COUNT
RBD_IMAGE_OPTION_DATA_POOL = _RBD_IMAGE_OPTION_DATA_POOL
RBD_IMAGE_OPTION_FLATTEN = _RBD_IMAGE_OPTION_FLATTEN
RBD_IMAGE_OPTION_CLONE_FORMAT = _RBD_IMAGE_OPTION_CLONE_FORMAT

RBD_SNAP_NAMESPACE_TYPE_USER = _RBD_SNAP_NAMESPACE_TYPE_USER
Expand Down Expand Up @@ -962,7 +963,7 @@ class RBD(object):

def migration_prepare(self, ioctx, image_name, dest_ioctx, dest_image_name,
features=None, order=None, stripe_unit=None, stripe_count=None,
data_pool=None, clone_format=None):
data_pool=None, clone_format=None, flatten=False):
"""
Prepare an RBD image migration.
Expand All @@ -987,6 +988,9 @@ class RBD(object):
:param clone_format: if the source image is a clone, which clone format
to use for the destination image
:type clone_format: int
:param flatten: if the source image is a clone, whether to flatten the
destination image or make it a clone of the same parent
:type flatten: bool
:raises: :class:`TypeError`
:raises: :class:`InvalidArgument`
:raises: :class:`ImageExists`
Expand Down Expand Up @@ -1022,6 +1026,7 @@ class RBD(object):
if clone_format is not None:
rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_CLONE_FORMAT,
clone_format)
rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FLATTEN, flatten)
with nogil:
ret = rbd_migration_prepare(_ioctx, _image_name, _dest_ioctx,
_dest_image_name, opts)
Expand Down Expand Up @@ -3451,7 +3456,7 @@ cdef class Image(object):
@requires_not_closed
def deep_copy(self, dest_ioctx, dest_name, features=None, order=None,
stripe_unit=None, stripe_count=None, data_pool=None,
clone_format=None):
clone_format=None, flatten=False):
"""
Deep copy the image to another location.
Expand All @@ -3472,6 +3477,9 @@ cdef class Image(object):
:param clone_format: if the source image is a clone, which clone format
to use for the destination image
:type clone_format: int
:param flatten: if the source image is a clone, whether to flatten the
destination image or make it a clone of the same parent
:type flatten: bool
:raises: :class:`TypeError`
:raises: :class:`InvalidArgument`
:raises: :class:`ImageExists`
Expand Down Expand Up @@ -3505,6 +3513,7 @@ cdef class Image(object):
if clone_format is not None:
rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_CLONE_FORMAT,
clone_format)
rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FLATTEN, flatten)
with nogil:
ret = rbd_deep_copy(self.image, _dest_ioctx, _dest_name, opts)
finally:
Expand Down
63 changes: 63 additions & 0 deletions src/test/pybind/test_rbd.py
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,66 @@ def test_deep_copy_clone_v2_to_v2(self):
self.rbd.remove(ioctx, clone_name)
self.image.remove_snap('snap1')

@require_features([RBD_FEATURE_LAYERING])
def test_deep_copy_clone_v1_flatten(self):
self.image.write(b'a' * 256, 0)
self.image.create_snap('snap1')
self.image.write(b'b' * 256, 0)
self.image.protect_snap('snap1')
clone_name = get_temp_image_name()
dst_name = get_temp_image_name()
self.rbd.clone(ioctx, image_name, 'snap1', ioctx, clone_name, features,
clone_format=1)
with Image(ioctx, clone_name) as child:
eq(0, child.op_features())
child.create_snap('snap1')
child.deep_copy(ioctx, dst_name, features=features,
order=self.image.stat()['order'],
stripe_unit=self.image.stripe_unit(),
stripe_count=self.image.stripe_count(),
flatten=True)
child.remove_snap('snap1')

with Image(ioctx, dst_name) as copy:
copy_data = copy.read(0, 256)
eq(b'a' * 256, copy_data)
assert_raises(ImageNotFound, copy.parent_id)
eq(0, copy.op_features())
copy.remove_snap('snap1')
self.rbd.remove(ioctx, dst_name)
self.rbd.remove(ioctx, clone_name)
self.image.unprotect_snap('snap1')
self.image.remove_snap('snap1')

@require_features([RBD_FEATURE_LAYERING])
def test_deep_copy_clone_v2_flatten(self):
self.image.write(b'a' * 256, 0)
self.image.create_snap('snap1')
self.image.write(b'b' * 256, 0)
clone_name = get_temp_image_name()
dst_name = get_temp_image_name()
self.rbd.clone(ioctx, image_name, 'snap1', ioctx, clone_name, features,
clone_format=2)
with Image(ioctx, clone_name) as child:
eq(RBD_OPERATION_FEATURE_CLONE_CHILD, child.op_features())
child.create_snap('snap1')
child.deep_copy(ioctx, dst_name, features=features,
order=self.image.stat()['order'],
stripe_unit=self.image.stripe_unit(),
stripe_count=self.image.stripe_count(),
flatten=True)
child.remove_snap('snap1')

with Image(ioctx, dst_name) as copy:
copy_data = copy.read(0, 256)
eq(b'a' * 256, copy_data)
assert_raises(ImageNotFound, copy.parent_id)
eq(0, copy.op_features())
copy.remove_snap('snap1')
self.rbd.remove(ioctx, dst_name)
self.rbd.remove(ioctx, clone_name)
self.image.remove_snap('snap1')

def test_create_snap(self):
global ioctx
self.image.create_snap('snap1')
Expand Down Expand Up @@ -2975,6 +3035,9 @@ def test_migration_clone_v2_to_v2(self):
image.remove_snap('snap1')
remove_image()

# TODO: add test_migration_clone_v{1,2}_flatten tests once
# https://tracker.ceph.com/issues/65743 is addressed

def test_migration_import(self):
create_image()
with Image(ioctx, image_name) as image:
Expand Down

0 comments on commit 39f207f

Please sign in to comment.