Refactor modules used by senlin-api
This patch moves wsgi into api module, merge JSON serializers and deserializers into the same module for easier maintenance. Change-Id: I579de8701c69ef6e231762b9eb3192dc3208a9de
This commit is contained in:
parent
7c58fa23e9
commit
4203e1a779
|
@ -36,10 +36,10 @@ from oslo_log import log as logging
|
||||||
from oslo_service import systemd
|
from oslo_service import systemd
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import config
|
from senlin.common import config
|
||||||
from senlin.common.i18n import _LI
|
from senlin.common.i18n import _LI
|
||||||
from senlin.common import messaging
|
from senlin.common import messaging
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin import version
|
from senlin import version
|
||||||
|
|
||||||
_lazy.enable_lazy()
|
_lazy.enable_lazy()
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
pipeline = request_id faultwrap ssl versionnegotiation webhook authtoken context trust apiv1app
|
pipeline = request_id faultwrap ssl versionnegotiation webhook authtoken context trust apiv1app
|
||||||
|
|
||||||
[app:apiv1app]
|
[app:apiv1app]
|
||||||
paste.app_factory = senlin.common.wsgi:app_factory
|
paste.app_factory = senlin.api.common.wsgi:app_factory
|
||||||
senlin.app_factory = senlin.api.openstack.v1:API
|
senlin.app_factory = senlin.api.openstack.v1:API
|
||||||
|
|
||||||
# Middleware to set x-openstack-request-id in http response header
|
# Middleware to set x-openstack-request-id in http response header
|
||||||
|
@ -12,26 +12,26 @@ senlin.app_factory = senlin.api.openstack.v1:API
|
||||||
paste.filter_factory = oslo_middleware.request_id:RequestId.factory
|
paste.filter_factory = oslo_middleware.request_id:RequestId.factory
|
||||||
|
|
||||||
[filter:faultwrap]
|
[filter:faultwrap]
|
||||||
paste.filter_factory = senlin.common.wsgi:filter_factory
|
paste.filter_factory = senlin.api.common.wsgi:filter_factory
|
||||||
senlin.filter_factory = senlin.api.openstack:faultwrap_filter
|
senlin.filter_factory = senlin.api.openstack:faultwrap_filter
|
||||||
|
|
||||||
[filter:context]
|
[filter:context]
|
||||||
paste.filter_factory = senlin.common.wsgi:filter_factory
|
paste.filter_factory = senlin.api.common.wsgi:filter_factory
|
||||||
senlin.filter_factory = senlin.api.openstack:contextmiddleware_filter
|
senlin.filter_factory = senlin.api.openstack:contextmiddleware_filter
|
||||||
|
|
||||||
[filter:ssl]
|
[filter:ssl]
|
||||||
paste.filter_factory = oslo_middleware.ssl:SSLMiddleware.factory
|
paste.filter_factory = oslo_middleware.ssl:SSLMiddleware.factory
|
||||||
|
|
||||||
[filter:versionnegotiation]
|
[filter:versionnegotiation]
|
||||||
paste.filter_factory = senlin.common.wsgi:filter_factory
|
paste.filter_factory = senlin.api.common.wsgi:filter_factory
|
||||||
senlin.filter_factory = senlin.api.openstack:version_negotiation_filter
|
senlin.filter_factory = senlin.api.openstack:version_negotiation_filter
|
||||||
|
|
||||||
[filter:trust]
|
[filter:trust]
|
||||||
paste.filter_factory = senlin.common.wsgi:filter_factory
|
paste.filter_factory = senlin.api.common.wsgi:filter_factory
|
||||||
senlin.filter_factory = senlin.api.openstack:trustmiddleware_filter
|
senlin.filter_factory = senlin.api.openstack:trustmiddleware_filter
|
||||||
|
|
||||||
[filter:webhook]
|
[filter:webhook]
|
||||||
paste.filter_factory = senlin.common.wsgi:filter_factory
|
paste.filter_factory = senlin.api.common.wsgi:filter_factory
|
||||||
senlin.filter_factory = senlin.api.openstack:webhookmiddleware_filter
|
senlin.filter_factory = senlin.api.openstack:webhookmiddleware_filter
|
||||||
|
|
||||||
# Auth middleware that validates token against keystone
|
# Auth middleware that validates token against keystone
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Utility methods for serializing responses
|
||||||
|
"""
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
|
from oslo_utils import encodeutils
|
||||||
|
import six
|
||||||
|
import webob
|
||||||
|
|
||||||
|
from senlin.common import exception
|
||||||
|
from senlin.common.i18n import _
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def is_json_content_type(request):
|
||||||
|
|
||||||
|
content_type = request.content_type
|
||||||
|
if not content_type or content_type.startswith('text/plain'):
|
||||||
|
content_type = 'application/json'
|
||||||
|
|
||||||
|
if (content_type in ('JSON', 'application/json') and
|
||||||
|
request.body.startswith(b'{')):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class JSONRequestDeserializer(object):
|
||||||
|
|
||||||
|
def has_body(self, request):
|
||||||
|
"""Returns whether a Webob.Request object will possess an entity body.
|
||||||
|
|
||||||
|
:param request: A Webob.Request object
|
||||||
|
"""
|
||||||
|
if request is None or request.content_length is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if request.content_length > 0 and is_json_content_type(request):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def from_json(self, datastring):
|
||||||
|
try:
|
||||||
|
if len(datastring) > cfg.CONF.max_json_body_size:
|
||||||
|
msg = _('JSON body size (%(len)s bytes) exceeds maximum '
|
||||||
|
'allowed size (%(limit)s bytes).'
|
||||||
|
) % {'len': len(datastring),
|
||||||
|
'limit': cfg.CONF.max_json_body_size}
|
||||||
|
raise exception.RequestLimitExceeded(message=msg)
|
||||||
|
return jsonutils.loads(datastring)
|
||||||
|
except ValueError as ex:
|
||||||
|
raise webob.exc.HTTPBadRequest(six.text_type(ex))
|
||||||
|
|
||||||
|
def default(self, request):
|
||||||
|
if self.has_body(request):
|
||||||
|
return {'body': self.from_json(request.body)}
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
class JSONResponseSerializer(object):
|
||||||
|
|
||||||
|
def to_json(self, data):
|
||||||
|
def sanitizer(obj):
|
||||||
|
if isinstance(obj, datetime.datetime):
|
||||||
|
return obj.isoformat()
|
||||||
|
return six.text_type(obj)
|
||||||
|
|
||||||
|
response = jsonutils.dumps(data, default=sanitizer, sort_keys=True)
|
||||||
|
LOG.debug("JSON response : %s" % response)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def default(self, response, result):
|
||||||
|
response.content_type = 'application/json'
|
||||||
|
response.body = encodeutils.safe_encode(self.to_json(result))
|
|
@ -1,20 +1,14 @@
|
||||||
|
# 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
|
||||||
#
|
#
|
||||||
# Copyright 2010 United States Government as represented by the
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
# Administrator of the National Aeronautics and Space Administration.
|
|
||||||
# Copyright 2013 IBM Corp.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
# not use this file except in compliance with the License. You may obtain
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
# a copy of the License at
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
#
|
# License for the specific language governing permissions and limitations
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
# under the License.
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Utility methods for working with WSGI servers
|
Utility methods for working with WSGI servers
|
||||||
|
@ -37,7 +31,6 @@ import functools
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
import oslo_i18n
|
import oslo_i18n
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
from oslo_utils import importutils
|
from oslo_utils import importutils
|
||||||
from paste import deploy
|
from paste import deploy
|
||||||
import routes
|
import routes
|
||||||
|
@ -46,12 +39,12 @@ import six
|
||||||
import webob.dec
|
import webob.dec
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
|
from senlin.api.common import serializers
|
||||||
from senlin.common import exception
|
from senlin.common import exception
|
||||||
from senlin.common.i18n import _
|
from senlin.common.i18n import _
|
||||||
from senlin.common.i18n import _LE
|
from senlin.common.i18n import _LE
|
||||||
from senlin.common.i18n import _LI
|
from senlin.common.i18n import _LI
|
||||||
from senlin.common.i18n import _LW
|
from senlin.common.i18n import _LW
|
||||||
from senlin.common import serializers
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
@ -643,52 +636,6 @@ class Request(webob.Request):
|
||||||
return self.accept_language.best_match(all_languages)
|
return self.accept_language.best_match(all_languages)
|
||||||
|
|
||||||
|
|
||||||
def is_json_content_type(request):
|
|
||||||
|
|
||||||
content_type = request.content_type
|
|
||||||
if not content_type or content_type.startswith('text/plain'):
|
|
||||||
content_type = 'application/json'
|
|
||||||
|
|
||||||
if (content_type in ('JSON', 'application/json') and
|
|
||||||
request.body.startswith(b'{')):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class JSONRequestDeserializer(object):
|
|
||||||
|
|
||||||
def has_body(self, request):
|
|
||||||
"""Returns whether a Webob.Request object will possess an entity body.
|
|
||||||
|
|
||||||
:param request: A Webob.Request object
|
|
||||||
"""
|
|
||||||
if request is None or request.content_length is None:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if request.content_length > 0 and is_json_content_type(request):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def from_json(self, datastring):
|
|
||||||
try:
|
|
||||||
if len(datastring) > cfg.CONF.max_json_body_size:
|
|
||||||
msg = _('JSON body size (%(len)s bytes) exceeds maximum '
|
|
||||||
'allowed size (%(limit)s bytes).'
|
|
||||||
) % {'len': len(datastring),
|
|
||||||
'limit': cfg.CONF.max_json_body_size}
|
|
||||||
raise exception.RequestLimitExceeded(message=msg)
|
|
||||||
return jsonutils.loads(datastring)
|
|
||||||
except ValueError as ex:
|
|
||||||
raise webob.exc.HTTPBadRequest(six.text_type(ex))
|
|
||||||
|
|
||||||
def default(self, request):
|
|
||||||
if self.has_body(request):
|
|
||||||
return {'body': self.from_json(request.body)}
|
|
||||||
else:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
class Resource(object):
|
class Resource(object):
|
||||||
"""WSGI app that handles (de)serialization and controller dispatch.
|
"""WSGI app that handles (de)serialization and controller dispatch.
|
||||||
|
|
|
@ -14,9 +14,9 @@ from oslo_config import cfg
|
||||||
from oslo_middleware import request_id as oslo_request_id
|
from oslo_middleware import request_id as oslo_request_id
|
||||||
from oslo_utils import encodeutils
|
from oslo_utils import encodeutils
|
||||||
|
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import context
|
from senlin.common import context
|
||||||
from senlin.common import exception
|
from senlin.common import exception
|
||||||
from senlin.common import wsgi
|
|
||||||
|
|
||||||
|
|
||||||
class ContextMiddleware(wsgi.Middleware):
|
class ContextMiddleware(wsgi.Middleware):
|
||||||
|
|
|
@ -22,9 +22,9 @@ from oslo_config import cfg
|
||||||
import six
|
import six
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
|
from senlin.api.common import serializers
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import exception
|
from senlin.common import exception
|
||||||
from senlin.common import serializers
|
|
||||||
from senlin.common import wsgi
|
|
||||||
|
|
||||||
|
|
||||||
class Fault(object):
|
class Fault(object):
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import context
|
from senlin.common import context
|
||||||
from senlin.common import exception
|
from senlin.common import exception
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.db import api as db_api
|
from senlin.db import api as db_api
|
||||||
from senlin.drivers import base as driver_base
|
from senlin.drivers import base as driver_base
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,11 @@ return
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import webob
|
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
import webob
|
||||||
|
|
||||||
from senlin.common import wsgi
|
from senlin.api.common import wsgi
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,10 @@ from oslo_log import log as logging
|
||||||
import six
|
import six
|
||||||
from six.moves.urllib import parse as urlparse
|
from six.moves.urllib import parse as urlparse
|
||||||
|
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import context
|
from senlin.common import context
|
||||||
from senlin.common import exception as exc
|
from senlin.common import exception as exc
|
||||||
from senlin.common.i18n import _
|
from senlin.common.i18n import _
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.drivers import base as driver_base
|
from senlin.drivers import base as driver_base
|
||||||
from senlin.rpc import client as rpc
|
from senlin.rpc import client as rpc
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
import routes
|
import routes
|
||||||
|
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.api.openstack.v1 import actions
|
from senlin.api.openstack.v1 import actions
|
||||||
from senlin.api.openstack.v1 import build_info
|
from senlin.api.openstack.v1 import build_info
|
||||||
from senlin.api.openstack.v1 import cluster_policies
|
from senlin.api.openstack.v1 import cluster_policies
|
||||||
|
@ -25,7 +26,6 @@ from senlin.api.openstack.v1 import profile_types
|
||||||
from senlin.api.openstack.v1 import profiles
|
from senlin.api.openstack.v1 import profiles
|
||||||
from senlin.api.openstack.v1 import receivers
|
from senlin.api.openstack.v1 import receivers
|
||||||
from senlin.api.openstack.v1 import webhooks
|
from senlin.api.openstack.v1 import webhooks
|
||||||
from senlin.common import wsgi
|
|
||||||
|
|
||||||
|
|
||||||
class API(wsgi.Router):
|
class API(wsgi.Router):
|
||||||
|
|
|
@ -13,12 +13,12 @@
|
||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import serializers
|
||||||
|
from senlin.api.common import util
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import consts
|
from senlin.common import consts
|
||||||
from senlin.common.i18n import _
|
from senlin.common.i18n import _
|
||||||
from senlin.common import serializers
|
|
||||||
from senlin.common import utils
|
from senlin.common import utils
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.rpc import client as rpc_client
|
from senlin.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,8 +119,8 @@ class ActionController(object):
|
||||||
|
|
||||||
|
|
||||||
def create_resource(options):
|
def create_resource(options):
|
||||||
'''Actions factory method.'''
|
"""Actions factory method."""
|
||||||
|
|
||||||
return wsgi.Resource(ActionController(options),
|
return wsgi.Resource(ActionController(options),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
serializers.JSONResponseSerializer())
|
serializers.JSONResponseSerializer())
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import serializers
|
||||||
from senlin.common import serializers
|
from senlin.api.common import util
|
||||||
from senlin.common import wsgi
|
from senlin.api.common import wsgi
|
||||||
from senlin.rpc import client as rpc_client
|
from senlin.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class BuildInfoController(object):
|
||||||
def create_resource(options):
|
def create_resource(options):
|
||||||
'''BuildInfo factory method.'''
|
'''BuildInfo factory method.'''
|
||||||
|
|
||||||
deserializer = wsgi.JSONRequestDeserializer()
|
deserializer = serializers.JSONRequestDeserializer()
|
||||||
serializer = serializers.JSONResponseSerializer()
|
serializer = serializers.JSONResponseSerializer()
|
||||||
return wsgi.Resource(BuildInfoController(options), deserializer,
|
return wsgi.Resource(BuildInfoController(options), deserializer,
|
||||||
serializer)
|
serializer)
|
||||||
|
|
|
@ -16,11 +16,11 @@ ClusterPolicies endpoint for Senlin v1 ReST API.
|
||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import serializers
|
||||||
|
from senlin.api.common import util
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import consts
|
from senlin.common import consts
|
||||||
from senlin.common import serializers
|
|
||||||
from senlin.common import utils
|
from senlin.common import utils
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.rpc import client as rpc_client
|
from senlin.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,5 +71,5 @@ def create_resource(options):
|
||||||
'''ClusterPolicies resource factory method.'''
|
'''ClusterPolicies resource factory method.'''
|
||||||
|
|
||||||
return wsgi.Resource(ClusterPolicyController(options),
|
return wsgi.Resource(ClusterPolicyController(options),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
serializers.JSONResponseSerializer())
|
serializers.JSONResponseSerializer())
|
||||||
|
|
|
@ -19,13 +19,13 @@ from oslo_config import cfg
|
||||||
import six
|
import six
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import serializers
|
||||||
|
from senlin.api.common import util
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import consts
|
from senlin.common import consts
|
||||||
from senlin.common import exception as senlin_exc
|
from senlin.common import exception as senlin_exc
|
||||||
from senlin.common.i18n import _
|
from senlin.common.i18n import _
|
||||||
from senlin.common import serializers
|
|
||||||
from senlin.common import utils
|
from senlin.common import utils
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.rpc import client as rpc_client
|
from senlin.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
|
@ -366,8 +366,8 @@ class ClusterController(object):
|
||||||
|
|
||||||
|
|
||||||
def create_resource(options):
|
def create_resource(options):
|
||||||
'''Clusters resource factory method.'''
|
"""Clusters resource factory method."""
|
||||||
|
|
||||||
return wsgi.Resource(ClusterController(options),
|
return wsgi.Resource(ClusterController(options),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
serializers.JSONResponseSerializer())
|
serializers.JSONResponseSerializer())
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import serializers
|
||||||
|
from senlin.api.common import util
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import consts
|
from senlin.common import consts
|
||||||
from senlin.common import serializers
|
|
||||||
from senlin.common import utils
|
from senlin.common import utils
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.rpc import client as rpc_client
|
from senlin.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,5 +80,5 @@ def create_resource(options):
|
||||||
'''Events factory method.'''
|
'''Events factory method.'''
|
||||||
|
|
||||||
return wsgi.Resource(EventController(options),
|
return wsgi.Resource(EventController(options),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
serializers.JSONResponseSerializer())
|
serializers.JSONResponseSerializer())
|
||||||
|
|
|
@ -16,12 +16,12 @@ Node endpoint for Senlin v1 ReST API.
|
||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import serializers
|
||||||
|
from senlin.api.common import util
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import consts
|
from senlin.common import consts
|
||||||
from senlin.common.i18n import _
|
from senlin.common.i18n import _
|
||||||
from senlin.common import serializers
|
|
||||||
from senlin.common import utils
|
from senlin.common import utils
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.rpc import client as rpc_client
|
from senlin.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
|
@ -166,8 +166,8 @@ class NodeController(object):
|
||||||
|
|
||||||
|
|
||||||
def create_resource(options):
|
def create_resource(options):
|
||||||
'''Nodes resource factory method.'''
|
"""Nodes resource factory method."""
|
||||||
|
|
||||||
return wsgi.Resource(NodeController(options),
|
return wsgi.Resource(NodeController(options),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
serializers.JSONResponseSerializer())
|
serializers.JSONResponseSerializer())
|
||||||
|
|
|
@ -16,12 +16,12 @@ Policy endpoint for Senlin v1 ReST API.
|
||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import serializers
|
||||||
|
from senlin.api.common import util
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import consts
|
from senlin.common import consts
|
||||||
from senlin.common.i18n import _
|
from senlin.common.i18n import _
|
||||||
from senlin.common import serializers
|
|
||||||
from senlin.common import utils
|
from senlin.common import utils
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.rpc import client as rpc_client
|
from senlin.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,8 +121,8 @@ class PolicyController(object):
|
||||||
|
|
||||||
|
|
||||||
def create_resource(options):
|
def create_resource(options):
|
||||||
'''Policies resource factory method.'''
|
"""Policies resource factory method."""
|
||||||
|
|
||||||
return wsgi.Resource(PolicyController(options),
|
return wsgi.Resource(PolicyController(options),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
serializers.JSONResponseSerializer())
|
serializers.JSONResponseSerializer())
|
||||||
|
|
|
@ -10,15 +10,15 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
'''
|
"""
|
||||||
Policy type endpoint for Senlin v1 ReST API.
|
Policy type endpoint for Senlin v1 ReST API.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import serializers
|
||||||
from senlin.common import serializers
|
from senlin.api.common import util
|
||||||
from senlin.common import wsgi
|
from senlin.api.common import wsgi
|
||||||
from senlin.rpc import client as rpc_client
|
from senlin.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,8 +46,8 @@ class PolicyTypeController(object):
|
||||||
|
|
||||||
|
|
||||||
def create_resource(options):
|
def create_resource(options):
|
||||||
'''Policy type resource factory method.'''
|
"""Policy type resource factory method."""
|
||||||
|
|
||||||
return wsgi.Resource(PolicyTypeController(options),
|
return wsgi.Resource(PolicyTypeController(options),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
serializers.JSONResponseSerializer())
|
serializers.JSONResponseSerializer())
|
||||||
|
|
|
@ -10,15 +10,15 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
'''
|
"""
|
||||||
Profile type endpoint for Senlin v1 ReST API.
|
Profile type endpoint for Senlin v1 ReST API.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import serializers
|
||||||
from senlin.common import serializers
|
from senlin.api.common import util
|
||||||
from senlin.common import wsgi
|
from senlin.api.common import wsgi
|
||||||
from senlin.rpc import client as rpc_client
|
from senlin.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,8 +48,8 @@ class ProfileTypeController(object):
|
||||||
|
|
||||||
|
|
||||||
def create_resource(options):
|
def create_resource(options):
|
||||||
'''Profile types resource factory method.'''
|
"""Profile types resource factory method."""
|
||||||
|
|
||||||
return wsgi.Resource(ProfileTypeController(options),
|
return wsgi.Resource(ProfileTypeController(options),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
serializers.JSONResponseSerializer())
|
serializers.JSONResponseSerializer())
|
||||||
|
|
|
@ -16,12 +16,12 @@ Profile endpoint for Senlin v1 ReST API.
|
||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import serializers
|
||||||
|
from senlin.api.common import util
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import consts
|
from senlin.common import consts
|
||||||
from senlin.common.i18n import _
|
from senlin.common.i18n import _
|
||||||
from senlin.common import serializers
|
|
||||||
from senlin.common import utils
|
from senlin.common import utils
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.rpc import client as rpc_client
|
from senlin.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,5 +142,5 @@ def create_resource(options):
|
||||||
'''Profiles resource factory method.'''
|
'''Profiles resource factory method.'''
|
||||||
|
|
||||||
return wsgi.Resource(ProfileController(options),
|
return wsgi.Resource(ProfileController(options),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
serializers.JSONResponseSerializer())
|
serializers.JSONResponseSerializer())
|
||||||
|
|
|
@ -16,12 +16,12 @@ Webhook endpoint for Senlin v1 ReST API.
|
||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import serializers
|
||||||
|
from senlin.api.common import util
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import consts
|
from senlin.common import consts
|
||||||
from senlin.common.i18n import _
|
from senlin.common.i18n import _
|
||||||
from senlin.common import serializers
|
|
||||||
from senlin.common import utils
|
from senlin.common import utils
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.rpc import client as rpc_client
|
from senlin.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,5 +141,5 @@ def create_resource(options):
|
||||||
"""Receiver resource factory method."""
|
"""Receiver resource factory method."""
|
||||||
|
|
||||||
return wsgi.Resource(ReceiverController(options),
|
return wsgi.Resource(ReceiverController(options),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
serializers.JSONResponseSerializer())
|
serializers.JSONResponseSerializer())
|
||||||
|
|
|
@ -16,9 +16,9 @@ Webhook endpoint for Senlin v1 ReST API.
|
||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import serializers
|
||||||
from senlin.common import serializers
|
from senlin.api.common import util
|
||||||
from senlin.common import wsgi
|
from senlin.api.common import wsgi
|
||||||
from senlin.rpc import client as rpc_client
|
from senlin.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,5 +52,5 @@ def create_resource(options):
|
||||||
"""Webhooks resource factory method."""
|
"""Webhooks resource factory method."""
|
||||||
|
|
||||||
return wsgi.Resource(WebhookController(options),
|
return wsgi.Resource(WebhookController(options),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
serializers.JSONResponseSerializer())
|
serializers.JSONResponseSerializer())
|
||||||
|
|
|
@ -21,8 +21,8 @@ import socket
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common.i18n import _
|
from senlin.common.i18n import _
|
||||||
from senlin.common import wsgi
|
|
||||||
|
|
||||||
paste_deploy_group = cfg.OptGroup('paste_deploy')
|
paste_deploy_group = cfg.OptGroup('paste_deploy')
|
||||||
paste_deploy_opts = [
|
paste_deploy_opts = [
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
Utility methods for serializing responses
|
|
||||||
"""
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
from oslo_log import log as logging
|
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
from oslo_utils import encodeutils
|
|
||||||
import six
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class JSONResponseSerializer(object):
|
|
||||||
|
|
||||||
def to_json(self, data):
|
|
||||||
def sanitizer(obj):
|
|
||||||
if isinstance(obj, datetime.datetime):
|
|
||||||
return obj.isoformat()
|
|
||||||
return six.text_type(obj)
|
|
||||||
|
|
||||||
response = jsonutils.dumps(data, default=sanitizer, sort_keys=True)
|
|
||||||
LOG.debug("JSON response : %s" % response)
|
|
||||||
return response
|
|
||||||
|
|
||||||
def default(self, response, result):
|
|
||||||
response.content_type = 'application/json'
|
|
||||||
response.body = encodeutils.safe_encode(self.to_json(result))
|
|
|
@ -0,0 +1,202 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
|
from oslo_utils import encodeutils
|
||||||
|
from oslo_utils import timeutils as tu
|
||||||
|
import six
|
||||||
|
import webob
|
||||||
|
|
||||||
|
from senlin.api.common import serializers
|
||||||
|
from senlin.api.common import wsgi
|
||||||
|
from senlin.common import exception
|
||||||
|
from senlin.tests.unit.common import base
|
||||||
|
|
||||||
|
|
||||||
|
class JSONRequestDeserializerTest(base.SenlinTestCase):
|
||||||
|
|
||||||
|
def test_has_body_no_content_length(self):
|
||||||
|
request = wsgi.Request.blank('/')
|
||||||
|
request.method = 'POST'
|
||||||
|
request.body = encodeutils.safe_encode('asdf')
|
||||||
|
request.headers.pop('Content-Length')
|
||||||
|
request.headers['Content-Type'] = 'application/json'
|
||||||
|
obj = serializers.JSONRequestDeserializer()
|
||||||
|
self.assertFalse(obj.has_body(request))
|
||||||
|
|
||||||
|
def test_has_body_zero_content_length(self):
|
||||||
|
request = wsgi.Request.blank('/')
|
||||||
|
request.method = 'POST'
|
||||||
|
request.body = encodeutils.safe_encode('asdf')
|
||||||
|
request.headers['Content-Length'] = 0
|
||||||
|
request.headers['Content-Type'] = 'application/json'
|
||||||
|
obj = serializers.JSONRequestDeserializer()
|
||||||
|
self.assertFalse(obj.has_body(request))
|
||||||
|
|
||||||
|
def test_has_body_has_content_length_no_content_type(self):
|
||||||
|
request = wsgi.Request.blank('/')
|
||||||
|
request.method = 'POST'
|
||||||
|
request.body = encodeutils.safe_encode('{"key": "value"}')
|
||||||
|
self.assertIn('Content-Length', request.headers)
|
||||||
|
obj = serializers.JSONRequestDeserializer()
|
||||||
|
self.assertTrue(obj.has_body(request))
|
||||||
|
|
||||||
|
def test_has_body_has_content_length_plain_content_type(self):
|
||||||
|
request = wsgi.Request.blank('/')
|
||||||
|
request.method = 'POST'
|
||||||
|
request.body = encodeutils.safe_encode('{"key": "value"}')
|
||||||
|
self.assertIn('Content-Length', request.headers)
|
||||||
|
request.headers['Content-Type'] = 'text/plain'
|
||||||
|
obj = serializers.JSONRequestDeserializer()
|
||||||
|
self.assertTrue(obj.has_body(request))
|
||||||
|
|
||||||
|
def test_has_body_has_content_type_malformed(self):
|
||||||
|
request = wsgi.Request.blank('/')
|
||||||
|
request.method = 'POST'
|
||||||
|
request.body = encodeutils.safe_encode('asdf')
|
||||||
|
self.assertIn('Content-Length', request.headers)
|
||||||
|
request.headers['Content-Type'] = 'application/json'
|
||||||
|
obj = serializers.JSONRequestDeserializer()
|
||||||
|
self.assertFalse(obj.has_body(request))
|
||||||
|
|
||||||
|
def test_has_body_has_content_type(self):
|
||||||
|
request = wsgi.Request.blank('/')
|
||||||
|
request.method = 'POST'
|
||||||
|
request.body = encodeutils.safe_encode('{"key": "value"}')
|
||||||
|
self.assertIn('Content-Length', request.headers)
|
||||||
|
request.headers['Content-Type'] = 'application/json'
|
||||||
|
obj = serializers.JSONRequestDeserializer()
|
||||||
|
self.assertTrue(obj.has_body(request))
|
||||||
|
|
||||||
|
def test_has_body_has_wrong_content_type(self):
|
||||||
|
request = wsgi.Request.blank('/')
|
||||||
|
request.method = 'POST'
|
||||||
|
request.body = encodeutils.safe_encode('{"key": "value"}')
|
||||||
|
self.assertIn('Content-Length', request.headers)
|
||||||
|
request.headers['Content-Type'] = 'application/xml'
|
||||||
|
obj = serializers.JSONRequestDeserializer()
|
||||||
|
self.assertFalse(obj.has_body(request))
|
||||||
|
|
||||||
|
def test_has_body_has_aws_content_type_only(self):
|
||||||
|
request = wsgi.Request.blank('/?ContentType=JSON')
|
||||||
|
request.method = 'GET'
|
||||||
|
request.body = encodeutils.safe_encode('{"key": "value"}')
|
||||||
|
self.assertIn('Content-Length', request.headers)
|
||||||
|
obj = serializers.JSONRequestDeserializer()
|
||||||
|
self.assertTrue(obj.has_body(request))
|
||||||
|
|
||||||
|
def test_has_body_content_type_with_get(self):
|
||||||
|
request = wsgi.Request.blank('/')
|
||||||
|
request.method = 'GET'
|
||||||
|
request.body = encodeutils.safe_encode('{"key": "value"}')
|
||||||
|
self.assertIn('Content-Length', request.headers)
|
||||||
|
obj = serializers.JSONRequestDeserializer()
|
||||||
|
self.assertTrue(obj.has_body(request))
|
||||||
|
|
||||||
|
def test_no_body_no_content_length(self):
|
||||||
|
request = wsgi.Request.blank('/')
|
||||||
|
obj = serializers.JSONRequestDeserializer()
|
||||||
|
self.assertFalse(obj.has_body(request))
|
||||||
|
|
||||||
|
def test_from_json(self):
|
||||||
|
fixture = '{"key": "value"}'
|
||||||
|
expected = {"key": "value"}
|
||||||
|
actual = serializers.JSONRequestDeserializer().from_json(fixture)
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
def test_from_json_malformed(self):
|
||||||
|
fixture = 'kjasdklfjsklajf'
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
|
serializers.JSONRequestDeserializer().from_json,
|
||||||
|
fixture)
|
||||||
|
|
||||||
|
def test_default_no_body(self):
|
||||||
|
request = wsgi.Request.blank('/')
|
||||||
|
actual = serializers.JSONRequestDeserializer().default(request)
|
||||||
|
expected = {}
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
def test_default_with_body(self):
|
||||||
|
request = wsgi.Request.blank('/')
|
||||||
|
request.method = 'POST'
|
||||||
|
request.body = encodeutils.safe_encode('{"key": "value"}')
|
||||||
|
actual = serializers.JSONRequestDeserializer().default(request)
|
||||||
|
expected = {"body": {"key": "value"}}
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
def test_default_with_get_with_body(self):
|
||||||
|
request = wsgi.Request.blank('/')
|
||||||
|
request.method = 'GET'
|
||||||
|
request.body = encodeutils.safe_encode('{"key": "value"}')
|
||||||
|
actual = serializers.JSONRequestDeserializer().default(request)
|
||||||
|
expected = {"body": {"key": "value"}}
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
def test_default_with_get_with_body_with_aws(self):
|
||||||
|
request = wsgi.Request.blank('/?ContentType=JSON')
|
||||||
|
request.method = 'GET'
|
||||||
|
request.body = encodeutils.safe_encode('{"key": "value"}')
|
||||||
|
actual = serializers.JSONRequestDeserializer().default(request)
|
||||||
|
expected = {"body": {"key": "value"}}
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
def test_from_json_exceeds_max_json_mb(self):
|
||||||
|
cfg.CONF.set_override('max_json_body_size', 10, enforce_type=True)
|
||||||
|
body = jsonutils.dumps(['a'] * cfg.CONF.max_json_body_size)
|
||||||
|
self.assertTrue(len(body) > cfg.CONF.max_json_body_size)
|
||||||
|
obj = serializers.JSONRequestDeserializer()
|
||||||
|
error = self.assertRaises(exception.RequestLimitExceeded,
|
||||||
|
obj.from_json,
|
||||||
|
body)
|
||||||
|
msg = ('Request limit exceeded: JSON body size '
|
||||||
|
'(%s bytes) exceeds maximum allowed size (%s bytes).'
|
||||||
|
) % (len(body), cfg.CONF.max_json_body_size)
|
||||||
|
self.assertEqual(msg, six.text_type(error))
|
||||||
|
|
||||||
|
|
||||||
|
class JSONResponseSerializerTest(base.SenlinTestCase):
|
||||||
|
|
||||||
|
def test_to_json(self):
|
||||||
|
fixture = {"key": "value"}
|
||||||
|
expected = '{"key": "value"}'
|
||||||
|
actual = serializers.JSONResponseSerializer().to_json(fixture)
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
def test_to_json_with_date_format_value(self):
|
||||||
|
test_date = tu.parse_strtime("0001-03-08T02:00:00",
|
||||||
|
'%Y-%m-%dT%H:%M:%S')
|
||||||
|
fixture = {"date": test_date}
|
||||||
|
expected = '{"date": "0001-03-08T02:00:00"}'
|
||||||
|
actual = serializers.JSONResponseSerializer().to_json(fixture)
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
def test_to_json_with_more_deep_format(self):
|
||||||
|
val = complex(1, 2)
|
||||||
|
fixture = {"is_public": True, "v": val}
|
||||||
|
expected = '{"is_public": true, "v": "(1+2j)"}'
|
||||||
|
actual = serializers.JSONResponseSerializer().to_json(fixture)
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
def test_default(self):
|
||||||
|
fixture = {"key": "value"}
|
||||||
|
response = webob.Response()
|
||||||
|
serializers.JSONResponseSerializer().default(response, fixture)
|
||||||
|
self.assertEqual(200, response.status_int)
|
||||||
|
content_types = filter(lambda h: h[0] == 'Content-Type',
|
||||||
|
response.headerlist)
|
||||||
|
# NOTE: filter returns a iterator in python 3.
|
||||||
|
types = [t for t in content_types]
|
||||||
|
self.assertEqual(1, len(types))
|
||||||
|
self.assertEqual('application/json', response.content_type)
|
||||||
|
self.assertEqual('{"key": "value"}',
|
||||||
|
encodeutils.safe_decode(response.body))
|
|
@ -13,10 +13,10 @@
|
||||||
import mock
|
import mock
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from senlin.api.openstack.v1 import util
|
from senlin.api.common import util
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import context
|
from senlin.common import context
|
||||||
from senlin.common import policy
|
from senlin.common import policy
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.tests.unit.common import base
|
from senlin.tests.unit.common import base
|
||||||
|
|
||||||
|
|
|
@ -10,19 +10,19 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import fixtures
|
|
||||||
import json
|
|
||||||
import mock
|
|
||||||
import six
|
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
|
import fixtures
|
||||||
|
import mock
|
||||||
|
from oslo_config import cfg
|
||||||
|
from oslo_utils import encodeutils
|
||||||
|
import six
|
||||||
import stubout
|
import stubout
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
from oslo_config import cfg
|
from senlin.api.common import serializers
|
||||||
from oslo_utils import encodeutils
|
from senlin.api.common import wsgi
|
||||||
|
|
||||||
from senlin.common import exception
|
from senlin.common import exception
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.tests.unit.common import base
|
from senlin.tests.unit.common import base
|
||||||
|
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ class ResourceTest(base.SenlinTestCase):
|
||||||
request = wsgi.Request.blank('/tests/123', environ=env)
|
request = wsgi.Request.blank('/tests/123', environ=env)
|
||||||
request.body = encodeutils.safe_encode('{"foo" : "value"}')
|
request.body = encodeutils.safe_encode('{"foo" : "value"}')
|
||||||
resource = wsgi.Resource(Controller(),
|
resource = wsgi.Resource(Controller(),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
None)
|
None)
|
||||||
|
|
||||||
# The Resource does not throw webob.HTTPExceptions, since they
|
# The Resource does not throw webob.HTTPExceptions, since they
|
||||||
|
@ -190,7 +190,7 @@ class ResourceTest(base.SenlinTestCase):
|
||||||
translated_ex = webob.exc.HTTPBadRequest(message_es)
|
translated_ex = webob.exc.HTTPBadRequest(message_es)
|
||||||
|
|
||||||
resource = wsgi.Resource(Controller(),
|
resource = wsgi.Resource(Controller(),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
None)
|
None)
|
||||||
|
|
||||||
def fake_translate_exception(ex, locale):
|
def fake_translate_exception(ex, locale):
|
||||||
|
@ -230,157 +230,28 @@ class ResourceExceptionHandlingTest(base.SenlinTestCase):
|
||||||
request = wsgi.Request.blank('/tests/123', environ=env)
|
request = wsgi.Request.blank('/tests/123', environ=env)
|
||||||
request.body = encodeutils.safe_encode('{"foo": "value"}')
|
request.body = encodeutils.safe_encode('{"foo": "value"}')
|
||||||
resource = wsgi.Resource(Controller(self.exception),
|
resource = wsgi.Resource(Controller(self.exception),
|
||||||
wsgi.JSONRequestDeserializer(),
|
serializers.JSONRequestDeserializer(),
|
||||||
None)
|
None)
|
||||||
e = self.assertRaises(self.exception_catch, resource, request)
|
e = self.assertRaises(self.exception_catch, resource, request)
|
||||||
e = e.exc if hasattr(e, 'exc') else e
|
e = e.exc if hasattr(e, 'exc') else e
|
||||||
self.assertNotIn(six.text_type(e), self.LOG.output)
|
self.assertNotIn(six.text_type(e), self.LOG.output)
|
||||||
|
|
||||||
|
|
||||||
class JSONRequestDeserializerTest(base.SenlinTestCase):
|
|
||||||
|
|
||||||
def test_has_body_no_content_length(self):
|
|
||||||
request = wsgi.Request.blank('/')
|
|
||||||
request.method = 'POST'
|
|
||||||
request.body = encodeutils.safe_encode('asdf')
|
|
||||||
request.headers.pop('Content-Length')
|
|
||||||
request.headers['Content-Type'] = 'application/json'
|
|
||||||
self.assertFalse(wsgi.JSONRequestDeserializer().has_body(request))
|
|
||||||
|
|
||||||
def test_has_body_zero_content_length(self):
|
|
||||||
request = wsgi.Request.blank('/')
|
|
||||||
request.method = 'POST'
|
|
||||||
request.body = encodeutils.safe_encode('asdf')
|
|
||||||
request.headers['Content-Length'] = 0
|
|
||||||
request.headers['Content-Type'] = 'application/json'
|
|
||||||
self.assertFalse(wsgi.JSONRequestDeserializer().has_body(request))
|
|
||||||
|
|
||||||
def test_has_body_has_content_length_no_content_type(self):
|
|
||||||
request = wsgi.Request.blank('/')
|
|
||||||
request.method = 'POST'
|
|
||||||
request.body = encodeutils.safe_encode('{"key": "value"}')
|
|
||||||
self.assertIn('Content-Length', request.headers)
|
|
||||||
self.assertTrue(wsgi.JSONRequestDeserializer().has_body(request))
|
|
||||||
|
|
||||||
def test_has_body_has_content_length_plain_content_type(self):
|
|
||||||
request = wsgi.Request.blank('/')
|
|
||||||
request.method = 'POST'
|
|
||||||
request.body = encodeutils.safe_encode('{"key": "value"}')
|
|
||||||
self.assertIn('Content-Length', request.headers)
|
|
||||||
request.headers['Content-Type'] = 'text/plain'
|
|
||||||
self.assertTrue(wsgi.JSONRequestDeserializer().has_body(request))
|
|
||||||
|
|
||||||
def test_has_body_has_content_type_malformed(self):
|
|
||||||
request = wsgi.Request.blank('/')
|
|
||||||
request.method = 'POST'
|
|
||||||
request.body = encodeutils.safe_encode('asdf')
|
|
||||||
self.assertIn('Content-Length', request.headers)
|
|
||||||
request.headers['Content-Type'] = 'application/json'
|
|
||||||
self.assertFalse(wsgi.JSONRequestDeserializer().has_body(request))
|
|
||||||
|
|
||||||
def test_has_body_has_content_type(self):
|
|
||||||
request = wsgi.Request.blank('/')
|
|
||||||
request.method = 'POST'
|
|
||||||
request.body = encodeutils.safe_encode('{"key": "value"}')
|
|
||||||
self.assertIn('Content-Length', request.headers)
|
|
||||||
request.headers['Content-Type'] = 'application/json'
|
|
||||||
self.assertTrue(wsgi.JSONRequestDeserializer().has_body(request))
|
|
||||||
|
|
||||||
def test_has_body_has_wrong_content_type(self):
|
|
||||||
request = wsgi.Request.blank('/')
|
|
||||||
request.method = 'POST'
|
|
||||||
request.body = encodeutils.safe_encode('{"key": "value"}')
|
|
||||||
self.assertIn('Content-Length', request.headers)
|
|
||||||
request.headers['Content-Type'] = 'application/xml'
|
|
||||||
self.assertFalse(wsgi.JSONRequestDeserializer().has_body(request))
|
|
||||||
|
|
||||||
def test_has_body_has_aws_content_type_only(self):
|
|
||||||
request = wsgi.Request.blank('/?ContentType=JSON')
|
|
||||||
request.method = 'GET'
|
|
||||||
request.body = encodeutils.safe_encode('{"key": "value"}')
|
|
||||||
self.assertIn('Content-Length', request.headers)
|
|
||||||
self.assertTrue(wsgi.JSONRequestDeserializer().has_body(request))
|
|
||||||
|
|
||||||
def test_has_body_content_type_with_get(self):
|
|
||||||
request = wsgi.Request.blank('/')
|
|
||||||
request.method = 'GET'
|
|
||||||
request.body = encodeutils.safe_encode('{"key": "value"}')
|
|
||||||
self.assertIn('Content-Length', request.headers)
|
|
||||||
self.assertTrue(wsgi.JSONRequestDeserializer().has_body(request))
|
|
||||||
|
|
||||||
def test_no_body_no_content_length(self):
|
|
||||||
request = wsgi.Request.blank('/')
|
|
||||||
self.assertFalse(wsgi.JSONRequestDeserializer().has_body(request))
|
|
||||||
|
|
||||||
def test_from_json(self):
|
|
||||||
fixture = '{"key": "value"}'
|
|
||||||
expected = {"key": "value"}
|
|
||||||
actual = wsgi.JSONRequestDeserializer().from_json(fixture)
|
|
||||||
self.assertEqual(expected, actual)
|
|
||||||
|
|
||||||
def test_from_json_malformed(self):
|
|
||||||
fixture = 'kjasdklfjsklajf'
|
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
|
||||||
wsgi.JSONRequestDeserializer().from_json, fixture)
|
|
||||||
|
|
||||||
def test_default_no_body(self):
|
|
||||||
request = wsgi.Request.blank('/')
|
|
||||||
actual = wsgi.JSONRequestDeserializer().default(request)
|
|
||||||
expected = {}
|
|
||||||
self.assertEqual(expected, actual)
|
|
||||||
|
|
||||||
def test_default_with_body(self):
|
|
||||||
request = wsgi.Request.blank('/')
|
|
||||||
request.method = 'POST'
|
|
||||||
request.body = encodeutils.safe_encode('{"key": "value"}')
|
|
||||||
actual = wsgi.JSONRequestDeserializer().default(request)
|
|
||||||
expected = {"body": {"key": "value"}}
|
|
||||||
self.assertEqual(expected, actual)
|
|
||||||
|
|
||||||
def test_default_with_get_with_body(self):
|
|
||||||
request = wsgi.Request.blank('/')
|
|
||||||
request.method = 'GET'
|
|
||||||
request.body = encodeutils.safe_encode('{"key": "value"}')
|
|
||||||
actual = wsgi.JSONRequestDeserializer().default(request)
|
|
||||||
expected = {"body": {"key": "value"}}
|
|
||||||
self.assertEqual(expected, actual)
|
|
||||||
|
|
||||||
def test_default_with_get_with_body_with_aws(self):
|
|
||||||
request = wsgi.Request.blank('/?ContentType=JSON')
|
|
||||||
request.method = 'GET'
|
|
||||||
request.body = encodeutils.safe_encode('{"key": "value"}')
|
|
||||||
actual = wsgi.JSONRequestDeserializer().default(request)
|
|
||||||
expected = {"body": {"key": "value"}}
|
|
||||||
self.assertEqual(expected, actual)
|
|
||||||
|
|
||||||
def test_from_json_exceeds_max_json_mb(self):
|
|
||||||
cfg.CONF.set_override('max_json_body_size', 10, enforce_type=True)
|
|
||||||
body = json.dumps(['a'] * cfg.CONF.max_json_body_size)
|
|
||||||
self.assertTrue(len(body) > cfg.CONF.max_json_body_size)
|
|
||||||
error = self.assertRaises(exception.RequestLimitExceeded,
|
|
||||||
wsgi.JSONRequestDeserializer().from_json,
|
|
||||||
body)
|
|
||||||
msg = ('Request limit exceeded: JSON body size '
|
|
||||||
'(%s bytes) exceeds maximum allowed size (%s bytes).'
|
|
||||||
) % (len(body), cfg.CONF.max_json_body_size)
|
|
||||||
self.assertEqual(msg, six.text_type(error))
|
|
||||||
|
|
||||||
|
|
||||||
class GetSocketTestCase(base.SenlinTestCase):
|
class GetSocketTestCase(base.SenlinTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(GetSocketTestCase, self).setUp()
|
super(GetSocketTestCase, self).setUp()
|
||||||
self.useFixture(fixtures.MonkeyPatch(
|
self.useFixture(fixtures.MonkeyPatch(
|
||||||
"senlin.common.wsgi.get_bind_addr",
|
"senlin.api.common.wsgi.get_bind_addr",
|
||||||
lambda x, y: ('192.168.0.13', 1234)))
|
lambda x, y: ('192.168.0.13', 1234)))
|
||||||
addr_info_list = [(2, 1, 6, '', ('192.168.0.13', 80)),
|
addr_info_list = [(2, 1, 6, '', ('192.168.0.13', 80)),
|
||||||
(2, 2, 17, '', ('192.168.0.13', 80)),
|
(2, 2, 17, '', ('192.168.0.13', 80)),
|
||||||
(2, 3, 0, '', ('192.168.0.13', 80))]
|
(2, 3, 0, '', ('192.168.0.13', 80))]
|
||||||
self.useFixture(fixtures.MonkeyPatch(
|
self.useFixture(fixtures.MonkeyPatch(
|
||||||
"senlin.common.wsgi.socket.getaddrinfo",
|
"senlin.api.common.wsgi.socket.getaddrinfo",
|
||||||
lambda *x: addr_info_list))
|
lambda *x: addr_info_list))
|
||||||
self.useFixture(fixtures.MonkeyPatch(
|
self.useFixture(fixtures.MonkeyPatch(
|
||||||
"senlin.common.wsgi.time.time",
|
"senlin.api.common.wsgi.time.time",
|
||||||
mock.Mock(side_effect=[0, 1, 5, 10, 20, 35])))
|
mock.Mock(side_effect=[0, 1, 5, 10, 20, 35])))
|
||||||
wsgi.cfg.CONF.senlin_api.cert_file = '/etc/ssl/cert'
|
wsgi.cfg.CONF.senlin_api.cert_file = '/etc/ssl/cert'
|
||||||
wsgi.cfg.CONF.senlin_api.key_file = '/etc/ssl/key'
|
wsgi.cfg.CONF.senlin_api.key_file = '/etc/ssl/key'
|
||||||
|
@ -390,10 +261,10 @@ class GetSocketTestCase(base.SenlinTestCase):
|
||||||
def test_correct_configure_socket(self):
|
def test_correct_configure_socket(self):
|
||||||
mock_socket = mock.Mock()
|
mock_socket = mock.Mock()
|
||||||
self.useFixture(fixtures.MonkeyPatch(
|
self.useFixture(fixtures.MonkeyPatch(
|
||||||
'senlin.common.wsgi.ssl.wrap_socket',
|
'senlin.api.common.wsgi.ssl.wrap_socket',
|
||||||
mock_socket))
|
mock_socket))
|
||||||
self.useFixture(fixtures.MonkeyPatch(
|
self.useFixture(fixtures.MonkeyPatch(
|
||||||
'senlin.common.wsgi.eventlet.listen',
|
'senlin.api.common.wsgi.eventlet.listen',
|
||||||
lambda *x, **y: mock_socket))
|
lambda *x, **y: mock_socket))
|
||||||
server = wsgi.Server(name='senlin-api', conf=cfg.CONF.senlin_api)
|
server = wsgi.Server(name='senlin-api', conf=cfg.CONF.senlin_api)
|
||||||
server.default_port = 1234
|
server.default_port = 1234
|
||||||
|
@ -417,11 +288,11 @@ class GetSocketTestCase(base.SenlinTestCase):
|
||||||
|
|
||||||
def test_get_socket_with_bind_problems(self):
|
def test_get_socket_with_bind_problems(self):
|
||||||
self.useFixture(fixtures.MonkeyPatch(
|
self.useFixture(fixtures.MonkeyPatch(
|
||||||
'senlin.common.wsgi.eventlet.listen',
|
'senlin.api.common.wsgi.eventlet.listen',
|
||||||
mock.Mock(side_effect=(
|
mock.Mock(side_effect=(
|
||||||
[wsgi.socket.error(socket.errno.EADDRINUSE)] * 3 + [None]))))
|
[wsgi.socket.error(socket.errno.EADDRINUSE)] * 3 + [None]))))
|
||||||
self.useFixture(fixtures.MonkeyPatch(
|
self.useFixture(fixtures.MonkeyPatch(
|
||||||
'senlin.common.wsgi.ssl.wrap_socket',
|
'senlin.api.common.wsgi.ssl.wrap_socket',
|
||||||
lambda *x, **y: None))
|
lambda *x, **y: None))
|
||||||
|
|
||||||
self.assertRaises(RuntimeError,
|
self.assertRaises(RuntimeError,
|
||||||
|
@ -429,10 +300,10 @@ class GetSocketTestCase(base.SenlinTestCase):
|
||||||
|
|
||||||
def test_get_socket_with_unexpected_socket_errno(self):
|
def test_get_socket_with_unexpected_socket_errno(self):
|
||||||
self.useFixture(fixtures.MonkeyPatch(
|
self.useFixture(fixtures.MonkeyPatch(
|
||||||
'senlin.common.wsgi.eventlet.listen',
|
'senlin.api.common.wsgi.eventlet.listen',
|
||||||
mock.Mock(side_effect=wsgi.socket.error(socket.errno.ENOMEM))))
|
mock.Mock(side_effect=wsgi.socket.error(socket.errno.ENOMEM))))
|
||||||
self.useFixture(fixtures.MonkeyPatch(
|
self.useFixture(fixtures.MonkeyPatch(
|
||||||
'senlin.common.wsgi.ssl.wrap_socket',
|
'senlin.api.common.wsgi.ssl.wrap_socket',
|
||||||
lambda *x, **y: None))
|
lambda *x, **y: None))
|
||||||
self.assertRaises(wsgi.socket.error, wsgi.get_socket,
|
self.assertRaises(wsgi.socket.error, wsgi.get_socket,
|
||||||
wsgi.cfg.CONF.senlin_api, 1234)
|
wsgi.cfg.CONF.senlin_api, 1234)
|
|
@ -17,8 +17,8 @@ from oslo_log import log
|
||||||
from oslo_messaging._drivers import common as rpc_common
|
from oslo_messaging._drivers import common as rpc_common
|
||||||
from oslo_utils import encodeutils
|
from oslo_utils import encodeutils
|
||||||
|
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.common import consts
|
from senlin.common import consts
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.tests.unit.common import utils
|
from senlin.tests.unit.common import utils
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@ from oslo_utils import encodeutils
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
|
from senlin.api.common import wsgi
|
||||||
from senlin.api.openstack import versions
|
from senlin.api.openstack import versions
|
||||||
from senlin.common import wsgi
|
|
||||||
from senlin.tests.unit.common import base
|
from senlin.tests.unit.common import base
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
# 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 webob
|
|
||||||
|
|
||||||
from oslo_utils import encodeutils
|
|
||||||
from oslo_utils import timeutils as tu
|
|
||||||
|
|
||||||
from senlin.common import serializers
|
|
||||||
from senlin.tests.unit.common import base
|
|
||||||
|
|
||||||
|
|
||||||
class JSONResponseSerializerTest(base.SenlinTestCase):
|
|
||||||
|
|
||||||
def test_to_json(self):
|
|
||||||
fixture = {"key": "value"}
|
|
||||||
expected = '{"key": "value"}'
|
|
||||||
actual = serializers.JSONResponseSerializer().to_json(fixture)
|
|
||||||
self.assertEqual(expected, actual)
|
|
||||||
|
|
||||||
def test_to_json_with_date_format_value(self):
|
|
||||||
test_date = tu.parse_strtime("0001-03-08T02:00:00",
|
|
||||||
'%Y-%m-%dT%H:%M:%S')
|
|
||||||
fixture = {"date": test_date}
|
|
||||||
expected = '{"date": "0001-03-08T02:00:00"}'
|
|
||||||
actual = serializers.JSONResponseSerializer().to_json(fixture)
|
|
||||||
self.assertEqual(expected, actual)
|
|
||||||
|
|
||||||
def test_to_json_with_more_deep_format(self):
|
|
||||||
val = complex(1, 2)
|
|
||||||
fixture = {"is_public": True, "v": val}
|
|
||||||
expected = '{"is_public": true, "v": "(1+2j)"}'
|
|
||||||
actual = serializers.JSONResponseSerializer().to_json(fixture)
|
|
||||||
self.assertEqual(expected, actual)
|
|
||||||
|
|
||||||
def test_default(self):
|
|
||||||
fixture = {"key": "value"}
|
|
||||||
response = webob.Response()
|
|
||||||
serializers.JSONResponseSerializer().default(response, fixture)
|
|
||||||
self.assertEqual(200, response.status_int)
|
|
||||||
content_types = filter(lambda h: h[0] == 'Content-Type',
|
|
||||||
response.headerlist)
|
|
||||||
# NOTE: filter returns a iterator in python 3.
|
|
||||||
types = [t for t in content_types]
|
|
||||||
self.assertEqual(1, len(types))
|
|
||||||
self.assertEqual('application/json', response.content_type)
|
|
||||||
self.assertEqual('{"key": "value"}',
|
|
||||||
encodeutils.safe_decode(response.body))
|
|
|
@ -2,7 +2,7 @@
|
||||||
output_file = etc/senlin/senlin.conf.sample
|
output_file = etc/senlin/senlin.conf.sample
|
||||||
wrap_width = 119
|
wrap_width = 119
|
||||||
namespace = senlin.common.config
|
namespace = senlin.common.config
|
||||||
namespace = senlin.common.wsgi
|
namespace = senlin.api.common.wsgi
|
||||||
namespace = senlin.engine.health_manager
|
namespace = senlin.engine.health_manager
|
||||||
namespace = keystonemiddleware.auth_token
|
namespace = keystonemiddleware.auth_token
|
||||||
namespace = oslo.db
|
namespace = oslo.db
|
||||||
|
|
Loading…
Reference in New Issue