diff --git a/neutron/agent/common/placement_report.py b/neutron/agent/common/placement_report.py index 1946ffae467..bf162821717 100644 --- a/neutron/agent/common/placement_report.py +++ b/neutron/agent/common/placement_report.py @@ -170,6 +170,26 @@ class PlacementState(object): rps.extend(device_rps) return rps + def _deferred_update_agent_rp_traits(self, traits_): + agent_rp_traits = [] + + if not traits_: + return agent_rp_traits + + # Remove hypervisor duplicates to avoid calling placement API multiple + # times for the same hypervisor. + hypervisors = set(h['name'] for h in self._hypervisor_rps.values()) + for hypervisor in hypervisors: + agent_rp_uuid = place_utils.agent_resource_provider_uuid( + self._driver_uuid_namespace, hypervisor) + agent_rp_traits.append( + DeferredCall( + self._client.update_resource_provider_traits, + resource_provider_uuid=agent_rp_uuid, + traits=traits_)) + + return agent_rp_traits + def deferred_update_resource_provider_traits(self): rp_traits = [] @@ -195,6 +215,8 @@ class PlacementState(object): resource_provider_uuid=rp_uuid, traits=traits)) + rp_traits += self._deferred_update_agent_rp_traits(vnic_type_traits) + return rp_traits def deferred_update_resource_provider_inventories(self): diff --git a/neutron/tests/unit/agent/common/test_placement_report.py b/neutron/tests/unit/agent/common/test_placement_report.py index 082e3724cc6..e7e391c9c1f 100644 --- a/neutron/tests/unit/agent/common/test_placement_report.py +++ b/neutron/tests/unit/agent/common/test_placement_report.py @@ -95,6 +95,31 @@ class PlacementStateTestCase(base.BaseTestCase): self.client_mock.update_trait.assert_any_call( name='CUSTOM_VNIC_TYPE_DIRECT') + def test__deferred_update_agent_rp_traits(self): + self.kwargs['hypervisor_rps']['eth3'] = { + 'name': 'fakehost2', + 'uuid': self.hypervisor2_rp_uuid, + } + state = placement_report.PlacementState(**self.kwargs) + + for deferred in state._deferred_update_agent_rp_traits( + ['CUSTOM_FAKE_TRAIT_NAME']): + deferred.execute() + + expected_calls = [ + mock.call( + traits=['CUSTOM_FAKE_TRAIT_NAME'], + # uuid -v5 '00000000-0000-0000-0000-000000000001' 'fakehost' + resource_provider_uuid=uuid.UUID( + 'c0b4abe5-516f-54b8-b965-ff94060dcbcc')), + mock.call( + traits=['CUSTOM_FAKE_TRAIT_NAME'], + # uuid -v5 '00000000-0000-0000-0000-000000000001' 'fakehost2' + resource_provider_uuid=uuid.UUID( + '544155b7-1295-5f10-b5f0-eadc50abc6d4'))] + self.client_mock.update_resource_provider_traits.\ + assert_has_calls(expected_calls, any_order=True) + def test__deferred_create_agent_rps(self): state = placement_report.PlacementState(**self.kwargs) @@ -176,18 +201,29 @@ class PlacementStateTestCase(base.BaseTestCase): for deferred in state.deferred_update_resource_provider_traits(): deferred.execute() - self.client_mock.update_resource_provider_traits.assert_called() - self.assertEqual( + expected_calls = [ # uuid below generated by the following command: # uuid -v5 '00000000-0000-0000-0000-000000000001' 'fakehost:eth0' - uuid.UUID('1ea6f823-bcf2-5dc5-9bee-4ee6177a6451'), - self.client_mock.update_resource_provider_traits.call_args[1][ - 'resource_provider_uuid']) + mock.call( + resource_provider_uuid=uuid.UUID( + '1ea6f823-bcf2-5dc5-9bee-4ee6177a6451'), + traits=mock.ANY), + + # uuid -v5 '00000000-0000-0000-0000-000000000001' 'fakehost' + mock.call( + resource_provider_uuid=uuid.UUID( + 'c0b4abe5-516f-54b8-b965-ff94060dcbcc'), + traits=mock.ANY)] + self.client_mock.update_resource_provider_traits.assert_has_calls( + expected_calls) + # NOTE(bence romsics): To avoid testing the _order_ of traits. + actual_traits = [set(args[1]['traits']) for args in + self.client_mock.update_resource_provider_traits.call_args_list] self.assertEqual( - set(['CUSTOM_PHYSNET_PHYSNET0', 'CUSTOM_VNIC_TYPE_NORMAL']), - set(self.client_mock.update_resource_provider_traits.call_args[1][ - 'traits'])) + [set(['CUSTOM_PHYSNET_PHYSNET0', 'CUSTOM_VNIC_TYPE_NORMAL']), + set(['CUSTOM_VNIC_TYPE_NORMAL'])], + actual_traits) def test_deferred_update_resource_provider_inventories(self): self.kwargs.update({