diff --git a/cinder/tests/unit/volume/drivers/test_rbd.py b/cinder/tests/unit/volume/drivers/test_rbd.py index d1cb000fd98..306be7c841e 100644 --- a/cinder/tests/unit/volume/drivers/test_rbd.py +++ b/cinder/tests/unit/volume/drivers/test_rbd.py @@ -888,13 +888,13 @@ class RBDTestCase(test.TestCase): self.mock_proxy().__enter__().volume.op_features.return_value = 1 self.mock_rbd.RBD_OPERATION_FEATURE_CLONE_PARENT = 1 - snapshot = mock.Mock() self.cfg.rbd_flatten_volume_from_snapshot = False with mock.patch.object(driver, 'LOG') as \ mock_log: - self.driver.create_volume_from_snapshot(self.volume_a, snapshot) + self.driver.create_volume_from_snapshot(self.volume_a, + self.snapshot) mock_log.info.assert_called_with('Using v2 Clone API') @@ -910,13 +910,13 @@ class RBDTestCase(test.TestCase): self.mock_proxy().__enter__().volume.op_features.return_value = 0 self.mock_rbd.RBD_OPERATION_FEATURE_CLONE_PARENT = 1 - snapshot = mock.Mock() self.cfg.rbd_flatten_volume_from_snapshot = False with mock.patch.object(driver, 'LOG') as \ mock_log: - self.driver.create_volume_from_snapshot(self.volume_a, snapshot) + self.driver.create_volume_from_snapshot(self.volume_a, + self.snapshot) self.assertTrue(any(m for m in mock_log.warning.call_args_list if 'Not using v2 clone API' in m[0][0])) @@ -1859,7 +1859,7 @@ class RBDTestCase(test.TestCase): @mock.patch.object(driver.RBDDriver, '_resize', mock.Mock()) def test_create_vol_from_snap_replication(self, mock_clone): self.cfg.rbd_flatten_volume_from_snapshot = False - snapshot = mock.Mock() + snapshot = self.snapshot_b res = self.driver.create_volume_from_snapshot(self.volume_a, snapshot) @@ -1869,6 +1869,75 @@ class RBDTestCase(test.TestCase): snapshot.volume_name, snapshot.name) + @common_mocks + @mock.patch.object(driver.RBDDriver, '_clone', + return_value=mock.sentinel.volume_update) + def test_create_encrypted_vol_from_snap_same_size(self, mock_clone): + """Test create encrypted volume from encrypted snapshot. + + When creating an encrypted volume from encrypted snapshot + the new volume is same size than the snapshot. + """ + self.cfg.rbd_flatten_volume_from_snapshot = False + volume_size = self.volume_c.size + self.snapshot_b.volume_size = volume_size + + mock_resize = self.mock_object(self.driver, '_resize') + mock_new_size = self.mock_object(self.driver, + '_calculate_new_size') + + res = self.driver.create_volume_from_snapshot(self.volume_c, + self.snapshot_b) + self.assertEqual(mock.sentinel.volume_update, res) + mock_resize.assert_not_called() + mock_new_size.assert_not_called() + + @common_mocks + @mock.patch.object(driver.RBDDriver, '_clone', + return_value=mock.sentinel.volume_update) + def test_create_encrypted_vol_from_snap(self, mock_clone): + """Test create encrypted volume from encrypted snapshot. + + When creating an encrypted volume from encrypted snapshot + the new volume is larger than the snapshot (12GB vs 11GB). + """ + self.cfg.rbd_flatten_volume_from_snapshot = False + new_size_bytes = 12288 + diff_size = 1 + volume_size = 11 + self.snapshot_b.volume_size = volume_size + + mock_resize = self.mock_object(self.driver, '_resize') + mock_new_size = self.mock_object(self.driver, + '_calculate_new_size') + + mock_new_size.return_value = new_size_bytes + res = self.driver.create_volume_from_snapshot(self.volume_c, + self.snapshot_b) + self.assertEqual(mock.sentinel.volume_update, res) + mock_resize.assert_called_once_with(self.volume_c, + size=new_size_bytes) + volume_name = self.volume_c.name + mock_new_size.assert_called_once_with(diff_size, + volume_name) + + @common_mocks + @mock.patch.object(driver.RBDDriver, '_clone', + return_value=mock.sentinel.volume_update) + def test_create_unencrypted_vol_from_snap(self, mock_clone): + """Test create regular volume from regular snapshot""" + + self.cfg.rbd_flatten_volume_from_snapshot = False + self.snapshot_b.volume.size = 9 + mock_resize = self.mock_object(self.driver, '_resize') + mock_new_size = self.mock_object(self.driver, + '_calculate_new_size') + res = self.driver.create_volume_from_snapshot(self.volume_b, + self.snapshot_b) + self.assertEqual(mock.sentinel.volume_update, res) + mock_resize.assert_called_once_with(self.volume_b, size=None) + mock_new_size.assert_not_called() + @common_mocks def test_extend_volume(self): fake_size = '20' diff --git a/cinder/volume/drivers/rbd.py b/cinder/volume/drivers/rbd.py index 1eee30032b1..13129e03bf9 100644 --- a/cinder/volume/drivers/rbd.py +++ b/cinder/volume/drivers/rbd.py @@ -1041,14 +1041,36 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD, with RBDVolumeProxy(self, volume.name) as vol: vol.resize(size) + def _calculate_new_size(self, size_diff, volume_name): + with RBDVolumeProxy(self, volume_name) as vol: + current_size_bytes = vol.volume.size() + size_diff_bytes = size_diff * units.Gi + new_size_bytes = current_size_bytes + size_diff_bytes + return new_size_bytes + def create_volume_from_snapshot(self, volume, snapshot): """Creates a volume from a snapshot.""" volume_update = self._clone(volume, self.configuration.rbd_pool, snapshot.volume_name, snapshot.name) if self.configuration.rbd_flatten_volume_from_snapshot: self._flatten(self.configuration.rbd_pool, volume.name) - if int(volume.size): - self._resize(volume) + + snap_vol_size = snapshot.volume_size + # In case the destination size is bigger than the snapshot size + # we should resize. In particular when the destination volume + # is encrypted we should consider the encryption header size. + # Because of this, we need to calculate the difference size to + # provide the size that the user is expecting. + # Otherwise if the destination volume size is equal to the + # source volume size we don't perform a resize. + if volume.size > snap_vol_size: + new_size = None + # In case the volume is encrypted we need to consider the + # size of the encryption header when resizing the volume + if volume.encryption_key_id: + size_diff = volume.size - snap_vol_size + new_size = self._calculate_new_size(size_diff, volume.name) + self._resize(volume, size=new_size) self._show_msg_check_clone_v2_api(snapshot.volume_name) return volume_update diff --git a/releasenotes/notes/bug-1922408-create-encryption-volume-from-snapshot-skip-resize-bb5d77c5e912b5c1.yaml b/releasenotes/notes/bug-1922408-create-encryption-volume-from-snapshot-skip-resize-bb5d77c5e912b5c1.yaml new file mode 100644 index 00000000000..503dcfd2b99 --- /dev/null +++ b/releasenotes/notes/bug-1922408-create-encryption-volume-from-snapshot-skip-resize-bb5d77c5e912b5c1.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + RBD driver `Bug #1922408 + `_: + Fixed create encrypted volume from encrypted snapshot.