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
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.
: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`
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)
@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.
: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`
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:
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')
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: