From 191bdf2069086493be2a2e0351afa7f3efad7099 Mon Sep 17 00:00:00 2001 From: Balazs Gibizer Date: Fri, 23 Jul 2021 18:23:28 +0200 Subject: Support move ops with extended resource request Nova re-generates the resource request of an instance for each server move operation (migrate, resize, evacuate, live-migrate, unshelve) to find (or validate) a target host for the instance move. This patch extends the this logic to support the extended resource request from neutron. As the changes in the neutron interface code is called from nova-compute service during the port binding the compute service version is bumped. And a check is added to the compute-api to reject the move operations with ports having extended resource request if there are old computes in the cluster. blueprint: qos-minimum-guaranteed-packet-rate Change-Id: Ibcf703e254e720b9a6de17527325758676628d48 --- nova/tests/unit/compute/test_api.py | 63 ++++++++++++++++++++++++++++++--- nova/tests/unit/compute/test_compute.py | 15 ++++++++ nova/tests/unit/compute/test_shelve.py | 19 ++++++++++ 3 files changed, 92 insertions(+), 5 deletions(-) (limited to 'nova/tests/unit/compute') diff --git a/nova/tests/unit/compute/test_api.py b/nova/tests/unit/compute/test_api.py index d0d7e5ba1d..a840c75629 100644 --- a/nova/tests/unit/compute/test_api.py +++ b/nova/tests/unit/compute/test_api.py @@ -86,6 +86,14 @@ class _ComputeAPIUnitTestMixIn(object): self.context = context.RequestContext(self.user_id, self.project_id) + self.useFixture( + fixtures.MonkeyPatch( + 'nova.network.neutron.API.' + 'instance_has_extended_resource_request', + mock.Mock(return_value=False), + ) + ) + def _get_vm_states(self, exclude_states=None): vm_state = set([vm_states.ACTIVE, vm_states.BUILDING, vm_states.PAUSED, vm_states.SUSPENDED, vm_states.RESCUED, vm_states.STOPPED, @@ -1751,7 +1759,7 @@ class _ComputeAPIUnitTestMixIn(object): @mock.patch('nova.virt.hardware.numa_get_constraints') @mock.patch('nova.network.neutron.API.get_requested_resource_for_instance', - return_value=[]) + return_value=([], objects.RequestLevelParams())) @mock.patch('nova.availability_zones.get_host_availability_zone', return_value='nova') @mock.patch('nova.objects.Quotas.check_deltas') @@ -1843,6 +1851,9 @@ class _ComputeAPIUnitTestMixIn(object): self.assertEqual( [], mock_get_reqspec.return_value.requested_resources) + self.assertEqual( + mock_get_requested_resources.return_value[1], + mock_get_reqspec.return_value.request_level_params) def test_revert_resize(self): self._test_revert_resize(same_flavor=False) @@ -2178,6 +2189,27 @@ class _ComputeAPIUnitTestMixIn(object): self.compute_api.resize, self.context, fake_inst, flavor_id=new_flavor.flavorid) + @mock.patch( + 'nova.compute.api.API.get_instance_host_status', + new=mock.Mock(return_value=fields_obj.HostStatus.UP) + ) + @mock.patch( + 'nova.objects.service.get_minimum_version_all_cells', + new=mock.Mock(return_value=58), + ) + @mock.patch( + 'nova.network.neutron.API.instance_has_extended_resource_request', + new=mock.Mock(return_value=True), + ) + def test_resize_with_extended_resource_request_old_compute(self): + fake_inst = self._create_instance_obj() + + self.assertRaises( + exception.ExtendedResourceRequestOldCompute, + self.compute_api.resize, + self.context, fake_inst, flavor_id=uuids.new_falvor + ) + def _test_migrate(self, *args, **kwargs): self._test_resize(*args, flavor_id_passed=False, **kwargs) @@ -2607,6 +2639,23 @@ class _ComputeAPIUnitTestMixIn(object): disk_over_commit=False) self.assertIsNone(instance.task_state) + @mock.patch( + 'nova.objects.service.get_minimum_version_all_cells', + new=mock.Mock(return_value=58), + ) + @mock.patch( + 'nova.network.neutron.API.instance_has_extended_resource_request', + new=mock.Mock(return_value=True), + ) + def test_live_migrate_with_extended_resource_request_old_compute(self): + instance = self._create_instance_obj() + self.assertRaises( + exception.ExtendedResourceRequestOldCompute, + self.compute_api.live_migrate, self.context, instance, + host_name='fake_host', block_migration='auto', + disk_over_commit=False + ) + @mock.patch.object(objects.RequestSpec, 'get_by_instance_uuid') @mock.patch.object(objects.Instance, 'save') @mock.patch.object(objects.InstanceAction, 'action_start') @@ -7696,8 +7745,10 @@ class ComputeAPIUnitTestCase(_ComputeAPIUnitTestMixIn, test.NoDBTestCase): mock_get_min_ver.assert_called_once_with( self.context, ['nova-compute']) - @mock.patch('nova.network.neutron.API.get_requested_resource_for_instance', - return_value=[objects.RequestGroup()]) + @mock.patch( + 'nova.network.neutron.API.get_requested_resource_for_instance', + return_value=([objects.RequestGroup()], objects.RequestLevelParams()) + ) @mock.patch('nova.objects.service.get_minimum_version_all_cells', return_value=compute_api.MIN_COMPUTE_CROSS_CELL_RESIZE) def test_allow_cross_cell_resize_false_port_with_resource_req( @@ -7716,8 +7767,10 @@ class ComputeAPIUnitTestCase(_ComputeAPIUnitTestMixIn, test.NoDBTestCase): self.context, ['nova-compute']) mock_get_res_req.assert_called_once_with(self.context, uuids.instance) - @mock.patch('nova.network.neutron.API.get_requested_resource_for_instance', - return_value=[]) + @mock.patch( + 'nova.network.neutron.API.get_requested_resource_for_instance', + return_value=([], objects.RequestLevelParams()) + ) @mock.patch('nova.objects.service.get_minimum_version_all_cells', return_value=compute_api.MIN_COMPUTE_CROSS_CELL_RESIZE) def test_allow_cross_cell_resize_true( diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py index 003114192b..ae71d3fd1f 100644 --- a/nova/tests/unit/compute/test_compute.py +++ b/nova/tests/unit/compute/test_compute.py @@ -12029,6 +12029,21 @@ class ComputeAPITestCase(BaseTestCase): host='fake_dest_host', on_shared_storage=True, admin_password=None) + @mock.patch( + 'nova.objects.service.get_minimum_version_all_cells', + new=mock.Mock(return_value=58), + ) + @mock.patch( + 'nova.network.neutron.API.instance_has_extended_resource_request', + new=mock.Mock(return_value=True), + ) + def test_evacuate_with_extended_resource_request_old_compute(self): + instance = self._create_fake_instance_obj(services=True) + self.assertRaises(exception.ExtendedResourceRequestOldCompute, + self.compute_api.evacuate, self.context.elevated(), instance, + host='fake_dest_host', on_shared_storage=True, + admin_password=None) + @mock.patch('nova.objects.MigrationList.get_by_filters') def test_get_migrations(self, mock_migration): migration = test_migration.fake_db_migration() diff --git a/nova/tests/unit/compute/test_shelve.py b/nova/tests/unit/compute/test_shelve.py index 12bf23bda2..3f3f470fa5 100644 --- a/nova/tests/unit/compute/test_shelve.py +++ b/nova/tests/unit/compute/test_shelve.py @@ -1028,6 +1028,25 @@ class ShelveComputeAPITestCase(test_compute.BaseTestCase): self.compute_api.unshelve, self.context, instance, new_az=new_az) + @mock.patch( + 'nova.objects.service.get_minimum_version_all_cells', + new=mock.Mock(return_value=58), + ) + @mock.patch( + 'nova.network.neutron.API.instance_has_extended_resource_request', + new=mock.Mock(return_value=True), + ) + def test_unshelve_offloaded_with_extended_resource_request_old_compute( + self + ): + instance = self._get_specify_state_instance( + vm_states.SHELVED_OFFLOADED) + + self.assertRaises( + exception.ExtendedResourceRequestOldCompute, + self.compute_api.unshelve, self.context, instance, new_az="az1" + ) + @mock.patch('nova.objects.BlockDeviceMappingList.get_by_instance_uuid', new_callable=mock.NonCallableMock) @mock.patch('nova.availability_zones.get_availability_zones') -- cgit v1.2.1