diff options
author | Zuul <zuul@review.opendev.org> | 2022-03-05 15:48:25 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2022-03-05 15:48:25 +0000 |
commit | cb935a313961721839c574d7dcba5568ada9b195 (patch) | |
tree | affee91f766c8e6af6ecfa4a4412e588798a7ffe | |
parent | 0da42ad73d726c1ccf50d91ee6a59063b7b8953d (diff) | |
parent | 2bee83b8a980b2bd9e276b75aa74253f8c0d0a70 (diff) | |
download | nova-cb935a313961721839c574d7dcba5568ada9b195.tar.gz |
Merge "compute: Avoid duplicate BDMs during reserve_block_device_name" into stable/wallaby23.2.0
-rw-r--r-- | nova/compute/manager.py | 6 | ||||
-rw-r--r-- | nova/tests/functional/regressions/test_bug_1937375.py | 15 | ||||
-rw-r--r-- | nova/tests/unit/compute/test_compute_mgr.py | 26 |
3 files changed, 41 insertions, 6 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 2541b83274..c59fd31f21 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -6991,6 +6991,12 @@ class ComputeManager(manager.Manager): objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid)) + # Now that we have the lock check that we haven't raced another + # request and ensure there is no existing attachment + if any(b for b in bdms if b.volume_id == volume_id): + msg = _("volume %s already attached") % volume_id + raise exception.InvalidVolume(reason=msg) + # NOTE(ndipanov): We need to explicitly set all the fields on the # object so that obj_load_attr does not fail new_bdm = objects.BlockDeviceMapping( diff --git a/nova/tests/functional/regressions/test_bug_1937375.py b/nova/tests/functional/regressions/test_bug_1937375.py index 007be9b5d7..88dfea0ad7 100644 --- a/nova/tests/functional/regressions/test_bug_1937375.py +++ b/nova/tests/functional/regressions/test_bug_1937375.py @@ -16,6 +16,7 @@ import mock import time from nova import context +from nova import exception from nova import objects from nova.tests.functional import integrated_helpers @@ -68,7 +69,12 @@ class TestDuplicateVolAttachRace(integrated_helpers._IntegratedTestBase): # twice to mimic two callers racing each other after the checks on # the api. original_bdm = original_reserve_name(*args, **kwargs) - original_reserve_name(*args, **kwargs) + + # Assert that a repeat call fails as an attachment already exists + self.assertRaises( + exception.InvalidVolume, + original_reserve_name, *args, **kwargs) + return original_bdm with mock.patch.object( @@ -86,10 +92,7 @@ class TestDuplicateVolAttachRace(integrated_helpers._IntegratedTestBase): bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( ctxt, server_id) - # FIXME(lyarwood): This is bug #1937375, we now have 3 bdms for the - # instance, the original root disk and two duplicate volume bdms for - # the same volume attachment. - self.assertEqual(3, len(bdms)) - self.assertEqual(volume_id, bdms[2].volume_id) + # Assert that the correct bdms are present + self.assertEqual(2, len(bdms)) self.assertEqual(volume_id, bdms[1].volume_id) self.assertEqual('local', bdms[0].destination_type) diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py index bc9b22ae2d..6dc9f4f83d 100644 --- a/nova/tests/unit/compute/test_compute_mgr.py +++ b/nova/tests/unit/compute/test_compute_mgr.py @@ -616,6 +616,32 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase, 'fake_device', 'fake_volume_id', 'fake_disk_bus', 'fake_device_type', tag=None, multiattach=True) + @mock.patch.object(compute_utils, 'add_instance_fault_from_exc', + new=mock.Mock()) + @mock.patch.object(objects.BlockDeviceMapping, 'create', new=mock.Mock()) + @mock.patch.object(objects.BlockDeviceMappingList, 'get_by_instance_uuid') + def test_reserve_block_device_name_raises_on_duplicate(self, mock_get): + instance = fake_instance.fake_instance_obj(self.context) + vol_bdm = objects.BlockDeviceMapping( + self.context, + id=1, + instance_uuid=instance.uuid, + volume_id="myinstanceuuid", + source_type='volume', + destination_type='volume', + delete_on_termination=True, + connection_info=None, + tag='fake-tag', + device_name='/dev/fake0', + attachment_id=uuids.attachment_id) + mock_get.return_value = objects.BlockDeviceMappingList( + objects=[vol_bdm]) + + self.assertRaises(exception.InvalidVolume, + self.compute.reserve_block_device_name, + self.context, instance, None, "myinstanceuuid", + None, None, 'foo', False) + @mock.patch.object(objects.Instance, 'save') @mock.patch.object(time, 'sleep') def test_allocate_network_succeeds_after_retries( |