Reorganize pipelines for multiple api versions
* Partially implements bp api-2 Change-Id: Ie942c54e0ba294da661de870a95d685a9b8966de
This commit is contained in:
parent
8e9e0cadaf
commit
35ed310555
etc
glance
api
common
tests
@ -1,6 +1,6 @@
|
||||
# Default minimal pipeline
|
||||
[pipeline:glance-api]
|
||||
pipeline = versionnegotiation context apiv1app
|
||||
pipeline = versionnegotiation context rootapp
|
||||
|
||||
# Use the following pipeline for keystone auth
|
||||
# i.e. in glance-api.conf:
|
||||
@ -8,7 +8,7 @@ pipeline = versionnegotiation context apiv1app
|
||||
# flavor = keystone
|
||||
#
|
||||
[pipeline:glance-api-keystone]
|
||||
pipeline = versionnegotiation authtoken context apiv1app
|
||||
pipeline = versionnegotiation authtoken context rootapp
|
||||
|
||||
# Use the following pipeline to enable transparent caching of image files
|
||||
# i.e. in glance-api.conf:
|
||||
@ -16,7 +16,7 @@ pipeline = versionnegotiation authtoken context apiv1app
|
||||
# flavor = caching
|
||||
#
|
||||
[pipeline:glance-api-caching]
|
||||
pipeline = versionnegotiation context cache apiv1app
|
||||
pipeline = versionnegotiation context cache rootapp
|
||||
|
||||
# Use the following pipeline for keystone auth with caching
|
||||
# i.e. in glance-api.conf:
|
||||
@ -24,7 +24,7 @@ pipeline = versionnegotiation context cache apiv1app
|
||||
# flavor = keystone+caching
|
||||
#
|
||||
[pipeline:glance-api-keystone+caching]
|
||||
pipeline = versionnegotiation authtoken context cache apiv1app
|
||||
pipeline = versionnegotiation authtoken context cache rootapp
|
||||
|
||||
# Use the following pipeline to enable the Image Cache Management API
|
||||
# i.e. in glance-api.conf:
|
||||
@ -32,7 +32,7 @@ pipeline = versionnegotiation authtoken context cache apiv1app
|
||||
# flavor = cachemanagement
|
||||
#
|
||||
[pipeline:glance-api-cachemanagement]
|
||||
pipeline = versionnegotiation context cache cachemanage apiv1app
|
||||
pipeline = versionnegotiation context cache cachemanage rootapp
|
||||
|
||||
# Use the following pipeline for keystone auth with cache management
|
||||
# i.e. in glance-api.conf:
|
||||
@ -40,7 +40,15 @@ pipeline = versionnegotiation context cache cachemanage apiv1app
|
||||
# flavor = keystone+cachemanagement
|
||||
#
|
||||
[pipeline:glance-api-keystone+cachemanagement]
|
||||
pipeline = versionnegotiation authtoken context cache cachemanage apiv1app
|
||||
pipeline = versionnegotiation authtoken context cache cachemanage rootapp
|
||||
|
||||
[composite:rootapp]
|
||||
use = egg:Paste#urlmap
|
||||
/: apiversions
|
||||
/v1: apiv1app
|
||||
|
||||
[app:apiversions]
|
||||
paste.app_factory = glance.api.versions:create_resource
|
||||
|
||||
[app:apiv1app]
|
||||
paste.app_factory = glance.common.wsgi:app_factory
|
||||
|
@ -77,7 +77,7 @@ class CacheManageFilter(wsgi.Middleware):
|
||||
|
||||
def process_request(self, request):
|
||||
# Map request to our resource object if we can handle it
|
||||
match = self._mapper.match(request.path, request.environ)
|
||||
match = self._mapper.match(request.path_info, request.environ)
|
||||
if match:
|
||||
request.environ['wsgiorg.routing_args'] = (None, match)
|
||||
return self._resource(request)
|
||||
|
@ -65,6 +65,8 @@ class VersionNegotiationFilter(wsgi.Middleware):
|
||||
req.environ['api.minor_version'])
|
||||
# Strip the version from the path
|
||||
req.path_info_pop()
|
||||
args = (req.environ['api.major_version'], req.path_info)
|
||||
req.path_info = '/v%s%s' % args
|
||||
return None
|
||||
else:
|
||||
logger.debug(_("Unknown version in versioned URI: %d.%d. "
|
||||
@ -85,6 +87,8 @@ class VersionNegotiationFilter(wsgi.Middleware):
|
||||
"Version: %d.%d"),
|
||||
req.environ['api.major_version'],
|
||||
req.environ['api.minor_version'])
|
||||
args = (req.environ['api.major_version'], req.path_info)
|
||||
req.path_info = '/v%s%s' % args
|
||||
return None
|
||||
else:
|
||||
logger.debug(_("Unknown version in accept header: %d.%d..."
|
||||
|
@ -20,6 +20,8 @@ import json
|
||||
|
||||
import webob.dec
|
||||
|
||||
from glance.common import wsgi
|
||||
|
||||
|
||||
class Controller(object):
|
||||
|
||||
@ -28,8 +30,7 @@ class Controller(object):
|
||||
def __init__(self, conf):
|
||||
self.conf = conf
|
||||
|
||||
@webob.dec.wsgify
|
||||
def __call__(self, req):
|
||||
def index(self, req):
|
||||
"""Respond to a request for all OpenStack API versions."""
|
||||
def build_version_object(version, path, status):
|
||||
return {
|
||||
@ -55,5 +56,10 @@ class Controller(object):
|
||||
response.body = json.dumps(dict(versions=version_objs))
|
||||
return response
|
||||
|
||||
def get_href(self, req, version):
|
||||
return "%s/v%s/" % (req.host_url, version)
|
||||
@webob.dec.wsgify(RequestClass=wsgi.Request)
|
||||
def __call__(self, req):
|
||||
return self.index(req)
|
||||
|
||||
|
||||
def create_resource(conf):
|
||||
return wsgi.Resource(Controller(conf))
|
||||
|
@ -451,7 +451,7 @@ class Resource(object):
|
||||
may raise a webob.exc exception or return a dict, which will be
|
||||
serialized by requested content type.
|
||||
"""
|
||||
def __init__(self, controller, deserializer, serializer):
|
||||
def __init__(self, controller, deserializer=None, serializer=None):
|
||||
"""
|
||||
:param controller: object that implement methods created by routes lib
|
||||
:param deserializer: object that supports webob request deserialization
|
||||
@ -460,8 +460,8 @@ class Resource(object):
|
||||
through controller-like actions
|
||||
"""
|
||||
self.controller = controller
|
||||
self.serializer = serializer
|
||||
self.deserializer = deserializer
|
||||
self.serializer = serializer or JSONResponseSerializer()
|
||||
self.deserializer = deserializer or JSONRequestDeserializer()
|
||||
|
||||
@webob.dec.wsgify(RequestClass=Request)
|
||||
def __call__(self, request):
|
||||
|
@ -252,16 +252,24 @@ policy_default_rule = %(policy_default_rule)s
|
||||
flavor = %(deployment_flavor)s
|
||||
"""
|
||||
self.paste_conf_base = """[pipeline:glance-api]
|
||||
pipeline = versionnegotiation context apiv1app
|
||||
pipeline = versionnegotiation context rootapp
|
||||
|
||||
[pipeline:glance-api-caching]
|
||||
pipeline = versionnegotiation context cache apiv1app
|
||||
pipeline = versionnegotiation context cache rootapp
|
||||
|
||||
[pipeline:glance-api-cachemanagement]
|
||||
pipeline = versionnegotiation context cache cache_manage apiv1app
|
||||
pipeline = versionnegotiation context cache cache_manage rootapp
|
||||
|
||||
[pipeline:glance-api-fakeauth]
|
||||
pipeline = versionnegotiation fakeauth context apiv1app
|
||||
pipeline = versionnegotiation fakeauth context rootapp
|
||||
|
||||
[composite:rootapp]
|
||||
use = egg:Paste#urlmap
|
||||
/: apiversions
|
||||
/v1: apiv1app
|
||||
|
||||
[app:apiversions]
|
||||
paste.app_factory = glance.api.versions:create_resource
|
||||
|
||||
[app:apiv1app]
|
||||
paste.app_factory = glance.common.wsgi:app_factory
|
||||
|
@ -56,7 +56,7 @@ class TestRootApi(functional.FunctionalTest):
|
||||
# 0. GET / with no Accept: header
|
||||
# Verify version choices returned.
|
||||
# Bug lp:803260 no Accept header causes a 500 in glance-api
|
||||
path = 'http://%s:%d/' % ('0.0.0.0', self.api_port)
|
||||
path = 'http://%s:%d' % ('0.0.0.0', self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'GET')
|
||||
self.assertEqual(response.status, 300)
|
||||
|
@ -18,7 +18,6 @@
|
||||
"""Stubouts, mocks and fixtures for the test suite"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
try:
|
||||
import sendfile
|
||||
@ -28,11 +27,9 @@ except ImportError:
|
||||
|
||||
import webob
|
||||
|
||||
from glance.api.middleware import version_negotiation
|
||||
from glance.api.v1 import router
|
||||
import glance.common.client
|
||||
from glance.common import context
|
||||
from glance.common import exception
|
||||
from glance.registry.api import v1 as rserver
|
||||
from glance.tests import utils
|
||||
|
||||
@ -118,8 +115,12 @@ def stub_out_registry_and_store_server(stubs, base_dir):
|
||||
def close(self):
|
||||
return True
|
||||
|
||||
def _clean_url(self, url):
|
||||
#TODO(bcwaldon): Fix the hack that strips off v1
|
||||
return url.replace('/v1', '', 1) if url.startswith('/v1') else url
|
||||
|
||||
def putrequest(self, method, url):
|
||||
self.req = webob.Request.blank("/" + url.lstrip("/"))
|
||||
self.req = webob.Request.blank(self._clean_url(url))
|
||||
if SENDFILE_SUPPORTED:
|
||||
fake_sendfile = FakeSendFile(self.req)
|
||||
stubs.Set(sendfile, 'sendfile', fake_sendfile.sendfile)
|
||||
@ -138,7 +139,7 @@ def stub_out_registry_and_store_server(stubs, base_dir):
|
||||
self.req.body += data.split("\r\n")[1]
|
||||
|
||||
def request(self, method, url, body=None, headers={}):
|
||||
self.req = webob.Request.blank("/" + url.lstrip("/"))
|
||||
self.req = webob.Request.blank(self._clean_url(url))
|
||||
self.req.method = method
|
||||
if headers:
|
||||
self.req.headers = headers
|
||||
@ -157,9 +158,7 @@ def stub_out_registry_and_store_server(stubs, base_dir):
|
||||
'filesystem_store_datadir': base_dir,
|
||||
'policy_file': os.path.join(base_dir, 'policy.json'),
|
||||
})
|
||||
api = version_negotiation.VersionNegotiationFilter(
|
||||
context.ContextMiddleware(router.API(conf), conf),
|
||||
conf)
|
||||
api = context.ContextMiddleware(router.API(conf), conf)
|
||||
res = self.req.get_response(api)
|
||||
|
||||
# httplib.Response has a read() method...fake it out
|
||||
|
@ -20,8 +20,6 @@ import json
|
||||
import webob
|
||||
|
||||
from glance.api import versions
|
||||
from glance import client
|
||||
from glance.common import exception
|
||||
from glance.tests.unit import base
|
||||
from glance.tests import utils
|
||||
|
||||
@ -35,7 +33,7 @@ class VersionsTest(base.IsolatedUnitTest):
|
||||
req.accept = 'application/json'
|
||||
config_opts = {'bind_host': '0.0.0.0', 'bind_port': 9292}
|
||||
conf = utils.TestConfigOpts(config_opts)
|
||||
res = req.get_response(versions.Controller(conf))
|
||||
res = versions.Controller(conf).index(req)
|
||||
self.assertEqual(res.status_int, 300)
|
||||
self.assertEqual(res.content_type, 'application/json')
|
||||
results = json.loads(res.body)['versions']
|
||||
@ -57,7 +55,3 @@ class VersionsTest(base.IsolatedUnitTest):
|
||||
},
|
||||
]
|
||||
self.assertEqual(results, expected)
|
||||
|
||||
def test_client_handles_versions(self):
|
||||
api_client = client.Client('0.0.0.0', doc_root='')
|
||||
self.assertRaises(exception.MultipleChoices, api_client.get_images)
|
||||
|
Loading…
x
Reference in New Issue
Block a user