[placement] POST /allocations to set allocations for >1 consumers
This provides microversion 1.13 of the placement API, giving the ability to POST to /allocations to set (or clear) allocations for more than one consumer uuid. It builds on the recent work to support a dict-based JSON format when doing a PUT to /allocations/{consumer_uuid}. Being able to set allocations for multiple consumers in one request helps to address race conditions when cleaning up allocations during move operations in nova. Clearing allocations is done by setting the 'allocations' key for a specific consumer to an empty dict. Updates to placement-api-ref, rest version history and a reno are included. Change-Id: I239f33841bb9fcd92b406f979674ae8c5f8d57e3 Implements: bp post-allocations
This commit is contained in:
parent
b60a599b5f
commit
8caf4f5148
@ -100,9 +100,12 @@ ROUTE_DECLARATIONS = {
|
||||
'/resource_providers/{uuid}/allocations': {
|
||||
'GET': allocation.list_for_resource_provider,
|
||||
},
|
||||
'/allocations': {
|
||||
'POST': allocation.set_allocations,
|
||||
},
|
||||
'/allocations/{consumer_uuid}': {
|
||||
'GET': allocation.list_for_consumer,
|
||||
'PUT': allocation.set_allocations,
|
||||
'PUT': allocation.set_allocations_for_consumer,
|
||||
'DELETE': allocation.delete_allocations,
|
||||
},
|
||||
'/allocation_candidates': {
|
||||
|
@ -138,6 +138,24 @@ ALLOCATION_SCHEMA_V1_12 = {
|
||||
}
|
||||
|
||||
|
||||
# POST to /allocations, added in microversion 1.13, uses the
|
||||
# POST_ALLOCATIONS_V1_13 schema to allow multiple allocations
|
||||
# from multiple consumers in one request. It is a dict, keyed by
|
||||
# consumer uuid, using the form of PUT allocations from microversion
|
||||
# 1.12. In POST the allocations can be empty, so DELETABLE_ALLOCATIONS
|
||||
# modifies ALLOCATION_SCHEMA_V1_12 accordingly.
|
||||
DELETABLE_ALLOCATIONS = copy.deepcopy(ALLOCATION_SCHEMA_V1_12)
|
||||
DELETABLE_ALLOCATIONS['properties']['allocations']['minProperties'] = 0
|
||||
POST_ALLOCATIONS_V1_13 = {
|
||||
"type": "object",
|
||||
"minProperties": 1,
|
||||
"additionalProperties": False,
|
||||
"patternProperties": {
|
||||
"^[0-9a-fA-F-]{36}$": DELETABLE_ALLOCATIONS
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def _allocations_dict(allocations, key_fetcher, resource_provider=None,
|
||||
want_version=None):
|
||||
"""Turn allocations into a dict of resources keyed by key_fetcher."""
|
||||
@ -277,7 +295,42 @@ def list_for_resource_provider(req):
|
||||
return req.response
|
||||
|
||||
|
||||
def _set_allocations(req, schema):
|
||||
def _new_allocations(context, resource_provider_uuid, consumer_uuid,
|
||||
resources, project_id, user_id):
|
||||
"""Create new allocation objects for a set of resources
|
||||
|
||||
Returns a list of Allocation objects.
|
||||
|
||||
:param context: The placement context.
|
||||
:param resource_provider_uuid: The uuid of the resource provider that
|
||||
has the resources.
|
||||
:param consumer_uuid: The uuid of the consumer of the resources.
|
||||
:param resources: A dict of resource classes and values.
|
||||
:param project_id: The project consuming the resources.
|
||||
:param user_id: The user consuming the resources.
|
||||
"""
|
||||
allocations = []
|
||||
try:
|
||||
resource_provider = rp_obj.ResourceProvider.get_by_uuid(
|
||||
context, resource_provider_uuid)
|
||||
except exception.NotFound:
|
||||
raise webob.exc.HTTPBadRequest(
|
||||
_("Allocation for resource provider '%(rp_uuid)s' "
|
||||
"that does not exist.") %
|
||||
{'rp_uuid': resource_provider_uuid})
|
||||
for resource_class in resources:
|
||||
allocation = rp_obj.Allocation(
|
||||
resource_provider=resource_provider,
|
||||
consumer_id=consumer_uuid,
|
||||
resource_class=resource_class,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
used=resources[resource_class])
|
||||
allocations.append(allocation)
|
||||
return allocations
|
||||
|
||||
|
||||
def _set_allocations_for_consumer(req, schema):
|
||||
context = req.environ['placement.context']
|
||||
consumer_uuid = util.wsgi_path_item(req.environ, 'consumer_uuid')
|
||||
data = util.extract_json(req.body, schema)
|
||||
@ -299,25 +352,13 @@ def _set_allocations(req, schema):
|
||||
# that does not exist, raise a 400.
|
||||
allocation_objects = []
|
||||
for resource_provider_uuid, allocation in allocation_data.items():
|
||||
try:
|
||||
resource_provider = rp_obj.ResourceProvider.get_by_uuid(
|
||||
context, resource_provider_uuid)
|
||||
except exception.NotFound:
|
||||
raise webob.exc.HTTPBadRequest(
|
||||
_("Allocation for resource provider '%(rp_uuid)s' "
|
||||
"that does not exist.") %
|
||||
{'rp_uuid': resource_provider_uuid})
|
||||
|
||||
resources = allocation['resources']
|
||||
for resource_class in resources:
|
||||
allocation = rp_obj.Allocation(
|
||||
resource_provider=resource_provider,
|
||||
consumer_id=consumer_uuid,
|
||||
resource_class=resource_class,
|
||||
project_id=data.get('project_id'),
|
||||
user_id=data.get('user_id'),
|
||||
used=resources[resource_class])
|
||||
allocation_objects.append(allocation)
|
||||
new_allocations = _new_allocations(context,
|
||||
resource_provider_uuid,
|
||||
consumer_uuid,
|
||||
allocation['resources'],
|
||||
data.get('project_id'),
|
||||
data.get('user_id'))
|
||||
allocation_objects.extend(new_allocations)
|
||||
|
||||
allocations = rp_obj.AllocationList(
|
||||
context, objects=allocation_objects)
|
||||
@ -349,22 +390,84 @@ def _set_allocations(req, schema):
|
||||
@wsgi_wrapper.PlacementWsgify
|
||||
@microversion.version_handler('1.0', '1.7')
|
||||
@util.require_content('application/json')
|
||||
def set_allocations(req):
|
||||
return _set_allocations(req, ALLOCATION_SCHEMA)
|
||||
def set_allocations_for_consumer(req):
|
||||
return _set_allocations_for_consumer(req, ALLOCATION_SCHEMA)
|
||||
|
||||
|
||||
@wsgi_wrapper.PlacementWsgify # noqa
|
||||
@microversion.version_handler('1.8', '1.11')
|
||||
@util.require_content('application/json')
|
||||
def set_allocations(req):
|
||||
return _set_allocations(req, ALLOCATION_SCHEMA_V1_8)
|
||||
def set_allocations_for_consumer(req):
|
||||
return _set_allocations_for_consumer(req, ALLOCATION_SCHEMA_V1_8)
|
||||
|
||||
|
||||
@wsgi_wrapper.PlacementWsgify # noqa
|
||||
@microversion.version_handler('1.12')
|
||||
@util.require_content('application/json')
|
||||
def set_allocations_for_consumer(req):
|
||||
return _set_allocations_for_consumer(req, ALLOCATION_SCHEMA_V1_12)
|
||||
|
||||
|
||||
@wsgi_wrapper.PlacementWsgify
|
||||
@microversion.version_handler('1.13')
|
||||
@util.require_content('application/json')
|
||||
def set_allocations(req):
|
||||
return _set_allocations(req, ALLOCATION_SCHEMA_V1_12)
|
||||
context = req.environ['placement.context']
|
||||
data = util.extract_json(req.body, POST_ALLOCATIONS_V1_13)
|
||||
|
||||
# Create a sequence of allocation objects to be used in an
|
||||
# AllocationList.create_all() call, which will mean all the changes
|
||||
# happen within a single transaction and with resource provider
|
||||
# generations check all in one go.
|
||||
allocation_objects = []
|
||||
|
||||
for consumer_uuid in data:
|
||||
project_id = data[consumer_uuid]['project_id']
|
||||
user_id = data[consumer_uuid]['user_id']
|
||||
allocations = data[consumer_uuid]['allocations']
|
||||
if allocations:
|
||||
for resource_provider_uuid in allocations:
|
||||
resources = allocations[resource_provider_uuid]['resources']
|
||||
new_allocations = _new_allocations(context,
|
||||
resource_provider_uuid,
|
||||
consumer_uuid,
|
||||
resources,
|
||||
project_id,
|
||||
user_id)
|
||||
allocation_objects.extend(new_allocations)
|
||||
else:
|
||||
# The allocations are empty, which means wipe them out.
|
||||
# Internal to the allocation object this is signalled by a
|
||||
# used value of 0.
|
||||
allocations = rp_obj.AllocationList.get_all_by_consumer_id(
|
||||
context, consumer_uuid)
|
||||
for allocation in allocations:
|
||||
allocation.used = 0
|
||||
allocation_objects.append(allocation)
|
||||
|
||||
allocations = rp_obj.AllocationList(
|
||||
context, objects=allocation_objects)
|
||||
|
||||
try:
|
||||
allocations.create_all()
|
||||
LOG.debug("Successfully wrote allocations %s", allocations)
|
||||
except exception.NotFound as exc:
|
||||
raise webob.exc.HTTPBadRequest(
|
||||
_("Unable to allocate inventory %(error)s") % {'error': exc})
|
||||
except exception.InvalidInventory as exc:
|
||||
# InvalidInventory is a parent for several exceptions that
|
||||
# indicate either that Inventory is not present, or that
|
||||
# capacity limits have been exceeded.
|
||||
raise webob.exc.HTTPConflict(
|
||||
_('Unable to allocate inventory: %(error)s') % {'error': exc})
|
||||
except exception.ConcurrentUpdateDetected as exc:
|
||||
raise webob.exc.HTTPConflict(
|
||||
_('Inventory changed while attempting to allocate: %(error)s') %
|
||||
{'error': exc})
|
||||
|
||||
req.response.status = 204
|
||||
req.response.content_type = None
|
||||
return req.response
|
||||
|
||||
|
||||
@wsgi_wrapper.PlacementWsgify
|
||||
|
@ -52,6 +52,7 @@ VERSIONS = [
|
||||
'1.12', # Add project_id and user_id to GET /allocations/{consumer_uuid}
|
||||
# and PUT to /allocations/{consumer_uuid} in the same dict form
|
||||
# as GET
|
||||
'1.13', # Adds POST /allocations to set allocations for multiple consumers
|
||||
]
|
||||
|
||||
|
||||
|
@ -172,3 +172,9 @@ response body. Because the `PUT` request requires `user_id` and
|
||||
response. In addition, the response body for ``GET /allocation_candidates``
|
||||
is updated so the allocations in the ``alocation_requests`` object work
|
||||
with the new `PUT` format.
|
||||
|
||||
1.13 POST multiple allocations to /allocations
|
||||
----------------------------------------------
|
||||
|
||||
Version 1.13 gives the ability to set or clear allocations for more than
|
||||
one consumer uuid with a request to ``POST /allocations``.
|
||||
|
@ -80,6 +80,11 @@ class APIFixture(fixture.GabbiFixture):
|
||||
os.environ['CUSTOM_RES_CLASS'] = 'CUSTOM_IRON_NFV'
|
||||
os.environ['PROJECT_ID'] = uuidutils.generate_uuid()
|
||||
os.environ['USER_ID'] = uuidutils.generate_uuid()
|
||||
os.environ['PROJECT_ID_ALT'] = uuidutils.generate_uuid()
|
||||
os.environ['USER_ID_ALT'] = uuidutils.generate_uuid()
|
||||
os.environ['INSTANCE_UUID'] = uuidutils.generate_uuid()
|
||||
os.environ['MIGRATION_UUID'] = uuidutils.generate_uuid()
|
||||
os.environ['CONSUMER_UUID'] = uuidutils.generate_uuid()
|
||||
|
||||
def stop_fixture(self):
|
||||
self.api_db_fixture.cleanup()
|
||||
|
@ -0,0 +1,288 @@
|
||||
# Test that it possible to POST multiple allocations to /allocations to
|
||||
# simultaneously make changes, including removing resources for a consumer if
|
||||
# the allocations are empty.
|
||||
|
||||
fixtures:
|
||||
- APIFixture
|
||||
|
||||
defaults:
|
||||
request_headers:
|
||||
x-auth-token: admin
|
||||
accept: application/json
|
||||
content-type: application/json
|
||||
openstack-api-version: placement 1.13
|
||||
|
||||
tests:
|
||||
|
||||
- name: create compute one
|
||||
POST: /resource_providers
|
||||
data:
|
||||
name: compute01
|
||||
status: 201
|
||||
|
||||
- name: rp compute01
|
||||
desc: provide a reference for later reuse
|
||||
GET: $LOCATION
|
||||
|
||||
- name: create compute two
|
||||
POST: /resource_providers
|
||||
data:
|
||||
name: compute02
|
||||
status: 201
|
||||
|
||||
- name: rp compute02
|
||||
desc: provide a reference for later reuse
|
||||
GET: $LOCATION
|
||||
|
||||
- name: create shared disk
|
||||
POST: /resource_providers
|
||||
data:
|
||||
name: storage01
|
||||
status: 201
|
||||
|
||||
- name: rp storage01
|
||||
desc: provide a reference for later reuse
|
||||
GET: $LOCATION
|
||||
|
||||
- name: inventory compute01
|
||||
PUT: $HISTORY['rp compute01'].$RESPONSE['links[?rel = "inventories"].href']
|
||||
data:
|
||||
resource_provider_generation: 0
|
||||
inventories:
|
||||
VCPU:
|
||||
total: 16
|
||||
MEMORY_MB:
|
||||
total: 2048
|
||||
|
||||
- name: inventory compute02
|
||||
PUT: $HISTORY['rp compute02'].$RESPONSE['links[?rel = "inventories"].href']
|
||||
data:
|
||||
resource_provider_generation: 0
|
||||
inventories:
|
||||
VCPU:
|
||||
total: 16
|
||||
MEMORY_MB:
|
||||
total: 2048
|
||||
|
||||
- name: inventory storage01
|
||||
PUT: $HISTORY['rp storage01'].$RESPONSE['links[?rel = "inventories"].href']
|
||||
data:
|
||||
resource_provider_generation: 0
|
||||
inventories:
|
||||
DISK_GB:
|
||||
total: 4096
|
||||
|
||||
- name: confirm only POST
|
||||
GET: /allocations
|
||||
status: 405
|
||||
response_headers:
|
||||
allow: POST
|
||||
|
||||
- name: 404 on older 1.12 microversion post
|
||||
POST: /allocations
|
||||
request_headers:
|
||||
openstack-api-version: placement 1.12
|
||||
status: 404
|
||||
|
||||
- name: post allocations two consumers
|
||||
POST: /allocations
|
||||
data:
|
||||
$ENVIRON['INSTANCE_UUID']:
|
||||
allocations:
|
||||
$HISTORY['rp compute02'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
MEMORY_MB: 1024
|
||||
VCPU: 2
|
||||
$HISTORY['rp storage01'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
DISK_GB: 5
|
||||
project_id: $ENVIRON['PROJECT_ID']
|
||||
user_id: $ENVIRON['USER_ID']
|
||||
$ENVIRON['MIGRATION_UUID']:
|
||||
allocations:
|
||||
$HISTORY['rp compute01'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
MEMORY_MB: 1024
|
||||
VCPU: 2
|
||||
project_id: $ENVIRON['PROJECT_ID']
|
||||
user_id: $ENVIRON['USER_ID']
|
||||
status: 204
|
||||
|
||||
- name: confirm usages
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
response_json_paths:
|
||||
$.usages.DISK_GB: 5
|
||||
$.usages.VCPU: 4
|
||||
$.usages.MEMORY_MB: 2048
|
||||
|
||||
- name: clear and set allocations
|
||||
POST: /allocations
|
||||
data:
|
||||
$ENVIRON['INSTANCE_UUID']:
|
||||
allocations:
|
||||
$HISTORY['rp compute02'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
MEMORY_MB: 1024
|
||||
VCPU: 2
|
||||
$HISTORY['rp storage01'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
DISK_GB: 5
|
||||
project_id: $ENVIRON['PROJECT_ID']
|
||||
user_id: $ENVIRON['USER_ID']
|
||||
$ENVIRON['MIGRATION_UUID']:
|
||||
allocations: {}
|
||||
project_id: $ENVIRON['PROJECT_ID']
|
||||
user_id: $ENVIRON['USER_ID']
|
||||
status: 204
|
||||
|
||||
- name: confirm usages after clear
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
response_json_paths:
|
||||
$.usages.DISK_GB: 5
|
||||
$.usages.VCPU: 2
|
||||
$.usages.MEMORY_MB: 1024
|
||||
|
||||
- name: post allocations two users
|
||||
POST: /allocations
|
||||
data:
|
||||
$ENVIRON['INSTANCE_UUID']:
|
||||
allocations:
|
||||
$HISTORY['rp compute02'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
MEMORY_MB: 1024
|
||||
VCPU: 2
|
||||
$HISTORY['rp storage01'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
DISK_GB: 5
|
||||
project_id: $ENVIRON['PROJECT_ID']
|
||||
user_id: $ENVIRON['USER_ID']
|
||||
# We must use a fresh consumer id with the alternate project id info.
|
||||
# A previously seen consumer id will be assumed to always have the same
|
||||
# project and user.
|
||||
$ENVIRON['CONSUMER_UUID']:
|
||||
allocations:
|
||||
$HISTORY['rp compute01'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
MEMORY_MB: 1024
|
||||
VCPU: 2
|
||||
project_id: $ENVIRON['PROJECT_ID_ALT']
|
||||
user_id: $ENVIRON['USER_ID_ALT']
|
||||
status: 204
|
||||
|
||||
- name: confirm usages user a
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
response_json_paths:
|
||||
$.usages.`len`: 3
|
||||
$.usages.DISK_GB: 5
|
||||
$.usages.VCPU: 2
|
||||
$.usages.MEMORY_MB: 1024
|
||||
|
||||
- name: confirm usages user b
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID_ALT']
|
||||
response_json_paths:
|
||||
$.usages.`len`: 2
|
||||
$.usages.VCPU: 2
|
||||
$.usages.MEMORY_MB: 1024
|
||||
|
||||
- name: fail allocations over capacity
|
||||
POST: /allocations
|
||||
data:
|
||||
$ENVIRON['INSTANCE_UUID']:
|
||||
allocations:
|
||||
$HISTORY['rp compute02'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
MEMORY_MB: 1024
|
||||
VCPU: 2
|
||||
$HISTORY['rp storage01'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
DISK_GB: 5
|
||||
project_id: $ENVIRON['PROJECT_ID']
|
||||
user_id: $ENVIRON['USER_ID']
|
||||
$ENVIRON['CONSUMER_UUID']:
|
||||
allocations:
|
||||
$HISTORY['rp compute01'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
MEMORY_MB: 2049
|
||||
VCPU: 2
|
||||
project_id: $ENVIRON['PROJECT_ID_ALT']
|
||||
user_id: $ENVIRON['USER_ID_ALT']
|
||||
status: 409
|
||||
response_strings:
|
||||
- The requested amount would exceed the capacity
|
||||
|
||||
- name: fail allocations deep schema violate
|
||||
desc: no schema yet
|
||||
POST: /allocations
|
||||
data:
|
||||
$ENVIRON['INSTANCE_UUID']:
|
||||
allocations:
|
||||
$HISTORY['rp compute02'].$RESPONSE['uuid']:
|
||||
cow: moo
|
||||
project_id: $ENVIRON['PROJECT_ID']
|
||||
user_id: $ENVIRON['USER_ID']
|
||||
status: 400
|
||||
|
||||
- name: fail allocations shallow schema violate
|
||||
desc: no schema yet
|
||||
POST: /allocations
|
||||
data:
|
||||
$ENVIRON['INSTANCE_UUID']:
|
||||
cow: moo
|
||||
status: 400
|
||||
|
||||
- name: fail resource provider not exist
|
||||
POST: /allocations
|
||||
data:
|
||||
$ENVIRON['INSTANCE_UUID']:
|
||||
allocations:
|
||||
# this rp does not exist
|
||||
'c42def7b-498b-4442-9502-c7970b14bea4':
|
||||
resources:
|
||||
MEMORY_MB: 1024
|
||||
VCPU: 2
|
||||
$HISTORY['rp storage01'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
DISK_GB: 5
|
||||
project_id: $ENVIRON['PROJECT_ID']
|
||||
user_id: $ENVIRON['USER_ID']
|
||||
status: 400
|
||||
response_strings:
|
||||
- that does not exist
|
||||
|
||||
- name: fail resource class not in inventory
|
||||
POST: /allocations
|
||||
data:
|
||||
$ENVIRON['INSTANCE_UUID']:
|
||||
allocations:
|
||||
$HISTORY['rp compute02'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
MEMORY_MB: 1024
|
||||
VCPU: 2
|
||||
PCI_DEVICE: 1
|
||||
$HISTORY['rp storage01'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
DISK_GB: 5
|
||||
project_id: $ENVIRON['PROJECT_ID']
|
||||
user_id: $ENVIRON['USER_ID']
|
||||
status: 409
|
||||
response_strings:
|
||||
- "Inventory for 'PCI_DEVICE' on"
|
||||
|
||||
- name: fail resource class not exist
|
||||
POST: /allocations
|
||||
data:
|
||||
$ENVIRON['INSTANCE_UUID']:
|
||||
allocations:
|
||||
$HISTORY['rp compute02'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
MEMORY_MB: 1024
|
||||
VCPU: 2
|
||||
CUSTOM_PONY: 1
|
||||
$HISTORY['rp storage01'].$RESPONSE['uuid']:
|
||||
resources:
|
||||
DISK_GB: 5
|
||||
project_id: $ENVIRON['PROJECT_ID']
|
||||
user_id: $ENVIRON['USER_ID']
|
||||
status: 400
|
||||
response_strings:
|
||||
- No such resource class CUSTOM_PONY
|
@ -14,11 +14,11 @@ defaults:
|
||||
|
||||
tests:
|
||||
|
||||
- name: get allocations no consumer is 404
|
||||
- name: get allocations no consumer is 405
|
||||
GET: /allocations
|
||||
status: 404
|
||||
status: 405
|
||||
response_json_paths:
|
||||
$.errors[0].title: Not Found
|
||||
$.errors[0].title: Method Not Allowed
|
||||
|
||||
- name: get allocations is empty dict
|
||||
GET: /allocations/599ffd2d-526a-4b2e-8683-f13ad25f9958
|
||||
|
@ -39,13 +39,13 @@ tests:
|
||||
response_json_paths:
|
||||
$.errors[0].title: Not Acceptable
|
||||
|
||||
- name: latest microversion is 1.12
|
||||
- name: latest microversion is 1.13
|
||||
GET: /
|
||||
request_headers:
|
||||
openstack-api-version: placement latest
|
||||
response_headers:
|
||||
vary: /OpenStack-API-Version/
|
||||
openstack-api-version: placement 1.12
|
||||
openstack-api-version: placement 1.13
|
||||
|
||||
- name: other accept header bad version
|
||||
GET: /
|
||||
|
@ -74,7 +74,7 @@ class TestMicroversionIntersection(test.NoDBTestCase):
|
||||
# if you add two different versions of method 'foobar' the
|
||||
# number only goes up by one if no other version foobar yet
|
||||
# exists. This operates as a simple sanity check.
|
||||
TOTAL_VERSIONED_METHODS = 15
|
||||
TOTAL_VERSIONED_METHODS = 16
|
||||
|
||||
def test_methods_versioned(self):
|
||||
methods_data = microversion.VERSIONED_METHODS
|
||||
|
@ -7,6 +7,51 @@ and used by some consumer of that resource. They indicate the amount
|
||||
of a particular resource that has been allocated to a given consumer
|
||||
of that resource from a particular resource provider.
|
||||
|
||||
Manage allocations
|
||||
==================
|
||||
|
||||
Create, update or delete allocations for multiple consumers in a single
|
||||
request. This allows a client to atomically set or swap allocations for
|
||||
multiple consumers as may be required during a migration or move type
|
||||
operation.
|
||||
|
||||
The allocations for an individual consumer uuid mentioned in the request
|
||||
can be removed by setting the `allocations` to an empty object (see the
|
||||
example below).
|
||||
|
||||
**Available as of microversion 1.13.**
|
||||
|
||||
.. rest_method:: POST /allocations
|
||||
|
||||
Normal response codes: 204
|
||||
|
||||
Error response codes: badRequest(400), conflict(409)
|
||||
|
||||
* `409 Conflict` if there is no available inventory in any of the
|
||||
resource providers for any specified resource classes or inventories
|
||||
are updated by another thread while attempting the operation.
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- consumer_uuid: consumer_uuid_body
|
||||
- project_id: project_id_body
|
||||
- user_id: user_id_body
|
||||
- allocations: allocations_dict_empty
|
||||
- resources: resources
|
||||
|
||||
Request Example
|
||||
|
||||
.. literalinclude:: manage-allocations-request.json
|
||||
:language: javascript
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
No body content is returned after a successful request
|
||||
|
||||
List allocations
|
||||
================
|
||||
|
||||
|
31
placement-api-ref/source/manage-allocations-request.json
Normal file
31
placement-api-ref/source/manage-allocations-request.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"30328d13-e299-4a93-a102-61e4ccabe474": {
|
||||
"project_id": "131d4efb-abc0-4872-9b92-8c8b9dc4320f",
|
||||
"user_id": "131d4efb-abc0-4872-9b92-8c8b9dc4320f",
|
||||
"allocations": {
|
||||
"e10927c4-8bc9-465d-ac60-d2f79f7e4a00": {
|
||||
"resources": {
|
||||
"VCPU": 2,
|
||||
"MEMORY_MB": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"71921e4e-1629-4c5b-bf8d-338d915d2ef3": {
|
||||
"project_id": "131d4efb-abc0-4872-9b92-8c8b9dc4320f",
|
||||
"user_id": "131d4efb-abc0-4872-9b92-8c8b9dc4320f",
|
||||
"allocations": {}
|
||||
},
|
||||
"48c1d40f-45d8-4947-8d46-52b4e1326df8": {
|
||||
"project_id": "131d4efb-abc0-4872-9b92-8c8b9dc4320f",
|
||||
"user_id": "131d4efb-abc0-4872-9b92-8c8b9dc4320f",
|
||||
"allocations": {
|
||||
"e10927c4-8bc9-465d-ac60-d2f79f7e4a00": {
|
||||
"resources": {
|
||||
"VCPU": 4,
|
||||
"MEMORY_MB": 5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
# variables in path
|
||||
consumer_uuid:
|
||||
consumer_uuid: &consumer_uuid
|
||||
type: string
|
||||
in: path
|
||||
required: true
|
||||
@ -147,19 +147,29 @@ allocations_by_resource_provider:
|
||||
required: true
|
||||
description: >
|
||||
A dictionary of allocations keyed by resource provider uuid.
|
||||
allocations_dict:
|
||||
allocations_dict: &allocations_dict
|
||||
type: object
|
||||
in: body
|
||||
required: true
|
||||
min_version: 1.12
|
||||
description: >
|
||||
A dictionary of resource allocations keyed by resource provider uuid.
|
||||
allocations_dict_empty:
|
||||
<<: *allocations_dict
|
||||
description: >
|
||||
A dictionary of resource allocations keyed by resource provider uuid.
|
||||
If this is an empty object, allocations for this consumer will be
|
||||
removed.
|
||||
min_version: null
|
||||
capacity:
|
||||
type: integer
|
||||
in: body
|
||||
required: true
|
||||
description: >
|
||||
The amount of the resource that the provider can accommodate.
|
||||
consumer_uuid_body:
|
||||
<<: *consumer_uuid
|
||||
in: body
|
||||
inventories:
|
||||
type: object
|
||||
in: body
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Microversion 1.13 of the Placement API gives the ability to set or clear
|
||||
allocations for more than one consumer uuid with a request to
|
||||
``POST /allocations``.
|
Loading…
Reference in New Issue
Block a user