RBD: Fix issue with managing volume with type properties

Certain properties like multiattach, replication etc. were
not inherited by the volume when we manage it using a volume type.
This patch enables it by calling the ``_setup_volume`` method in
the manage workflow to apply the volume type properties to the
RBD image.

Closes-Bug: #2115985

Signed-off-by: Rajat Dhasmana <rajatdhasmana@gmail.com>
Change-Id: Ia58b12a48ff853c82a3fc0a9a3f8ad8a54e284f0
This commit is contained in:
Rajat Dhasmana
2025-07-04 13:59:58 +00:00
committed by whoami-rajat
parent 27373d61fe
commit dc8a59c918
3 changed files with 115 additions and 12 deletions

View File

@@ -294,6 +294,18 @@ class RBDTestCase(test.TestCase):
self.qos_policy_b = {"read_iops_sec": "500",
"write_iops_sec": "200"}
# For tests involving multiattach volume type
MULTIATTACH_FULL_FEATURES = (
driver.RBDDriver.RBD_FEATURE_LAYERING |
driver.RBDDriver.RBD_FEATURE_EXCLUSIVE_LOCK |
driver.RBDDriver.RBD_FEATURE_OBJECT_MAP |
driver.RBDDriver.RBD_FEATURE_FAST_DIFF |
driver.RBDDriver.RBD_FEATURE_JOURNALING)
MULTIATTACH_REDUCED_FEATURES = (
driver.RBDDriver.RBD_FEATURE_LAYERING |
driver.RBDDriver.RBD_FEATURE_EXCLUSIVE_LOCK)
@ddt.data({'cluster_name': None, 'pool_name': 'rbd'},
{'cluster_name': 'volumes', 'pool_name': None})
@ddt.unpack
@@ -737,6 +749,87 @@ class RBDTestCase(test.TestCase):
self.assertEqual([self.mock_rbd.ImageNotFound],
RAISED_EXCEPTIONS)
@common_mocks
def test_manage_existing_replicated_type(self):
client = self.mock_client.return_value
client.__enter__.return_value = client
self.volume_a.volume_type = fake_volume.fake_volume_type_obj(
self.context,
id=fake.VOLUME_TYPE_ID,
extra_specs={'replication_enabled': '<is> True'})
with mock.patch.object(self.driver.rbd.RBD(), 'rename') as \
mock_rbd_image_rename:
exist_volume = 'vol-exist'
existing_ref = {'source-name': exist_volume}
mock_rbd_image_rename.return_value = 0
res = self.driver.manage_existing(self.volume_a, existing_ref)
mock_rbd_image_rename.assert_called_with(
client.ioctx,
exist_volume,
self.volume_a.name)
self.assertEqual('enabled', res['replication_status'])
@common_mocks
def test_manage_existing_multiattach_type(self):
client = self.mock_client.return_value
client.__enter__.return_value = client
image = self.mock_proxy.return_value.__enter__.return_value
image_features = self.MULTIATTACH_FULL_FEATURES
image.features.return_value = image_features
expected_res = {
'provider_location': "{\"saved_features\":%s}" % image_features}
self.volume_a.volume_type = fake_volume.fake_volume_type_obj(
self.context,
id=fake.VOLUME_TYPE_ID,
extra_specs={'multiattach': '<is> True'})
with mock.patch.object(self.driver.rbd.RBD(), 'rename') as \
mock_rbd_image_rename:
exist_volume = 'vol-exist'
existing_ref = {'source-name': exist_volume}
mock_rbd_image_rename.return_value = 0
res = self.driver.manage_existing(self.volume_a, existing_ref)
mock_rbd_image_rename.assert_called_with(
client.ioctx,
exist_volume,
self.volume_a.name)
self.assertEqual(expected_res, res)
@common_mocks
def test_manage_existing_invalid_type(self):
client = self.mock_client.return_value
client.__enter__.return_value = client
# Replication and multiattach are mutually exclusive
extra_specs = {
'replication_enabled': '<is> True',
'multiattach': '<is> True'
}
self.volume_a.volume_type = fake_volume.fake_volume_type_obj(
self.context,
id=fake.VOLUME_TYPE_ID,
extra_specs=extra_specs)
with mock.patch.object(self.driver.rbd.RBD(), 'rename') as \
mock_rbd_image_rename:
exist_volume = 'vol-exist'
existing_ref = {'source-name': exist_volume}
mock_rbd_image_rename.return_value = 0
res = self.assertRaises(
exception.ManageExistingVolumeTypeMismatch,
self.driver.manage_existing, self.volume_a, existing_ref)
self.assertIn(
"Manage existing volume failed due to volume type mismatch",
str(res))
self.assertIn(
"Replication and Multiattach are mutually exclusive.",
str(res))
# Ensure rename is not called
mock_rbd_image_rename.assert_not_called()
@common_mocks
@mock.patch.object(driver.RBDDriver, '_get_image_status')
def test_get_manageable_volumes(self, mock_get_image_status):
@@ -3439,17 +3532,6 @@ class RBDTestCase(test.TestCase):
self.driver.RBD_FEATURE_EXCLUSIVE_LOCK,
self.driver.MULTIATTACH_EXCLUSIONS)
MULTIATTACH_FULL_FEATURES = (
driver.RBDDriver.RBD_FEATURE_LAYERING |
driver.RBDDriver.RBD_FEATURE_EXCLUSIVE_LOCK |
driver.RBDDriver.RBD_FEATURE_OBJECT_MAP |
driver.RBDDriver.RBD_FEATURE_FAST_DIFF |
driver.RBDDriver.RBD_FEATURE_JOURNALING)
MULTIATTACH_REDUCED_FEATURES = (
driver.RBDDriver.RBD_FEATURE_LAYERING |
driver.RBDDriver.RBD_FEATURE_EXCLUSIVE_LOCK)
@ddt.data(MULTIATTACH_FULL_FEATURES, MULTIATTACH_REDUCED_FEATURES)
@common_mocks
def test_enable_multiattach(self, features):

View File

@@ -2141,8 +2141,17 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
LOG.debug("Extend volume from %(old_size)s GB to %(new_size)s GB.",
{'old_size': old_size, 'new_size': new_size})
def _is_valid_type(self, volume_type):
want_replication = self._is_replicated_type(volume_type)
want_multiattach = self._is_multiattach_type(volume_type)
if want_replication and want_multiattach:
return False
return True
def manage_existing(self,
volume: Volume, existing_ref: dict[str, str]) -> None:
volume: Volume,
existing_ref: dict[str, str]) -> dict[str, Any]:
"""Manages an existing image.
Renames the image name to match the expected name for the volume.
@@ -2154,12 +2163,17 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
existing_ref is a dictionary of the form:
{'source-name': <name of RBD image>}
"""
# check if the volume type is valid and fail fast if not
if not self._is_valid_type(volume.volume_type):
msg = _('Replication and Multiattach are mutually exclusive.')
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
# Raise an exception if we didn't find a suitable rbd image.
with RADOSClient(self) as client:
rbd_name = existing_ref['source-name']
self.RBDProxy().rename(client.ioctx,
utils.convert_str(rbd_name),
volume.name)
return self._setup_volume(volume)
def manage_existing_get_size(self,
volume: Volume,

View File

@@ -0,0 +1,7 @@
---
fixes:
- |
RBD `bug #2115985
<https://bugs.launchpad.net/cinder/+bug/2115985>`_: Fixed
issue when managing a volume with ``multiattach`` or
``replication_enabled`` properties in volume type.