Add placement client methods for allocations
Added placement client methods for listing and updating allocations and for updating QoS minumum bandwidth allocation. Change-Id: I9dab2e9e9728183ee209a038a0347eb7b4a83a1c Related-Bug: #1882804
This commit is contained in:
parent
3d6e16de32
commit
41e6b9bed8
@ -80,3 +80,17 @@ class AmbiguousResponsibilityForResourceProvider(exceptions.NeutronException):
|
||||
"""Not clear who's responsible for resource provider."""
|
||||
message = _("Expected one driver to be responsible for resource provider "
|
||||
"%(rsc_provider)s, but got many: %(drivers)s")
|
||||
|
||||
|
||||
class PlacementAllocationGenerationConflict(exceptions.Conflict):
|
||||
message = _("Resource allocation has been changed for consumer "
|
||||
"%(consumer)s in Placement while Neutron tried to update it.")
|
||||
|
||||
|
||||
class PlacementAllocationRemoved(exceptions.BadRequest):
|
||||
message = _("Resource allocation is deleted for consumer %(consumer)s")
|
||||
|
||||
|
||||
class PlacementAllocationRpNotExists(exceptions.BadRequest):
|
||||
message = _("Resource provider %(resource_provider)s for %(consumer)s "
|
||||
"does not exist")
|
||||
|
@ -38,7 +38,8 @@ PLACEMENT_API_WITH_MEMBER_OF = 'placement 1.3'
|
||||
PLACEMENT_API_WITH_NESTED_RESOURCES = 'placement 1.14'
|
||||
PLACEMENT_API_RETURN_PROVIDER_BODY = 'placement 1.20'
|
||||
PLACEMENT_API_ERROR_CODE = 'placement 1.23'
|
||||
PLACEMENT_API_LATEST_SUPPORTED = PLACEMENT_API_ERROR_CODE
|
||||
PLACEMENT_API_CONSUMER_GENERATION = 'placement 1.28'
|
||||
PLACEMENT_API_LATEST_SUPPORTED = PLACEMENT_API_CONSUMER_GENERATION
|
||||
GENERATION_CONFLICT_RETRIES = 10
|
||||
|
||||
|
||||
@ -732,3 +733,60 @@ class PlacementAPIClient(object):
|
||||
self._delete(url)
|
||||
except ks_exc.NotFound:
|
||||
raise n_exc.PlacementResourceClassNotFound(resource_class=name)
|
||||
|
||||
@_check_placement_api_available
|
||||
def list_allocations(self, consumer_uuid):
|
||||
"""List allocations for the consumer
|
||||
|
||||
:param consumer_uuid: The uuid of the consumer, in case of bound port
|
||||
owned by a VM, the VM uuid.
|
||||
:returns: All allocation records for the consumer.
|
||||
"""
|
||||
url = '/allocations/%s' % consumer_uuid
|
||||
return self._get(url).json()
|
||||
|
||||
def update_qos_minbw_allocation(self, consumer_uuid, minbw_alloc_diff,
|
||||
rp_uuid):
|
||||
"""Update allocation for QoS minimum bandwidth consumer
|
||||
|
||||
:param consumer_uuid: The uuid of the consumer, in case of bound port
|
||||
owned by a VM, the VM uuid.
|
||||
:param minbw_alloc_diff: A dict which contains the fields to update
|
||||
for the allocation under the given resource
|
||||
provider.
|
||||
:param rp_uuid: uuid of the resource provider for which the
|
||||
allocations are to be updated.
|
||||
"""
|
||||
for i in range(GENERATION_CONFLICT_RETRIES):
|
||||
body = self.list_allocations(consumer_uuid)
|
||||
if not body['allocations']:
|
||||
raise n_exc.PlacementAllocationRemoved(consumer=consumer_uuid)
|
||||
if rp_uuid not in body['allocations']:
|
||||
raise n_exc.PlacementAllocationRpNotExists(
|
||||
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]
|
||||
new_kbps = orig_kbps + min_kbps_diff
|
||||
body['allocations'][rp_uuid]['resources'][drctn] = new_kbps
|
||||
try:
|
||||
# Update allocations has no return body, but leave the loop
|
||||
return self.update_allocation(consumer_uuid, body)
|
||||
except ks_exc.Conflict as e:
|
||||
resp = e.response.json()
|
||||
if resp['errors'][0]['code'] == 'placement.concurrent_update':
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
raise n_exc.PlacementAllocationGenerationConflict(
|
||||
consumer=consumer_uuid)
|
||||
|
||||
def update_allocation(self, consumer_uuid, allocations):
|
||||
"""Update allocation record for given consumer and rp
|
||||
|
||||
:param consumer_uuid: The uuid of the consumer
|
||||
:param allocations: Dict in the form described in placement API ref:
|
||||
https://tinyurl.com/yxeuzn6l
|
||||
"""
|
||||
url = '/allocations/%s' % consumer_uuid
|
||||
self._put(url, allocations)
|
||||
|
@ -26,6 +26,7 @@ from neutron_lib.tests import _base as base
|
||||
|
||||
|
||||
RESOURCE_PROVIDER_UUID = uuidutils.generate_uuid()
|
||||
CONSUMER_UUID = uuidutils.generate_uuid()
|
||||
RESOURCE_PROVIDER_NAME = 'resource_provider_name'
|
||||
RESOURCE_PROVIDER = {
|
||||
'uuid': RESOURCE_PROVIDER_UUID,
|
||||
@ -698,3 +699,138 @@ class TestPlacementAPIClient(base.BaseTestCase):
|
||||
resource_provider_generation=None,
|
||||
)
|
||||
self.assertEqual(1, self.placement_fixture.mock_put.call_count)
|
||||
|
||||
def test_list_allocations(self):
|
||||
self.placement_api_client.list_allocations(CONSUMER_UUID)
|
||||
self.placement_fixture.mock_get.assert_called_once_with(
|
||||
'/allocations/%s' % CONSUMER_UUID)
|
||||
|
||||
def test_update_allocation(self):
|
||||
mock_rsp = mock.Mock()
|
||||
mock_rsp.json = lambda: {
|
||||
'allocations': {
|
||||
RESOURCE_PROVIDER_UUID: {'resources': {'a': 10}}
|
||||
}
|
||||
}
|
||||
self.placement_fixture.mock_get.side_effect = [mock_rsp]
|
||||
self.placement_api_client.update_allocation(
|
||||
CONSUMER_UUID,
|
||||
{'allocations': {
|
||||
RESOURCE_PROVIDER_UUID: {
|
||||
'resources': {'a': 20}}
|
||||
}})
|
||||
self.placement_fixture.mock_put.assert_called_once_with(
|
||||
'/allocations/%s' % CONSUMER_UUID,
|
||||
{'allocations': {
|
||||
RESOURCE_PROVIDER_UUID: {
|
||||
'resources': {'a': 20}}
|
||||
}}
|
||||
)
|
||||
|
||||
def test_update_qos_minbw_allocation(self):
|
||||
mock_rsp_get = mock.Mock()
|
||||
mock_rsp_get.json = lambda: {
|
||||
'allocations': {
|
||||
RESOURCE_PROVIDER_UUID: {
|
||||
'resources': {'a': 3, 'b': 2}
|
||||
}
|
||||
}
|
||||
}
|
||||
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': 2, 'b': 2},
|
||||
rp_uuid=RESOURCE_PROVIDER_UUID
|
||||
)
|
||||
self.placement_fixture.mock_put.assert_called_once_with(
|
||||
'/allocations/%s' % CONSUMER_UUID,
|
||||
{'allocations': {
|
||||
RESOURCE_PROVIDER_UUID: {
|
||||
'resources': {'a': 5, 'b': 4}}
|
||||
}}
|
||||
)
|
||||
|
||||
def test_update_qos_minbw_allocation_removed(self):
|
||||
mock_rsp = mock.Mock()
|
||||
mock_rsp.json = lambda: {'allocations': {}}
|
||||
self.placement_fixture.mock_get.side_effect = [mock_rsp]
|
||||
self.assertRaises(
|
||||
n_exc.PlacementAllocationRemoved,
|
||||
self.placement_api_client.update_qos_minbw_allocation,
|
||||
consumer_uuid=CONSUMER_UUID,
|
||||
minbw_alloc_diff={'a': 1, 'b': 1},
|
||||
rp_uuid=RESOURCE_PROVIDER_UUID
|
||||
)
|
||||
|
||||
def test_update_qos_minbw_allocation_rp_not_exists(self):
|
||||
mock_rsp = mock.Mock()
|
||||
mock_rsp.json = lambda: {'allocations': {'other:rp:uuid': {'c': 3}}}
|
||||
self.placement_fixture.mock_get.side_effect = [mock_rsp]
|
||||
self.assertRaises(
|
||||
n_exc.PlacementAllocationRpNotExists,
|
||||
self.placement_api_client.update_qos_minbw_allocation,
|
||||
consumer_uuid=CONSUMER_UUID,
|
||||
minbw_alloc_diff={'a': 1, 'b': 1},
|
||||
rp_uuid=RESOURCE_PROVIDER_UUID
|
||||
)
|
||||
|
||||
def test_update_qos_minbw_allocation_max_retries(self):
|
||||
mock_rsp_get = mock.Mock()
|
||||
mock_rsp_get.json = lambda: {
|
||||
'allocations': {RESOURCE_PROVIDER_UUID: {'c': 3}}
|
||||
}
|
||||
self.placement_fixture.mock_get.side_effect = 10 * [mock_rsp_get]
|
||||
mock_rsp_put = mock.Mock()
|
||||
mock_rsp_put.json = lambda: {
|
||||
'errors': [{'code': 'placement.concurrent_update'}]}
|
||||
self.placement_fixture.mock_put.side_effect = ks_exc.Conflict(
|
||||
response=mock_rsp_put)
|
||||
self.assertRaises(
|
||||
n_exc.PlacementAllocationGenerationConflict,
|
||||
self.placement_api_client.update_qos_minbw_allocation,
|
||||
consumer_uuid=CONSUMER_UUID,
|
||||
minbw_alloc_diff={},
|
||||
rp_uuid=RESOURCE_PROVIDER_UUID,
|
||||
)
|
||||
self.assertEqual(10, self.placement_fixture.mock_put.call_count)
|
||||
|
||||
def test_update_qos_minbwallocation_generation_conflict_solved(self):
|
||||
mock_rsp_get = mock.Mock()
|
||||
mock_rsp_get.json = lambda: {
|
||||
'allocations': {RESOURCE_PROVIDER_UUID: {'c': 3}}
|
||||
}
|
||||
self.placement_fixture.mock_get.side_effect = 2 * [mock_rsp_get]
|
||||
mock_rsp_put = mock.Mock()
|
||||
mock_rsp_put.json = lambda: {
|
||||
'errors': [{'code': 'placement.concurrent_update'}]}
|
||||
self.placement_fixture.mock_put.side_effect = [
|
||||
ks_exc.Conflict(response=mock_rsp_put),
|
||||
mock.Mock()
|
||||
]
|
||||
self.placement_api_client.update_qos_minbw_allocation(
|
||||
consumer_uuid=CONSUMER_UUID,
|
||||
minbw_alloc_diff={},
|
||||
rp_uuid=RESOURCE_PROVIDER_UUID
|
||||
)
|
||||
self.assertEqual(2, self.placement_fixture.mock_put.call_count)
|
||||
|
||||
def test_update_qos_minbw_allocation_other_conflict(self):
|
||||
mock_rsp_get = mock.Mock()
|
||||
mock_rsp_get.json = lambda: {
|
||||
'allocations': {RESOURCE_PROVIDER_UUID: {'c': 3}}
|
||||
}
|
||||
self.placement_fixture.mock_get.side_effect = 10*[mock_rsp_get]
|
||||
mock_rsp_put = mock.Mock()
|
||||
mock_rsp_put.text = ''
|
||||
mock_rsp_put.json = lambda: {
|
||||
'errors': [{'code': 'some other error code'}]}
|
||||
self.placement_fixture.mock_put.side_effect = ks_exc.Conflict(
|
||||
response=mock_rsp_put)
|
||||
self.assertRaises(
|
||||
ks_exc.Conflict,
|
||||
self.placement_api_client.update_qos_minbw_allocation,
|
||||
consumer_uuid=CONSUMER_UUID,
|
||||
minbw_alloc_diff={},
|
||||
rp_uuid=RESOURCE_PROVIDER_UUID,
|
||||
)
|
||||
self.placement_fixture.mock_put.assert_called_once()
|
||||
|
8
releasenotes/notes/allocations_api-1ae5fd78c83353df.yaml
Normal file
8
releasenotes/notes/allocations_api-1ae5fd78c83353df.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
- Bump ``PlacementAPIClient's`` max supported microversion to ``1.28``,
|
||||
as from that version ``allocations`` API handles generations in a general
|
||||
way.
|
||||
- Add ``list_allocations``, ``update_allocation`` and
|
||||
``update_qos_minbw_allocation`` methods.
|
Loading…
Reference in New Issue
Block a user