[placement] add two ways to GET allocations
Add two resources on the placement api for retrieving allocations. One, /resource_providers/{uuid}/allocations, returns all the allocations currently against this resource provider in this format: {'resource_provider_generation': GENERATION, 'allocations': CONSUMER_ID_1: { 'resources': { 'DISK_GB': 4, 'VCPU': 2 } }, CONSUMER_ID_2: { 'resources': { 'DISK_GB': 6, 'VCPU': 3 } } } Another, /allocations/{consumer_id}, returns all the allocations for the current consumer in this format: {'allocations': RP_UUID_1: { 'generation': GENERATION, 'resources': { 'DISK_GB': 4, 'VCPU': 2 } }, RP_UUID_2: { 'generation': GENERATION, 'resources': { 'DISK_GB': 6, 'VCPU': 3 } } } The formats are eminently usable on the client side, by having a comparable dict reachable by a predictable key, but not self describing (we don't know that the keys are consumer ids or resource uuids). In the first format the descent into a resources key is to maintain parity with the second format and provide room for expansion. Change-Id: I69fbc4e9834ec6dc80dacf43f8fd9dc6ec139006 Closes-Bug: #1621059
This commit is contained in:
parent
2bd800ce25
commit
eab8100b42
|
@ -70,7 +70,11 @@ ROUTE_DECLARATIONS = {
|
|||
'/resource_providers/{uuid}/usages': {
|
||||
'GET': usage.list_usages
|
||||
},
|
||||
'/resource_providers/{uuid}/allocations': {
|
||||
'GET': allocation.list_for_resource_provider,
|
||||
},
|
||||
'/allocations/{consumer_uuid}': {
|
||||
'GET': allocation.list_for_consumer,
|
||||
'PUT': allocation.set_allocations,
|
||||
'DELETE': allocation.delete_allocations,
|
||||
},
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
# under the License.
|
||||
"""Placement API handlers for setting and deleting allocations."""
|
||||
|
||||
import collections
|
||||
|
||||
import jsonschema
|
||||
from oslo_serialization import jsonutils
|
||||
import webob
|
||||
|
@ -62,6 +64,28 @@ ALLOCATION_SCHEMA = {
|
|||
}
|
||||
|
||||
|
||||
def _allocations_dict(allocations, key_fetcher, resource_provider=None):
|
||||
"""Turn allocations into a dict of resources keyed by key_fetcher."""
|
||||
allocation_data = collections.defaultdict(dict)
|
||||
|
||||
for allocation in allocations:
|
||||
key = key_fetcher(allocation)
|
||||
if 'resources' not in allocation_data[key]:
|
||||
allocation_data[key]['resources'] = {}
|
||||
|
||||
resource_class = allocation.resource_class
|
||||
allocation_data[key]['resources'][resource_class] = allocation.used
|
||||
|
||||
if not resource_provider:
|
||||
generation = allocation.resource_provider.generation
|
||||
allocation_data[key]['generation'] = generation
|
||||
|
||||
result = {'allocations': allocation_data}
|
||||
if resource_provider:
|
||||
result['resource_provider_generation'] = resource_provider.generation
|
||||
return result
|
||||
|
||||
|
||||
def _extract_allocations(body, schema):
|
||||
"""Extract allocation data from a JSON body."""
|
||||
try:
|
||||
|
@ -80,6 +104,111 @@ def _extract_allocations(body, schema):
|
|||
return data
|
||||
|
||||
|
||||
def _serialize_allocations_for_consumer(allocations):
|
||||
"""Turn a list of allocations into a dict by resource provider uuid.
|
||||
|
||||
{'allocations':
|
||||
RP_UUID_1: {
|
||||
'generation': GENERATION,
|
||||
'resources': {
|
||||
'DISK_GB': 4,
|
||||
'VCPU': 2
|
||||
}
|
||||
},
|
||||
RP_UUID_2: {
|
||||
'generation': GENERATION,
|
||||
'resources': {
|
||||
'DISK_GB': 6,
|
||||
'VCPU': 3
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
return _allocations_dict(allocations,
|
||||
lambda x: x.resource_provider.uuid)
|
||||
|
||||
|
||||
def _serialize_allocations_for_resource_provider(allocations,
|
||||
resource_provider):
|
||||
"""Turn a list of allocations into a dict by consumer id.
|
||||
|
||||
{'resource_provider_generation': GENERATION,
|
||||
'allocations':
|
||||
CONSUMER_ID_1: {
|
||||
'resources': {
|
||||
'DISK_GB': 4,
|
||||
'VCPU': 2
|
||||
}
|
||||
},
|
||||
CONSUMER_ID_2: {
|
||||
'resources': {
|
||||
'DISK_GB': 6,
|
||||
'VCPU': 3
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
return _allocations_dict(allocations, lambda x: x.consumer_id,
|
||||
resource_provider=resource_provider)
|
||||
|
||||
|
||||
@webob.dec.wsgify
|
||||
@util.check_accept('application/json')
|
||||
def list_for_consumer(req):
|
||||
"""List allocations associated with a consumer."""
|
||||
context = req.environ['placement.context']
|
||||
consumer_id = util.wsgi_path_item(req.environ, 'consumer_uuid')
|
||||
|
||||
# NOTE(cdent): There is no way for a 404 to be returned here,
|
||||
# only an empty result. We do not have a way to validate a
|
||||
# consumer id.
|
||||
allocations = objects.AllocationList.get_all_by_consumer_id(
|
||||
context, consumer_id)
|
||||
|
||||
allocations_json = jsonutils.dumps(
|
||||
_serialize_allocations_for_consumer(allocations))
|
||||
|
||||
req.response.status = 200
|
||||
req.response.body = allocations_json
|
||||
req.response.content_type = 'application/json'
|
||||
return req.response
|
||||
|
||||
|
||||
@webob.dec.wsgify
|
||||
@util.check_accept('application/json')
|
||||
def list_for_resource_provider(req):
|
||||
"""List allocations associated with a resource provider."""
|
||||
# TODO(cdent): On a shared resource provider (for example a
|
||||
# giant disk farm) this list could get very long. At the moment
|
||||
# we have no facility for limiting the output. Given that we are
|
||||
# using a dict of dicts for the output we are potentially limiting
|
||||
# ourselves in terms of sorting and filtering.
|
||||
context = req.environ['placement.context']
|
||||
uuid = util.wsgi_path_item(req.environ, 'uuid')
|
||||
|
||||
# confirm existence of resource provider so we get a reasonable
|
||||
# 404 instead of empty list
|
||||
try:
|
||||
resource_provider = objects.ResourceProvider.get_by_uuid(
|
||||
context, uuid)
|
||||
except exception.NotFound as exc:
|
||||
raise webob.exc.HTTPNotFound(
|
||||
"Resource provider '%s' not found: %s" % (uuid, exc),
|
||||
json_formatter=util.json_error_formatter)
|
||||
|
||||
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
||||
context, uuid)
|
||||
|
||||
allocations_json = jsonutils.dumps(
|
||||
_serialize_allocations_for_resource_provider(
|
||||
allocations, resource_provider))
|
||||
|
||||
req.response.status = 200
|
||||
req.response.body = allocations_json
|
||||
req.response.content_type = 'application/json'
|
||||
return req.response
|
||||
|
||||
|
||||
@webob.dec.wsgify
|
||||
@util.require_content('application/json')
|
||||
def set_allocations(req):
|
||||
|
|
|
@ -18,11 +18,10 @@ tests:
|
|||
GET: /allocations
|
||||
status: 404
|
||||
|
||||
- name: get allocations is 405
|
||||
- name: get allocations is empty dict
|
||||
GET: /allocations/599ffd2d-526a-4b2e-8683-f13ad25f9958
|
||||
status: 405
|
||||
response_headers:
|
||||
allow: /(PUT, DELETE|DELETE, PUT)/
|
||||
response_json_paths:
|
||||
$.allocations: {}
|
||||
|
||||
- name: put an allocation no resource provider
|
||||
PUT: /allocations/599ffd2d-526a-4b2e-8683-f13ad25f9958
|
||||
|
@ -200,3 +199,144 @@ tests:
|
|||
response_json_paths:
|
||||
$.resource_provider_generation: 7
|
||||
$.usages.DISK_GB: 40
|
||||
|
||||
- name: check allocations for the resource provider
|
||||
GET: /resource_providers/$ENVIRON['RP_UUID']/allocations
|
||||
response_json_paths:
|
||||
$.resource_provider_generation: 7
|
||||
# allocations are keyed by consumer id, jsonpath-rw needs us
|
||||
# to quote the uuids or its parser gets confused that maybe
|
||||
# they are numbers on which math needs to be done.
|
||||
$.allocations['833f0885-f78c-4788-bb2b-3607b0656be7'].resources.DISK_GB: 20
|
||||
$.allocations['833f0885-f78c-4788-bb2b-3607b0656be7'].resources.VCPU: 4
|
||||
$.allocations['599ffd2d-526a-4b2e-8683-f13ad25f9958'].resources.DISK_GB: 10
|
||||
$.allocations['39715579-2167-4c63-8247-301311cc6703'].resources.DISK_GB: 10
|
||||
|
||||
- name: confirm 404 for allocations of bad resource provider
|
||||
GET: /resource_providers/cb8a3007-b93a-471f-9e1f-4d58355678bd/allocations
|
||||
status: 404
|
||||
|
||||
- name: check allocations by consumer id
|
||||
GET: /allocations/833f0885-f78c-4788-bb2b-3607b0656be7
|
||||
response_json_paths:
|
||||
# TODO(cdent): Can't currently do substituion on left hand
|
||||
# side of json path in gabbi, a bug has been made. In the
|
||||
# meantime we have to jump over it. This works because we only
|
||||
# have one resource provider in this output.
|
||||
$.allocations..generation: 7
|
||||
$.allocations..resources.DISK_GB: 20
|
||||
$.allocations..resources.VCPU: 4
|
||||
|
||||
- name: check allocations by diferent consumer id
|
||||
GET: /allocations/599ffd2d-526a-4b2e-8683-f13ad25f9958
|
||||
response_json_paths:
|
||||
# TODO(cdent): Can't currently do substituion on left hand
|
||||
# side of json path in gabbi, a bug has been made. In the
|
||||
# meantime we have to jump over the resource provider (which
|
||||
# we don't know as a static value). This works because we only
|
||||
# have one resource provider in this output.
|
||||
$.allocations..generation: 7
|
||||
$.allocations..DISK_GB: 10
|
||||
|
||||
# - name: create another two resource providers
|
||||
- name: create resource provider 1
|
||||
POST: /resource_providers
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
name: rp1
|
||||
uuid: 9229b2fc-d556-4e38-9c18-443e4bc6ceae
|
||||
status: 201
|
||||
|
||||
- name: create resource provider 2
|
||||
POST: /resource_providers
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
name: rp2
|
||||
uuid: fcfa516a-abbe-45d1-8152-d5225d82e596
|
||||
status: 201
|
||||
|
||||
- name: set inventory on rp1
|
||||
PUT: /resource_providers/9229b2fc-d556-4e38-9c18-443e4bc6ceae/inventories
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
# TODO(cdent): This format is going to go out of date because
|
||||
# of other changes
|
||||
resource_provider_generation: 0
|
||||
inventories:
|
||||
- resource_class: VCPU
|
||||
total: 32
|
||||
- resource_class: DISK_GB
|
||||
total: 10
|
||||
|
||||
- name: set inventory on rp2
|
||||
PUT: /resource_providers/fcfa516a-abbe-45d1-8152-d5225d82e596/inventories
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
# TODO(cdent): This format is going to go out of date because
|
||||
# of other changes
|
||||
resource_provider_generation: 0
|
||||
inventories:
|
||||
- resource_class: VCPU
|
||||
total: 16
|
||||
- resource_class: DISK_GB
|
||||
total: 20
|
||||
status: 200
|
||||
|
||||
- name: put allocations on both those providers one
|
||||
PUT: /allocations/1835b1c9-1c61-45af-9eb3-3e0e9f29487b
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
allocations:
|
||||
- resource_provider:
|
||||
uuid: fcfa516a-abbe-45d1-8152-d5225d82e596
|
||||
resources:
|
||||
DISK_GB: 10
|
||||
VCPU: 8
|
||||
- resource_provider:
|
||||
uuid: 9229b2fc-d556-4e38-9c18-443e4bc6ceae
|
||||
resources:
|
||||
DISK_GB: 5
|
||||
VCPU: 16
|
||||
status: 204
|
||||
|
||||
- name: put allocations on both those providers two
|
||||
PUT: /allocations/75d0f5f7-75d9-458c-b204-f90ac91604ec
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
allocations:
|
||||
- resource_provider:
|
||||
uuid: fcfa516a-abbe-45d1-8152-d5225d82e596
|
||||
resources:
|
||||
DISK_GB: 5
|
||||
VCPU: 4
|
||||
- resource_provider:
|
||||
uuid: 9229b2fc-d556-4e38-9c18-443e4bc6ceae
|
||||
resources:
|
||||
DISK_GB: 2
|
||||
VCPU: 8
|
||||
status: 204
|
||||
|
||||
- name: get those allocations for consumer
|
||||
GET: /allocations/1835b1c9-1c61-45af-9eb3-3e0e9f29487b
|
||||
response_json_paths:
|
||||
$.allocations.['fcfa516a-abbe-45d1-8152-d5225d82e596'].generation: 3
|
||||
$.allocations.['fcfa516a-abbe-45d1-8152-d5225d82e596'].resources.DISK_GB: 10
|
||||
$.allocations.['fcfa516a-abbe-45d1-8152-d5225d82e596'].resources.VCPU: 8
|
||||
$.allocations.['9229b2fc-d556-4e38-9c18-443e4bc6ceae'].generation: 3
|
||||
$.allocations.['9229b2fc-d556-4e38-9c18-443e4bc6ceae'].resources.DISK_GB: 5
|
||||
$.allocations.['9229b2fc-d556-4e38-9c18-443e4bc6ceae'].resources.VCPU: 16
|
||||
|
||||
- name: get those allocations for resource provider
|
||||
GET: /resource_providers/fcfa516a-abbe-45d1-8152-d5225d82e596/allocations
|
||||
response_json_paths:
|
||||
$.resource_provider_generation: 3
|
||||
$.allocations.['75d0f5f7-75d9-458c-b204-f90ac91604ec'].resources.DISK_GB: 5
|
||||
$.allocations.['75d0f5f7-75d9-458c-b204-f90ac91604ec'].resources.VCPU: 4
|
||||
$.allocations.['1835b1c9-1c61-45af-9eb3-3e0e9f29487b'].resources.DISK_GB: 10
|
||||
$.allocations.['1835b1c9-1c61-45af-9eb3-3e0e9f29487b'].resources.VCPU: 8
|
||||
|
|
Loading…
Reference in New Issue