2049e868a5
Response codes for create ops in API v1.0 not compliant with spec Change-Id: I7723e46b05ffd7b29940327b9c7362f843e01817
197 lines
6.3 KiB
Python
197 lines
6.3 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright 2011 Citrix System.
|
|
# All Rights Reserved.
|
|
#
|
|
# 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.
|
|
|
|
import logging
|
|
|
|
from webob import exc
|
|
|
|
from quantum import wsgi
|
|
from quantum.api import faults
|
|
|
|
XML_NS_V10 = 'http://openstack.org/quantum/api/v1.0'
|
|
XML_NS_V11 = 'http://openstack.org/quantum/api/v1.1'
|
|
LOG = logging.getLogger('quantum.api.api_common')
|
|
|
|
|
|
class OperationalStatus:
|
|
""" Enumeration for operational status
|
|
|
|
UP : the resource is available (operationall up)
|
|
DOWN : the resource is not operational; this might indicate
|
|
a failure in the underlying switching fabric.
|
|
PROVISIONING: the plugin is creating or updating the resource
|
|
in the underlying switching fabric
|
|
UNKNOWN: the plugin does not support the operational status concept.
|
|
"""
|
|
UP = "UP"
|
|
DOWN = "DOWN"
|
|
PROVISIONING = "PROVISIONING"
|
|
UNKNOWN = "UNKNOWN"
|
|
|
|
|
|
def create_resource(version, controller_dict):
|
|
"""
|
|
Generic function for creating a wsgi resource
|
|
The function takes as input:
|
|
- desired version
|
|
- controller and metadata dictionary
|
|
e.g.: {'1.0': [ctrl_v10, meta_v10, xml_ns],
|
|
'1.1': [ctrl_v11, meta_v11, xml_ns]}
|
|
|
|
"""
|
|
# the first element of the iterable is expected to be the controller
|
|
controller = controller_dict[version][0]
|
|
# the second element should be the metadata
|
|
metadata = controller_dict[version][1]
|
|
# and the third element the xml namespace
|
|
xmlns = controller_dict[version][2]
|
|
# and also the function for building the fault body
|
|
fault_body_function = faults.fault_body_function(version)
|
|
|
|
headers_serializers = {
|
|
'1.0': HeaderSerializer10(),
|
|
'1.1': HeaderSerializer11()
|
|
}
|
|
xml_serializer = wsgi.XMLDictSerializer(metadata, xmlns)
|
|
json_serializer = wsgi.JSONDictSerializer()
|
|
xml_deserializer = wsgi.XMLDeserializer(metadata)
|
|
json_deserializer = wsgi.JSONDeserializer()
|
|
|
|
body_serializers = {
|
|
'application/xml': xml_serializer,
|
|
'application/json': json_serializer,
|
|
}
|
|
|
|
body_deserializers = {
|
|
'application/xml': xml_deserializer,
|
|
'application/json': json_deserializer,
|
|
}
|
|
|
|
serializer = wsgi.ResponseSerializer(body_serializers,
|
|
headers_serializers[version])
|
|
deserializer = wsgi.RequestDeserializer(body_deserializers)
|
|
|
|
return wsgi.Resource(controller,
|
|
fault_body_function,
|
|
deserializer,
|
|
serializer)
|
|
|
|
|
|
def APIFaultWrapper(errors=None):
|
|
|
|
quantum_error_dict = {
|
|
'1.0': faults.Quantum10HTTPError,
|
|
'1.1': faults.Quantum11HTTPError
|
|
}
|
|
|
|
def wrapper(func, **kwargs):
|
|
|
|
def the_func(*args, **kwargs):
|
|
try:
|
|
# Grab API version from type of controller
|
|
controller = args[0]
|
|
version = controller.version
|
|
return func(*args, **kwargs)
|
|
except Exception as e:
|
|
if errors is not None and type(e) in errors:
|
|
# Version-specific behaviour
|
|
quantum_error_class = quantum_error_dict[version]
|
|
raise quantum_error_class(e)
|
|
# otherwise just re-raise
|
|
raise
|
|
|
|
the_func.__name__ = func.__name__
|
|
return the_func
|
|
|
|
return wrapper
|
|
|
|
|
|
class HeaderSerializer10(wsgi.ResponseHeaderSerializer):
|
|
"""
|
|
Defines default respone status codes for Quantum API 1.0 operations
|
|
create - 200 OK
|
|
update - 204 NOCONTENT
|
|
delete - 204 NOCONTENT
|
|
others - 200 OK (defined in base class)
|
|
|
|
"""
|
|
|
|
def create(self, response, data):
|
|
response.status_int = 200
|
|
|
|
def delete(self, response, data):
|
|
response.status_int = 204
|
|
|
|
def update(self, response, data):
|
|
response.status_int = 204
|
|
|
|
def attach_resource(self, response, data):
|
|
response.status_int = 204
|
|
|
|
def detach_resource(self, response, data):
|
|
response.status_int = 204
|
|
|
|
|
|
class HeaderSerializer11(HeaderSerializer10):
|
|
"""
|
|
Defines default respone status codes for Quantum API 1.0 operations
|
|
create - 202 ACCEPTED
|
|
update - 204 NOCONTENT
|
|
delete - 204 NOCONTENT
|
|
others - 200 OK (defined in base class)
|
|
|
|
"""
|
|
|
|
def create(self, response, data):
|
|
response.status_int = 202
|
|
|
|
|
|
class QuantumController(object):
|
|
""" Base controller class for Quantum API """
|
|
|
|
def __init__(self, plugin):
|
|
self._plugin = plugin
|
|
super(QuantumController, self).__init__()
|
|
|
|
def _prepare_request_body(self, body, params):
|
|
""" verifies required parameters are in request body.
|
|
sets default value for missing optional parameters.
|
|
|
|
body argument must be the deserialized body
|
|
"""
|
|
try:
|
|
if body is None:
|
|
# Initialize empty resource for setting default value
|
|
body = {self._resource_name: {}}
|
|
data = body[self._resource_name]
|
|
except KeyError:
|
|
# raise if _resource_name is not in req body.
|
|
raise exc.HTTPBadRequest("Unable to find '%s' in request body"\
|
|
% self._resource_name)
|
|
for param in params:
|
|
param_name = param['param-name']
|
|
param_value = data.get(param_name, None)
|
|
# If the parameter wasn't found and it was required, return 400
|
|
if param_value is None and param['required']:
|
|
msg = ("Failed to parse request. " +
|
|
"Parameter: " + param_name + " not specified")
|
|
for line in msg.split('\n'):
|
|
LOG.error(line)
|
|
raise exc.HTTPBadRequest(msg)
|
|
data[param_name] = param_value or param.get('default-value')
|
|
return body
|