[placement] Idempotent PUT /resource_classes/{name}

In a microversion 1.7 change PUT /resource_classes/{name} so that
creation and existence validation of a custom resource class can
happen in a single request and prevent the previous behavior of
being able to update a single resource class to a new name, which is
not desirable.

The previous update_resource_class is still in place to support
microversion 1.2-1.6.

The original resource-classs.yaml sets the default microversion
header to 'latest' so for those existing tests that are using the
old style of PUT, a '1.6' header has been added. New files for
version 1.6 (to add a "no 1.7 behavior here" test) and 1.7 (testing
the new PUT behavior and explicitly verifying POST to create is
still around) are added.

Change-Id: I95f62ab2cb1ab76d18fb52b93f87ed28e4e7b5f3
Implements: bp placement-put-resource-class
This commit is contained in:
Chris Dent 2017-03-22 20:05:37 +00:00
parent 36aa8b3782
commit d6658d268d
8 changed files with 134 additions and 3 deletions

View File

@ -164,7 +164,7 @@ def list_resource_classes(req):
@wsgi_wrapper.PlacementWsgify @wsgi_wrapper.PlacementWsgify
@microversion.version_handler('1.2') @microversion.version_handler('1.2', '1.6')
@util.require_content('application/json') @util.require_content('application/json')
def update_resource_class(req): def update_resource_class(req):
"""PUT to update a single resource class. """PUT to update a single resource class.
@ -199,3 +199,38 @@ def update_resource_class(req):
req.response.status = 200 req.response.status = 200
req.response.content_type = 'application/json' req.response.content_type = 'application/json'
return req.response return req.response
@wsgi_wrapper.PlacementWsgify # noqa
@microversion.version_handler('1.7')
def update_resource_class(req):
"""PUT to create or validate the existence of single resource class.
On a successful create return 201. Return 204 if the class already
exists. If the resource class is not a custom resource class, return
a 400. 409 might be a better choice, but 400 aligns with previous code.
"""
name = util.wsgi_path_item(req.environ, 'name')
context = req.environ['placement.context']
# Use JSON validation to validation resource class name.
util.extract_json('{"name": "%s"}' % name, PUT_RC_SCHEMA_V1_2)
status = 204
try:
rc = objects.ResourceClass.get_by_name(context, name)
except exception.NotFound:
try:
rc = objects.ResourceClass(context, name=name)
rc.create()
status = 201
# We will not see ResourceClassCannotUpdateStandard because
# that was already caught when validating the {name}.
except exception.ResourceClassExists:
# Someone just now created the class, so stick with 204
pass
req.response.status = status
req.response.content_type = None
req.response.location = util.resource_class_url(req.environ, rc)
return req.response

View File

@ -43,6 +43,7 @@ VERSIONS = [
'1.5', # Adds DELETE /resource_providers/{uuid}/inventories '1.5', # Adds DELETE /resource_providers/{uuid}/inventories
'1.6', # Adds /traits and /resource_providers{uuid}/traits resource '1.6', # Adds /traits and /resource_providers{uuid}/traits resource
# endpoints # endpoints
'1.7', # PUT /resource_classes/{name} is bodiless create or update
] ]

View File

@ -113,3 +113,13 @@ The following new routes are added:
Custom traits must begin with the prefix "CUSTOM\_" and contain only Custom traits must begin with the prefix "CUSTOM\_" and contain only
the letters A through Z, the numbers 0 through 9 and the underscore "\_" the letters A through Z, the numbers 0 through 9 and the underscore "\_"
character. character.
1.7 Idempotent PUT /resource_classes/{name}
-------------------------------------------
The 1.7 version changes handling of `PUT /resource_classes/{name}` to be a
create or verification of the resource class with `{name}`. If the resource
class is a custom resource class and does not already exist it will be created
and a ``201`` response code returned. If the class already exists the response
code will be ``204``. This makes it possible to check or create a resource
class in one request.

View File

@ -39,13 +39,13 @@ tests:
response_json_paths: response_json_paths:
$.errors[0].title: Not Acceptable $.errors[0].title: Not Acceptable
- name: latest microversion is 1.6 - name: latest microversion is 1.7
GET: / GET: /
request_headers: request_headers:
openstack-api-version: placement latest openstack-api-version: placement latest
response_headers: response_headers:
vary: /OpenStack-API-Version/ vary: /OpenStack-API-Version/
openstack-api-version: placement 1.6 openstack-api-version: placement 1.7
- name: other accept header bad version - name: other accept header bad version
GET: / GET: /

View File

@ -0,0 +1,21 @@
# Confirm that 1.7 behavior of PUT resource classes is not in
# microversion 1.6.
fixtures:
- APIFixture
defaults:
request_headers:
x-auth-token: admin
accept: application/json
content-type: application/json
OpenStack-API-Version: placement 1.6
tests:
- name: bodiless put
PUT: /resource_classes/CUSTOM_COW
status: 400
response_strings:
# We don't check much of this string because it is different
# between python 2 and 3.
- "Malformed JSON:"

View File

@ -0,0 +1,49 @@
fixtures:
- APIFixture
defaults:
request_headers:
x-auth-token: admin
accept: application/json
content-type: application/json
OpenStack-API-Version: placement 1.7
tests:
- name: create new custom class with put
PUT: /resource_classes/CUSTOM_COW
status: 201
response_headers:
location: //resource_classes/CUSTOM_COW/
- name: verify that class with put
PUT: /resource_classes/CUSTOM_COW
status: 204
response_headers:
location: //resource_classes/CUSTOM_COW/
- name: fail to put non custom class
PUT: /resource_classes/COW
status: 400
response_strings:
- "Failed validating 'pattern'"
- name: try to put standard class
PUT: /resource_classes/VCPU
status: 400
response_strings:
- "Failed validating 'pattern'"
- name: try to put too long class
PUT: /resource_classes/CUSTOM_SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
status: 400
response_strings:
- "Failed validating 'maxLength'"
- name: post to create still works
POST: /resource_classes
data:
name: CUSTOM_SHEEP
status: 201
response_headers:
location: //resource_classes/CUSTOM_SHEEP/

View File

@ -125,6 +125,7 @@ tests:
PUT: /resource_classes/VCPU PUT: /resource_classes/VCPU
request_headers: request_headers:
content-type: application/json content-type: application/json
OpenStack-API-Version: placement 1.6
data: data:
name: VCPU_ALTERNATE name: VCPU_ALTERNATE
status: 400 status: 400
@ -137,6 +138,7 @@ tests:
PUT: /resource_classes/$ENVIRON['CUSTOM_RES_CLASS'] PUT: /resource_classes/$ENVIRON['CUSTOM_RES_CLASS']
request_headers: request_headers:
content-type: application/json content-type: application/json
OpenStack-API-Version: placement 1.6
data: data:
name: VCPU name: VCPU
status: 400 status: 400
@ -157,6 +159,7 @@ tests:
PUT: /resource_classes/CUSTOM_NFV_FOO PUT: /resource_classes/CUSTOM_NFV_FOO
request_headers: request_headers:
content-type: application/json content-type: application/json
OpenStack-API-Version: placement 1.6
data: data:
name: $ENVIRON['CUSTOM_RES_CLASS'] name: $ENVIRON['CUSTOM_RES_CLASS']
status: 409 status: 409
@ -170,6 +173,7 @@ tests:
PUT: /resource_classes/$ENVIRON['CUSTOM_RES_CLASS'] PUT: /resource_classes/$ENVIRON['CUSTOM_RES_CLASS']
request_headers: request_headers:
content-type: application/json content-type: application/json
OpenStack-API-Version: placement 1.6
data: data:
name: CUSTOM_NFV_BAR name: CUSTOM_NFV_BAR
status: 200 status: 200
@ -234,6 +238,7 @@ tests:
PUT: /resource_classes/$ENVIRON['CUSTOM_RES_CLASS'] PUT: /resource_classes/$ENVIRON['CUSTOM_RES_CLASS']
request_headers: request_headers:
content-type: application/json content-type: application/json
OpenStack-API-Version: placement 1.6
data: data:
name: *name_exceeds_max_length_check name: *name_exceeds_max_length_check
status: 400 status: 400

View File

@ -0,0 +1,10 @@
---
features:
- |
The 1.7 version of the placement API changes handling of
`PUT /resource_classes/{name}` to be a create or verification of the
resource class with `{name}`. If the resource class is a custom resource
class and does not already exist it will be created and a ``201`` response
code returned. If the class already exists the response code will be
``204``. This makes it possible to check or create a resource class in one
request.