New dict format of allocations (v1.11, v1.12)

v1.11:
Microversion 1.11 does not need any support in osc so we just skip over
that in this patch.

v1.12:
* Dict format to PUT /allocations.
  Compare for versions 1.11 and 1.12:
  $ openstack \
      --debug \
      --os-placement-api-version VERSION \
      resource provider allocation set CONSUMER-ID \
        --project-id PROJECT-ID \
        --user-id USER-ID \
        --allocation rp=RP-ID,MEMORY_MB=1
* Fields added to the GET /allocations response: project_id, user_id.
  $ openstack \
      --debug \
      --os-placement-api-version VERSION \
      resource provider allocation show CONSUMER-ID
* Dict format in allocation_requests of GET /allocation_candidates.
  $ openstack \
      --debug \
      --os-placement-api-version VERSION \
      allocation candidate show \
        --resource VCPU=1,MEMORY_MB=1

Partially-Implements: blueprint placement-osc-plugin-rocky
Change-Id: Ie2f6a9e73e9b00968c8e850aea705ffccdfa124b
This commit is contained in:
Bence Romsics 2018-02-08 15:39:42 +01:00 committed by Matt Riedemann
parent d343dcb7ca
commit f3ed1e7112
5 changed files with 108 additions and 22 deletions

View File

@ -18,7 +18,6 @@ from osc_placement import version
BASE_URL = '/allocations'
FIELDS = ('generation', 'resources')
def parse_allocations(allocation_strings):
@ -57,6 +56,10 @@ class SetAllocation(command.Lister, version.CheckerMixin):
recommended to provide a ``--project-id`` and ``--user-id`` when setting
allocations for accounting and data consistency reasons.
Starting with ``--os-placement-api-version 1.12`` the API response
contains the project_id and user_id of allocations which also
appears in the CLI output.
"""
def get_parser(self, prog_name):
@ -101,9 +104,15 @@ class SetAllocation(command.Lister, version.CheckerMixin):
if not allocations:
raise exceptions.CommandError(
'At least one resource allocation must be specified')
allocations = [
{'resource_provider': {'uuid': rp}, 'resources': resources}
for rp, resources in allocations.items()]
if self.compare_version(version.ge('1.12')):
allocations = {
rp: {'resources': resources}
for rp, resources in allocations.items()}
else:
allocations = [
{'resource_provider': {'uuid': rp}, 'resources': resources}
for rp, resources in allocations.items()]
url = BASE_URL + '/' + parsed_args.uuid
payload = {'allocations': allocations}
@ -115,16 +124,29 @@ class SetAllocation(command.Lister, version.CheckerMixin):
'affect allocation for '
'--os-placement-api-version less than 1.8')
http.request('PUT', url, json=payload)
per_provider = http.request('GET', url).json()['allocations'].items()
resp = http.request('GET', url).json()
per_provider = resp['allocations'].items()
fields = ('resource_provider', 'generation', 'resources')
allocs = [dict(resource_provider=k, **v) for k, v in per_provider]
if self.compare_version(version.ge('1.12')):
fields += ('project_id', 'user_id')
[alloc.update(project_id=resp['project_id'],
user_id=resp['user_id'])
for alloc in allocs]
fields_ext = ('resource_provider', ) + FIELDS
rows = (utils.get_dict_properties(a, fields_ext) for a in allocs)
return fields_ext, rows
rows = (utils.get_dict_properties(a, fields) for a in allocs)
return fields, rows
class ShowAllocation(command.Lister):
"""Show resource allocations for a given consumer."""
class ShowAllocation(command.Lister, version.CheckerMixin):
"""Show resource allocations for a given consumer.
Starting with ``--os-placement-api-version 1.12`` the API response contains
the project_id and user_id of allocations which also appears in the CLI
output.
"""
def get_parser(self, prog_name):
parser = super(ShowAllocation, self).get_parser(prog_name)
@ -141,12 +163,23 @@ class ShowAllocation(command.Lister):
http = self.app.client_manager.placement
url = BASE_URL + '/' + parsed_args.uuid
per_provider = http.request('GET', url).json()['allocations'].items()
allocs = [dict(resource_provider=k, **v) for k, v in per_provider]
resp = http.request('GET', url).json()
per_provider = resp['allocations'].items()
if self.compare_version(version.ge('1.12')):
allocs = [dict(
resource_provider=k,
project_id=resp['project_id'],
user_id=resp['user_id'],
**v) for k, v in per_provider]
else:
allocs = [dict(resource_provider=k, **v) for k, v in per_provider]
fields_ext = ('resource_provider', ) + FIELDS
rows = (utils.get_dict_properties(a, fields_ext) for a in allocs)
return fields_ext, rows
fields = ('resource_provider', 'generation', 'resources')
if self.compare_version(version.ge('1.12')):
fields += ('project_id', 'user_id')
rows = (utils.get_dict_properties(a, fields) for a in allocs)
return fields, rows
class DeleteAllocation(command.Command):

View File

@ -88,13 +88,22 @@ class ListAllocationCandidate(command.Lister, version.CheckerMixin):
rps[rp_uuid] = ','.join(
'%s=%s/%s' % (rc, value['used'], value['capacity'])
for rc, value in resources['resources'].items())
rows = []
for i, allocation_req in enumerate(resp['allocation_requests']):
for allocation in allocation_req['allocations']:
rp = allocation['resource_provider']['uuid']
req = ','.join(
'%s=%s' % (rc, value)
for rc, value in allocation['resources'].items())
rows.append([i + 1, req, rp, rps[rp]])
if self.compare_version(version.ge('1.12')):
for i, allocation_req in enumerate(resp['allocation_requests']):
for rp, resources in allocation_req['allocations'].items():
req = ','.join(
'%s=%s' % (rc, value)
for rc, value in resources['resources'].items())
rows.append([i + 1, req, rp, rps[rp]])
else:
for i, allocation_req in enumerate(resp['allocation_requests']):
for allocation in allocation_req['allocations']:
rp = allocation['resource_provider']['uuid']
req = ','.join(
'%s=%s' % (rc, value)
for rc, value in allocation['resources'].items())
rows.append([i + 1, req, rp, rps[rp]])
return FIELDS, rows

View File

@ -126,3 +126,41 @@ class TestAllocation18(base.BaseTestCase):
]
self.assertEqual(expected, created_alloc)
self.assertEqual(expected, retrieved_alloc)
class TestAllocation112(base.BaseTestCase):
VERSION = '1.12'
def setUp(self):
super(TestAllocation112, self).setUp()
self.rp1 = self.resource_provider_create()
self.inv_cpu1 = self.resource_inventory_set(
self.rp1['uuid'],
'VCPU=4',
'VCPU:max_unit=4',
'MEMORY_MB=1024',
'MEMORY_MB:max_unit=1024')
def test_allocation_update(self):
consumer_uuid = str(uuid.uuid4())
project_uuid = str(uuid.uuid4())
user_uuid = str(uuid.uuid4())
created_alloc = self.resource_allocation_set(
consumer_uuid,
['rp={},VCPU=2'.format(self.rp1['uuid']),
'rp={},MEMORY_MB=512'.format(self.rp1['uuid'])],
project_id=project_uuid, user_id=user_uuid
)
retrieved_alloc = self.resource_allocation_show(consumer_uuid)
expected = [
{'resource_provider': self.rp1['uuid'],
'generation': 2,
'project_id': project_uuid,
'user_id': user_uuid,
'resources': {'VCPU': 2, 'MEMORY_MB': 512}}
]
self.assertEqual(expected, created_alloc)
self.assertEqual(expected, retrieved_alloc)

View File

@ -90,3 +90,7 @@ class TestAllocationCandidate(base.BaseTestCase):
def test_fail_if_unknown_rc(self):
self.assertCommandFailed(
'No such resource', self.allocation_candidate_list, 'UNKNOWN=10')
class TestAllocationCandidate112(TestAllocationCandidate):
VERSION = '1.12'

View File

@ -26,6 +26,8 @@ SUPPORTED_VERSIONS = [
'1.8',
'1.9',
'1.10',
'1.11',
'1.12'
]