[stable-only] Fix allocation update for min bw rule with different direction

Neutron API supports QoS policy change on a bound port. The new QoS
policy can contain a different set of rules, or different values. In
case of QoS minimum bandwidth rule, it can be min_kbps or direction
attribute. If the new QoS minimum bandwidth rule is different than the
one in previous QoS policy, Placement allocation has to be updated.

An issue arises when QoS minimum bandwidth rule direction is changed.
Ingress and egress directions are represented with separate resource
classes: NET_BW_IGR_KILOBIT_PER_SEC and NET_BW_EGR_KILOBIT_PER_SEC
respectively. During direction change, resource class representing old
direction is freed and a resource class representing the new direction
is requested. update_qos_minbw_allocation() implementation always
expects requested resource class to be present in the allocation that
is being updated, but that assumption is wrong. If current Placement
allocation record doesn't contain particular resource class, we need to
use 0 as a default value.

Similarly, we should defer deletion of RP from request body until all
items from minbw_alloc_diff are processed. Only then we can be certain
that this RR is not going to have any resources.

This commit is based on 47a08e36bf.

Partial-Bug: #1943724
Change-Id: I9a0df4d461c0e73ba07ca18648f16a982a2e267b
This commit is contained in:
Przemyslaw Szczerbik 2021-11-02 11:24:44 +01:00
parent 19cf80f06c
commit 997be4d13b
2 changed files with 24 additions and 5 deletions

View File

@ -773,7 +773,8 @@ class PlacementAPIClient(object):
resource_provider=rp_uuid, consumer=consumer_uuid)
# Count new min_kbps values based on the diff in alloc_diff
for drctn, min_kbps_diff in minbw_alloc_diff.items():
orig_kbps = body['allocations'][rp_uuid]['resources'][drctn]
orig_kbps = (body['allocations'][rp_uuid][
'resources'].get(drctn, 0))
new_kbps = orig_kbps + min_kbps_diff
if new_kbps > 0:
body['allocations'][rp_uuid]['resources'][drctn] = new_kbps
@ -781,10 +782,12 @@ class PlacementAPIClient(object):
# Remove the resource class if the new value for min_kbps
# is 0
resources = body['allocations'][rp_uuid]['resources']
if len(resources) > 1:
resources.pop(drctn, None)
else:
body['allocations'].pop(rp_uuid)
resources.pop(drctn, None)
# Remove RPs without any resources
body['allocations'] = {
rp: alloc for rp, alloc in body['allocations'].items()
if alloc.get('resources')}
try:
# Update allocations has no return body, but leave the loop
return self.update_allocation(consumer_uuid, body)

View File

@ -857,3 +857,19 @@ class TestPlacementAPIClient(base.BaseTestCase):
RESOURCE_PROVIDER_UUID: {
'resources': {'b': 3}}
}})
def test_update_qos_minbw_allocation_one_class_to_zero_and_new_class(self):
mock_rsp_get = self._get_allocation_response(
{'resources': {'a': 3}})
self.placement_fixture.mock_get.side_effect = [mock_rsp_get]
self.placement_api_client.update_qos_minbw_allocation(
consumer_uuid=CONSUMER_UUID,
minbw_alloc_diff={'a': -3, 'b': 1},
rp_uuid=RESOURCE_PROVIDER_UUID
)
self.placement_fixture.mock_put.assert_called_once_with(
'/allocations/%s' % CONSUMER_UUID,
{'allocations': {
RESOURCE_PROVIDER_UUID: {
'resources': {'b': 1}}
}})