From 18ec0eb20921e41ba4cade555f9da823c9dbfa13 Mon Sep 17 00:00:00 2001 From: Przemyslaw Szczerbik Date: Mon, 25 Oct 2021 13:24:07 +0200 Subject: [PATCH] Fix placement allocation update for port with network QoS policy If port has no QoS policy on its own, fallback to the network QoS policy and use it to check if Placement allocation needs to be updated. Closes-Bug: #1915849 Change-Id: Iffc87e4021391bcb98375621739a59064540a6a7 --- neutron/services/qos/qos_plugin.py | 9 ++- .../unit/services/qos/test_qos_plugin.py | 64 +++++++++++++++---- 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/neutron/services/qos/qos_plugin.py b/neutron/services/qos/qos_plugin.py index b8a8dd1eb8b..4d544037392 100644 --- a/neutron/services/qos/qos_plugin.py +++ b/neutron/services/qos/qos_plugin.py @@ -396,10 +396,13 @@ class QoSPlugin(qos.QoSPluginBase): context = payload.context orig_port = payload.states[0] port = payload.latest_state - original_policy_id = orig_port.get(qos_consts.QOS_POLICY_ID) - if qos_consts.QOS_POLICY_ID not in port: + original_policy_id = (orig_port.get(qos_consts.QOS_POLICY_ID) or + orig_port.get(qos_consts.QOS_NETWORK_POLICY_ID)) + if (qos_consts.QOS_POLICY_ID not in port and + qos_consts.QOS_NETWORK_POLICY_ID not in port): return - policy_id = port.get(qos_consts.QOS_POLICY_ID) + policy_id = (port.get(qos_consts.QOS_POLICY_ID) or + port.get(qos_consts.QOS_NETWORK_POLICY_ID)) if policy_id == original_policy_id: return diff --git a/neutron/tests/unit/services/qos/test_qos_plugin.py b/neutron/tests/unit/services/qos/test_qos_plugin.py index 38b5ffca09e..777f8bc7310 100644 --- a/neutron/tests/unit/services/qos/test_qos_plugin.py +++ b/neutron/tests/unit/services/qos/test_qos_plugin.py @@ -768,6 +768,7 @@ class TestQosPlugin(base.BaseQosTestCase): tenant_policy = { 'policy': {'id': policy_id, 'project_id': project_id, + 'tenant_id': project_id, 'name': 'test-policy', 'description': 'Test policy description', 'shared': True, @@ -2040,7 +2041,7 @@ class TestQosPluginDB(base.BaseQosTestCase): return qos_rule def _make_port(self, network_id, qos_policy_id=None, port_id=None, - device_owner=None): + qos_network_policy_id=None, device_owner=None): port_id = port_id if port_id else uuidutils.generate_uuid() base_mac = ['aa', 'bb', 'cc', 'dd', 'ee', 'ff'] mac = netaddr.EUI(next(net_utils.random_mac_generator(base_mac))) @@ -2048,7 +2049,8 @@ class TestQosPluginDB(base.BaseQosTestCase): port = ports_object.Port( self.context, network_id=network_id, device_owner=device_owner, project_id=self.project_id, admin_state_up=True, status='DOWN', - device_id='2', qos_policy_id=qos_policy_id, mac_address=mac, + device_id='2', qos_policy_id=qos_policy_id, + qos_network_policy_id=qos_network_policy_id, mac_address=mac, id=port_id) port.create() return port @@ -2133,11 +2135,14 @@ class TestQosPluginDB(base.BaseQosTestCase): def test_validate_create_port_callback_no_policy(self): self._test_validate_create_port_callback() - def _prepare_for_port_placement_allocation_change(self, qos1, qos2): + def _prepare_for_port_placement_allocation_change(self, qos1, qos2, + qos_network_policy=None): qos1_id = qos1.id if qos1 else None qos2_id = qos2.id if qos2 else None + qos_network_policy_id = ( + qos_network_policy.id if qos_network_policy else None) - network = self._make_network() + network = self._make_network(qos_policy_id=qos_network_policy_id) port = self._make_port( network.id, qos_policy_id=qos1_id, port_id=TestQosPluginDB.PORT_ID) @@ -2145,7 +2150,8 @@ class TestQosPluginDB(base.BaseQosTestCase): "original_port": { "id": port.id, "device_owner": "compute:uu:id", - "qos_policy_id": qos1_id}, + "qos_policy_id": qos1_id, + "qos_network_policy_id": qos_network_policy_id}, "port": {"id": port.id, "qos_policy_id": qos2_id}} def test_check_port_for_placement_allocation_change_no_qos_change(self): @@ -2220,6 +2226,26 @@ class TestQosPluginDB(base.BaseQosTestCase): context, states=(original_port, port))) mock_alloc_change.assert_not_called() + def test_check_port_for_placement_allocation_change_qos_network_policy( + self): + qos_network = self._make_qos_policy() + desired_qos = self._make_qos_policy() + kwargs = self._prepare_for_port_placement_allocation_change( + qos1=None, qos2=desired_qos, qos_network_policy=qos_network) + context = kwargs['context'] + original_port = kwargs['original_port'] + port = kwargs['port'] + + with mock.patch.object( + self.qos_plugin, + '_change_placement_allocation') as mock_alloc_change: + self.qos_plugin._check_port_for_placement_allocation_change( + 'PORT', 'before_update', 'test_plugin', + payload=events.DBEventPayload( + context, states=(original_port, port))) + mock_alloc_change.assert_called_once_with( + qos_network, desired_qos, kwargs['original_port'], port) + def test_check_network_for_placement_allocation_change_no_qos_change(self): qos1 = self._make_qos_policy() original_network = self._make_network(qos1.id) @@ -2395,26 +2421,28 @@ class TestQosPluginDB(base.BaseQosTestCase): def _prepare_port_for_placement_allocation(self, original_qos, desired_qos=None, + qos_network_policy=None, original_min_kbps=None, desired_min_kbps=None, original_min_kpps=None, desired_min_kpps=None, is_sriov=False): kwargs = self._prepare_for_port_placement_allocation_change( - original_qos, desired_qos) + original_qos, desired_qos, qos_network_policy=qos_network_policy) orig_port = kwargs['original_port'] - original_qos.rules = [] + qos = original_qos or qos_network_policy + qos.rules = [] allocation = {} if original_min_kbps: - original_qos.rules += [self._make_qos_minbw_rule( - original_qos.id, min_kbps=original_min_kbps, + qos.rules += [self._make_qos_minbw_rule( + qos.id, min_kbps=original_min_kbps, rule_id=TestQosPluginDB.QOS_MIN_BW_RULE_ID)] allocation.update( {TestQosPluginDB.MIN_BW_REQUEST_GROUP_UUID: TestQosPluginDB.MIN_BW_RP}) if original_min_kpps: - original_qos.rules += [self._make_qos_minpps_rule( - original_qos.id, min_kpps=original_min_kpps, + qos.rules += [self._make_qos_minpps_rule( + qos.id, min_kpps=original_min_kpps, rule_id=TestQosPluginDB.QOS_MIN_PPS_RULE_ID)] allocation.update( {TestQosPluginDB.MIN_PPS_REQUEST_GROUP_UUID: @@ -2728,3 +2756,17 @@ class TestQosPluginDB(base.BaseQosTestCase): pl_exc.PlacementAllocationGenerationConflict, self.qos_plugin._change_placement_allocation, qos1, qos2, orig_port, port) + + def test_change_placement_allocation_qos_network_policy(self): + qos_network = self._make_qos_policy() + desired_qos = self._make_qos_policy() + orig_port, port = self._prepare_port_for_placement_allocation( + None, desired_qos, qos_network_policy=qos_network, + original_min_kbps=1000, desired_min_kbps=2000) + with mock.patch.object(self.qos_plugin._placement_client, + 'update_qos_allocation') as mock_update_qos_alloc: + self.qos_plugin._change_placement_allocation( + qos_network, desired_qos, orig_port, port) + mock_update_qos_alloc.assert_called_once_with( + consumer_uuid='uu:id', + alloc_diff={self.MIN_BW_RP: {'NET_BW_IGR_KILOBIT_PER_SEC': 1000}})