diff --git a/nova/tests/unit/virt/test_block_device.py b/nova/tests/unit/virt/test_block_device.py index 703f15967cba..3973b7fb5f40 100644 --- a/nova/tests/unit/virt/test_block_device.py +++ b/nova/tests/unit/virt/test_block_device.py @@ -15,6 +15,7 @@ from os_brick import encryptors from unittest import mock +import ddt from oslo_serialization import jsonutils from oslo_utils.fixture import uuidsentinel as uuids @@ -35,6 +36,7 @@ from nova.volume import cinder ATTACHMENT_ID = uuids.attachment_id +@ddt.ddt class TestDriverBlockDevice(test.NoDBTestCase): # os-brick>=5.1 now uses external file system locks instead of internal # locks so we need to set up locking @@ -613,6 +615,7 @@ class TestDriverBlockDevice(test.NoDBTestCase): # First call to get() fails because the API isn't new enough. # So we fallback to the old call. self.volume_api.get.side_effect = [ + exception.CinderAPIVersionNotAvailable(version='3.69'), exception.CinderAPIVersionNotAvailable(version='3.48'), fake_volume] @@ -688,14 +691,17 @@ class TestDriverBlockDevice(test.NoDBTestCase): if include_shared_targets: self.volume_api.get.assert_called_once_with( - self.context, fake_volume['id'], microversion='3.48') + self.context, fake_volume['id'], microversion='3.69') else: # First call to get() fails because the API isn't new enough. # So we fallback to the old call. self.volume_api.get.assert_has_calls([ + mock.call(self.context, fake_volume['id'], + microversion='3.69'), mock.call(self.context, fake_volume['id'], microversion='3.48'), - mock.call(self.context, fake_volume['id'])]) + mock.call(self.context, fake_volume['id'], + microversion=None)]) try: self.volume_api.check_availability_zone.assert_called_once_with( @@ -1557,6 +1563,24 @@ class TestDriverBlockDevice(test.NoDBTestCase): self._test_boot_from_volume_source_snapshot_volume_type( bdm, 'fake-lvm-1') + @ddt.data(['3.69'], ['3.69', '3.48'], ['3.69', '3.48', None]) + def test__get_volume(self, microversions): + volume_api = mock.Mock() + exp = mock.Mock() + exc = exception.CinderAPIVersionNotAvailable + side_effect = [exc(version=mv) for mv in microversions[:-1]] + [exp] + volume_api.get.side_effect = side_effect + + res = self.driver_classes['volume']._get_volume( + self.context, volume_api, mock.sentinel.volume_id) + + self.assertEqual(exp, res) + + self.assertEqual(len(microversions), volume_api.get.call_count) + volume_api.get.assert_has_calls( + [mock.call(self.context, mock.sentinel.volume_id, microversion=mv) + for mv in microversions]) + class TestDriverBlockDeviceNewFlow(TestDriverBlockDevice): """Virt block_device tests for the Cinder 3.44 volume attach flow diff --git a/nova/virt/block_device.py b/nova/virt/block_device.py index 28a866a817fb..059131c25095 100644 --- a/nova/virt/block_device.py +++ b/nova/virt/block_device.py @@ -399,13 +399,14 @@ class DriverVolumeBlockDevice(DriverBlockDevice): @staticmethod def _get_volume(context, volume_api, volume_id): - # First try to get the volume at microversion 3.48 so we can get the - # shared_targets parameter exposed in that version. If that API version - # is not available, we just fallback. - try: - return volume_api.get(context, volume_id, microversion='3.48') - except exception.CinderAPIVersionNotAvailable: - return volume_api.get(context, volume_id) + # First try microversion for tri-state shared_targets, then older + # shared_targets, finally fallback to standard v3. + versions = ('3.69', '3.48', None) + for mv in versions: + try: + return volume_api.get(context, volume_id, microversion=mv) + except exception.CinderAPIVersionNotAvailable: + pass def _create_volume(self, context, instance, volume_api, size, wait_func=None, **create_kwargs): diff --git a/releasenotes/notes/nvmeof-guard-0f99effdd03983b6.yaml b/releasenotes/notes/nvmeof-guard-0f99effdd03983b6.yaml new file mode 100644 index 000000000000..379ae9daace3 --- /dev/null +++ b/releasenotes/notes/nvmeof-guard-0f99effdd03983b6.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + `Bug #2035375 <https://bugs.launchpad.net/nova/+bug/2035375>`_: Fixed + leftover NVMe-oF subsystems when disconnecting multiple NVMe-oF volumes on + the same host from storage sharing the subsystem for different volumes.