Add versioning support
Implements blueprint murano-api-version-support Change-Id: Ib24a737c2817f503b4200117886102c4daab311a
This commit is contained in:
parent
2b0c534a0e
commit
17cfe56728
@ -1,8 +1,5 @@
|
||||
[pipeline:muranoapi]
|
||||
pipeline = authtoken context apiv1app
|
||||
|
||||
[app:apiv1app]
|
||||
paste.app_factory = muranoapi.api.v1.router:API.factory
|
||||
pipeline = versionnegotiation authtoken context rootapp
|
||||
|
||||
[filter:context]
|
||||
paste.filter_factory = muranoapi.api.middleware.context:ContextMiddleware.factory
|
||||
@ -11,3 +8,17 @@ paste.filter_factory = muranoapi.api.middleware.context:ContextMiddleware.factor
|
||||
#http://docs.openstack.org/developer/keystone/configuringservices.html
|
||||
[filter:authtoken]
|
||||
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
|
||||
|
||||
[composite:rootapp]
|
||||
use = egg:Paste#urlmap
|
||||
/: apiversions
|
||||
/v1: apiv1app
|
||||
|
||||
[app:apiversions]
|
||||
paste.app_factory = muranoapi.api.versions:create_resource
|
||||
|
||||
[app:apiv1app]
|
||||
paste.app_factory = muranoapi.api.v1.router:API.factory
|
||||
|
||||
[filter:versionnegotiation]
|
||||
paste.filter_factory = muranoapi.api.middleware.version_negotiation:VersionNegotiationFilter.factory
|
||||
|
96
muranoapi/api/middleware/version_negotiation.py
Normal file
96
muranoapi/api/middleware/version_negotiation.py
Normal file
@ -0,0 +1,96 @@
|
||||
# Copyright (c) 2014 Mirantis, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
A filter middleware that inspects the requested URI for a version string
|
||||
and/or Accept headers and attempts to negotiate an API controller to
|
||||
return
|
||||
"""
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from muranoapi.api import versions
|
||||
from muranoapi.openstack.common.gettextutils import _ # noqa
|
||||
import muranoapi.openstack.common.log as logging
|
||||
from muranoapi.openstack.common import wsgi
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VersionNegotiationFilter(wsgi.Middleware):
|
||||
@classmethod
|
||||
def factory(cls, global_conf, **local_conf):
|
||||
def filter(app):
|
||||
return cls(app)
|
||||
return filter
|
||||
|
||||
def __init__(self, app):
|
||||
self.versions_app = versions.Controller()
|
||||
super(VersionNegotiationFilter, self).__init__(app)
|
||||
|
||||
def process_request(self, req):
|
||||
"""Try to find a version first in the accept header, then the URL"""
|
||||
msg = _("Determining version of request: %(method)s %(path)s"
|
||||
" Accept: %(accept)s")
|
||||
args = {'method': req.method, 'path': req.path, 'accept': req.accept}
|
||||
LOG.debug(msg % args)
|
||||
|
||||
LOG.debug(_("Using url versioning"))
|
||||
# Remove version in url so it doesn't conflict later
|
||||
req_version = self._pop_path_info(req)
|
||||
|
||||
try:
|
||||
version = self._match_version_string(req_version)
|
||||
except ValueError:
|
||||
LOG.debug(_("Unknown version. Returning version choices."))
|
||||
return self.versions_app
|
||||
|
||||
req.environ['api.version'] = version
|
||||
req.path_info = ''.join(('/v', str(version), req.path_info))
|
||||
LOG.debug(_("Matched version: v%d"), version)
|
||||
LOG.debug('new path %s' % req.path_info)
|
||||
return None
|
||||
|
||||
def _match_version_string(self, subject):
|
||||
"""
|
||||
Given a string, tries to match a major and/or
|
||||
minor version number.
|
||||
|
||||
:param subject: The string to check
|
||||
:returns version found in the subject
|
||||
:raises ValueError if no acceptable version could be found
|
||||
"""
|
||||
if subject in ('v1',):
|
||||
major_version = 1
|
||||
else:
|
||||
raise ValueError()
|
||||
return major_version
|
||||
|
||||
def _pop_path_info(self, req):
|
||||
"""
|
||||
'Pops' off the next segment of PATH_INFO, returns the popped
|
||||
segment. Do NOT push it onto SCRIPT_NAME.
|
||||
"""
|
||||
path = req.path_info
|
||||
if not path:
|
||||
return None
|
||||
while path.startswith('/'):
|
||||
path = path[1:]
|
||||
idx = path.find('/')
|
||||
if idx == -1:
|
||||
idx = len(path)
|
||||
r = path[:idx]
|
||||
req.path_info = path[idx:]
|
||||
return r
|
@ -19,7 +19,6 @@ from muranoapi.common import utils
|
||||
from muranoapi.db import models
|
||||
from muranoapi.db import session as db_session
|
||||
|
||||
|
||||
from muranoapi.openstack.common.gettextutils import _ # noqa
|
||||
from muranoapi.openstack.common import log as logging
|
||||
from muranoapi.openstack.common import wsgi
|
||||
|
@ -15,7 +15,6 @@
|
||||
from sqlalchemy import desc
|
||||
from webob import exc
|
||||
|
||||
|
||||
from muranoapi.api.v1 import statistics
|
||||
from muranoapi.common import utils
|
||||
from muranoapi.db import models
|
||||
@ -23,7 +22,6 @@ from muranoapi.db.services import core_services
|
||||
from muranoapi.db.services import environments as envs
|
||||
from muranoapi.db import session as db_session
|
||||
|
||||
|
||||
from muranoapi.openstack.common.gettextutils import _ # noqa
|
||||
from muranoapi.openstack.common import log as logging
|
||||
from muranoapi.openstack.common import wsgi
|
||||
|
@ -11,7 +11,6 @@
|
||||
# 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 routes
|
||||
|
||||
from muranoapi.api.v1 import deployments
|
||||
|
62
muranoapi/api/versions.py
Normal file
62
muranoapi/api/versions.py
Normal file
@ -0,0 +1,62 @@
|
||||
# Copyright (c) 2014 Mirantis, Inc.
|
||||
#
|
||||
# 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 httplib
|
||||
|
||||
from oslo.config import cfg
|
||||
import webob.dec
|
||||
|
||||
from muranoapi.openstack.common import jsonutils
|
||||
from muranoapi.openstack.common import wsgi
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class Controller(object):
|
||||
|
||||
"""A wsgi controller that reports which API versions are supported."""
|
||||
|
||||
def index(self, req):
|
||||
"""Respond to a request for all OpenStack API versions."""
|
||||
def build_version_object(version, path, status):
|
||||
return {
|
||||
'id': 'v%s' % version,
|
||||
'status': status,
|
||||
'links': [
|
||||
{
|
||||
'rel': 'self',
|
||||
'href': '%s/%s/' % (req.host_url, path),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
version_objs = []
|
||||
version_objs.extend([
|
||||
build_version_object(1.0, 'v1', 'CURRENT'),
|
||||
])
|
||||
|
||||
response = webob.Response(request=req,
|
||||
status=httplib.MULTIPLE_CHOICES,
|
||||
content_type='application/json')
|
||||
response.body = jsonutils.dumps(dict(versions=version_objs))
|
||||
return response
|
||||
|
||||
@webob.dec.wsgify(RequestClass=wsgi.Request)
|
||||
def __call__(self, req):
|
||||
return self.index(req)
|
||||
|
||||
|
||||
def create_resource(conf):
|
||||
return wsgi.Resource(Controller())
|
Loading…
Reference in New Issue
Block a user