Implement get and set aggregates in the placement API

/resource_providers/{uuid}/aggregates
GET for a list of aggregate uuids associated with this resource
    provider
PUT to set the list of aggregate uuids associated with this this
    provider

The API requests map directly to set_ and get_ aggregates on the
ResourceProvider object.

This is implemented as placement API microversion 1.1. To make that
easier a raise_404_if_not_version helper method is added to the
microversion module.

The new rest_api_version_history doc is updated to reflect this
new version.

Change-Id: I514c15c7d387cf25bf7986d07baccf0e7a785f46
Partially-Implements: blueprint generic-resource-pools-ocata
This commit is contained in:
Chris Dent 2016-08-19 16:14:14 +00:00
parent b3745f92e0
commit 44ca84a7e1
6 changed files with 202 additions and 2 deletions

View File

@ -28,6 +28,7 @@ import webob
from oslo_log import log as logging
from nova.api.openstack.placement.handlers import aggregate
from nova.api.openstack.placement.handlers import allocation
from nova.api.openstack.placement.handlers import inventory
from nova.api.openstack.placement.handlers import resource_provider
@ -79,6 +80,10 @@ ROUTE_DECLARATIONS = {
'/resource_providers/{uuid}/usages': {
'GET': usage.list_usages
},
'/resource_providers/{uuid}/aggregates': {
'GET': aggregate.get_aggregates,
'PUT': aggregate.set_aggregates
},
'/resource_providers/{uuid}/allocations': {
'GET': allocation.list_for_resource_provider,
},

View File

@ -0,0 +1,74 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Aggregate handlers for Placement API."""
from oslo_serialization import jsonutils
import webob
from nova.api.openstack.placement import microversion
from nova.api.openstack.placement import util
from nova import objects
PUT_AGGREGATES_SCHEMA = {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"uniqueItems": True
}
def _send_aggregates(response, aggregate_uuids):
response.status = 200
response.body = jsonutils.dumps(_serialize_aggregates(aggregate_uuids))
response.content_type = 'application/json'
return response
def _serialize_aggregates(aggregate_uuids):
return {'aggregates': aggregate_uuids}
@webob.dec.wsgify
@util.check_accept('application/json')
def get_aggregates(req):
"""GET a list of aggregates associated with a resource provider.
If the resource provider does not exist return a 404.
On success return a 200 with an application/json body containing a
list of aggregate uuids.
"""
microversion.raise_404_if_not_version(req, (1, 1))
context = req.environ['placement.context']
uuid = util.wsgi_path_item(req.environ, 'uuid')
resource_provider = objects.ResourceProvider.get_by_uuid(
context, uuid)
aggregate_uuids = resource_provider.get_aggregates()
return _send_aggregates(req.response, aggregate_uuids)
@webob.dec.wsgify
@util.require_content('application/json')
def set_aggregates(req):
microversion.raise_404_if_not_version(req, (1, 1))
context = req.environ['placement.context']
uuid = util.wsgi_path_item(req.environ, 'uuid')
resource_provider = objects.ResourceProvider.get_by_uuid(
context, uuid)
aggregate_uuids = util.extract_json(req.body, PUT_AGGREGATES_SCHEMA)
resource_provider.set_aggregates(aggregate_uuids)
return _send_aggregates(req.response, aggregate_uuids)

View File

@ -35,6 +35,7 @@ VERSIONED_METHODS = collections.defaultdict(list)
# The Canonical Version List
VERSIONS = [
'1.0',
'1.1', # initial support for aggregate.get_aggregates and set_aggregates
]
@ -68,6 +69,13 @@ def parse_version_string(version_string):
version_string, exc))
def raise_404_if_not_version(req, min_version, max_version=None):
"""Utility to raise a 404 if the wanted microversion does not match."""
want_version = req.environ[MICROVERSION_ENVIRON]
if not want_version.matches(min_version, max_version):
raise webob.exc.HTTPNotFound
class MicroversionMiddleware(object):
"""WSGI middleware for getting microversion info."""

View File

@ -17,3 +17,12 @@ Nova 14.0.0 (Newton). This contains the following routes:
* /resource_providers/inventories
* /resource_providers/usages
* /allocations
1.1
___
The 1.1 version adds support for associating aggregates with
resource providers with ``GET`` and ``PUT`` methods on one new
route:
* /resource_providers/{uuid}/aggregates

View File

@ -0,0 +1,104 @@
fixtures:
- APIFixture
defaults:
request_headers:
x-auth-token: admin
content-type: application/json
openstack-api-version: placement latest
vars:
- &agg_1 f918801a-5e54-4bee-9095-09a9d0c786b8
- &agg_2 a893eb5c-e2a0-4251-ab26-f71d3b0cfc0b
tests:
- name: get aggregates for bad resource provider
GET: /resource_providers/6984bb2d-830d-4c8d-ac64-c5a8103664be/aggregates
status: 404
- name: put aggregates for bad resource provider
PUT: /resource_providers/6984bb2d-830d-4c8d-ac64-c5a8103664be/aggregates
data: []
status: 404
- name: post new resource provider
POST: /resource_providers
data:
name: $ENVIRON['RP_NAME']
uuid: $ENVIRON['RP_UUID']
status: 201
response_headers:
location: //resource_providers/[a-f0-9-]+/
- name: get empty aggregates
GET: /resource_providers/$ENVIRON['RP_UUID']/aggregates
response_json_paths:
$.aggregates: []
- name: aggregates 404 for out of date microversion get
GET: /resource_providers/$ENVIRON['RP_UUID']/aggregates
request_headers:
openstack-api-version: placement 1.0
status: 404
- name: aggregates 404 for out of date microversion put
PUT: /resource_providers/$ENVIRON['RP_UUID']/aggregates
request_headers:
openstack-api-version: placement 1.0
status: 404
- name: put some aggregates
PUT: $LAST_URL
data:
- *agg_1
- *agg_2
status: 200
response_headers:
content-type: /application/json/
response_json_paths:
$.aggregates[0]: *agg_1
$.aggregates[1]: *agg_2
- name: get those aggregates
GET: $LAST_URL
response_json_paths:
$.aggregates.`len`: 2
- name: clear those aggregates
PUT: $LAST_URL
data: []
status: 200
response_json_paths:
$.aggregates: []
- name: get empty aggregates again
GET: /resource_providers/$ENVIRON['RP_UUID']/aggregates
response_json_paths:
$.aggregates: []
- name: put non json
PUT: $LAST_URL
data: '{"bad", "not json"}'
status: 400
response_strings:
- Malformed JSON
- name: put invalid json not array
PUT: $LAST_URL
data:
aggregates:
- *agg_1
- *agg_2
status: 400
response_strings:
- JSON does not validate
- name: put invalid json not uuids
PUT: $LAST_URL
data:
- harry
- sally
status: 400
response_strings:
- JSON does not validate

View File

@ -37,13 +37,13 @@ tests:
response_strings:
- "Unacceptable version header: 0.5"
- name: latest microversion is 1.0
- name: latest microversion is 1.1
GET: /
request_headers:
openstack-api-version: placement latest
response_headers:
vary: /OpenStack-API-Version/
openstack-api-version: placement 1.0
openstack-api-version: placement 1.1
- name: other accept header bad version
GET: /