Allow to get option from paste-deploy
This change allows any middleware that use oslo.config to be configured via paste-deploy, like the cors does. Related-bug: #1482086 Change-Id: Ibb3e951b45b51c9bc602c9113df18a58226d92d1
This commit is contained in:
parent
e744501c47
commit
41ac7aeec2
@ -2,5 +2,8 @@
|
|||||||
Healthcheck middleware plugins
|
Healthcheck middleware plugins
|
||||||
================================
|
================================
|
||||||
|
|
||||||
|
.. automodule:: oslo_middleware.healthcheck
|
||||||
|
:members:
|
||||||
|
|
||||||
.. automodule:: oslo_middleware.healthcheck.disable_by_file
|
.. automodule:: oslo_middleware.healthcheck.disable_by_file
|
||||||
:members:
|
:members:
|
||||||
|
@ -10,4 +10,5 @@ Contents
|
|||||||
api
|
api
|
||||||
healthcheck_plugins
|
healthcheck_plugins
|
||||||
cors
|
cors
|
||||||
|
oslo_config
|
||||||
contributing
|
contributing
|
||||||
|
53
doc/source/oslo_config.rst
Normal file
53
doc/source/oslo_config.rst
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
=============================
|
||||||
|
Middlewares and configuration
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Middlewares can be configured in multiple fashion depending of the
|
||||||
|
application needs. Here is some use-cases:
|
||||||
|
|
||||||
|
Configuration from the application
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
The application code will looks like::
|
||||||
|
|
||||||
|
from oslo_middleware import sizelimit
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
conf = cfg.ConfigOpts()
|
||||||
|
app = sizelimit.RequestBodySizeLimiter(your_wsgi_application, conf)
|
||||||
|
|
||||||
|
|
||||||
|
Configuration with paste-deploy and the oslo.config
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
The paste filter (in /etc/my_app/api-paste.ini) will looks like::
|
||||||
|
|
||||||
|
[filter:sizelimit]
|
||||||
|
paste.filter_factory = oslo_middleware.sizelimit:RequestBodySizeLimiter.factory
|
||||||
|
# In case of the application doesn't use the global oslo.config
|
||||||
|
# object. The middleware must known the app name to load
|
||||||
|
# the application configuration, by setting this:
|
||||||
|
# oslo_config_project = my_app
|
||||||
|
|
||||||
|
The oslo.config file of the application (eg: /etc/my_app/my_app.conf) will looks like::
|
||||||
|
|
||||||
|
[oslo_middleware]
|
||||||
|
max_request_body_size=1000
|
||||||
|
|
||||||
|
|
||||||
|
Configuration with pastedeploy only
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
The paste filter (in /etc/my_app/api-paste.ini) will looks like::
|
||||||
|
|
||||||
|
[filter:sizelimit]
|
||||||
|
paste.filter_factory = oslo_middleware.sizelimit:RequestBodySizeLimiter.factory
|
||||||
|
max_request_body_size=1000
|
||||||
|
|
||||||
|
This will override any configuration done via oslo.config
|
||||||
|
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
healtcheck middleware does not yet use oslo.config, see :doc:`healthcheck_plugins`
|
||||||
|
|
@ -63,6 +63,13 @@ class Middleware(object):
|
|||||||
# Fallback to global object
|
# Fallback to global object
|
||||||
self.oslo_conf = cfg.CONF
|
self.oslo_conf = cfg.CONF
|
||||||
|
|
||||||
|
def _conf_get(self, key, group="oslo_middleware"):
|
||||||
|
if key in self.conf:
|
||||||
|
# Validate value type
|
||||||
|
self.oslo_conf.set_override(key, self.conf[key], group=group,
|
||||||
|
enforce_type=True)
|
||||||
|
return getattr(getattr(self.oslo_conf, group), key)
|
||||||
|
|
||||||
def process_request(self, req):
|
def process_request(self, req):
|
||||||
"""Called on each request.
|
"""Called on each request.
|
||||||
|
|
||||||
|
@ -76,19 +76,11 @@ class CORS(base.Middleware):
|
|||||||
super(CORS, self).__init__(application, conf)
|
super(CORS, self).__init__(application, conf)
|
||||||
# Begin constructing our configuration hash.
|
# Begin constructing our configuration hash.
|
||||||
self.allowed_origins = {}
|
self.allowed_origins = {}
|
||||||
|
self._init_conf()
|
||||||
self._init_from_oslo(self.oslo_conf)
|
|
||||||
self._init_from_conf()
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def factory(cls, global_conf, allowed_origin, **local_conf):
|
def factory(cls, global_conf, allowed_origin, **local_conf):
|
||||||
# Ensures allowed_origin config exists
|
"""factory method for paste.deploy
|
||||||
return super(CORS, cls).factory(global_conf,
|
|
||||||
allowed_origin=allowed_origin,
|
|
||||||
**local_conf)
|
|
||||||
|
|
||||||
def _init_from_conf(self):
|
|
||||||
"""Load configuration from paste.deploy
|
|
||||||
|
|
||||||
allowed_origin: Protocol, host, and port for the allowed origin.
|
allowed_origin: Protocol, host, and port for the allowed origin.
|
||||||
allow_credentials: Whether to permit credentials.
|
allow_credentials: Whether to permit credentials.
|
||||||
@ -98,20 +90,23 @@ class CORS(base.Middleware):
|
|||||||
allow_headers: List of HTTP headers to permit from the client.
|
allow_headers: List of HTTP headers to permit from the client.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if 'allowed_origin' in self.conf:
|
# Ensures allowed_origin config exists
|
||||||
self.add_origin(
|
return super(CORS, cls).factory(global_conf,
|
||||||
allowed_origin=self.conf['allowed_origin'],
|
allowed_origin=allowed_origin,
|
||||||
allow_credentials=self.conf.get('allow_credentials', True),
|
**local_conf)
|
||||||
expose_headers=self.conf.get('expose_headers'),
|
|
||||||
max_age=self.conf.get('max_age'),
|
|
||||||
allow_methods=self.conf.get('allow_methods'),
|
|
||||||
allow_headers=self.conf.get('allow_headers'))
|
|
||||||
|
|
||||||
def _init_from_oslo(self, conf):
|
def _init_conf(self):
|
||||||
'''Initialize this middleware from an oslo.config instance.'''
|
'''Initialize this middleware from an oslo.config instance.'''
|
||||||
|
|
||||||
# First, check the configuration and register global options.
|
# First, check the configuration and register global options.
|
||||||
conf.register_opts(CORS_OPTS, 'cors')
|
self.oslo_conf.register_opts(CORS_OPTS, 'cors')
|
||||||
|
|
||||||
|
allowed_origin = self._conf_get('allowed_origin', 'cors')
|
||||||
|
allow_credentials = self._conf_get('allow_credentials', 'cors')
|
||||||
|
expose_headers = self._conf_get('expose_headers', 'cors')
|
||||||
|
max_age = self._conf_get('max_age', 'cors')
|
||||||
|
allow_methods = self._conf_get('allow_methods', 'cors')
|
||||||
|
allow_headers = self._conf_get('allow_headers', 'cors')
|
||||||
|
|
||||||
# Clone our original CORS_OPTS, and set the defaults to whatever is
|
# Clone our original CORS_OPTS, and set the defaults to whatever is
|
||||||
# set in the global conf instance. This is done explicitly (instead
|
# set in the global conf instance. This is done explicitly (instead
|
||||||
@ -119,24 +114,29 @@ class CORS(base.Middleware):
|
|||||||
# allowed_origin.
|
# allowed_origin.
|
||||||
subgroup_opts = copy.deepcopy(CORS_OPTS)
|
subgroup_opts = copy.deepcopy(CORS_OPTS)
|
||||||
cfg.set_defaults(subgroup_opts,
|
cfg.set_defaults(subgroup_opts,
|
||||||
allow_credentials=conf.cors.allow_credentials,
|
allow_credentials=allow_credentials,
|
||||||
expose_headers=conf.cors.expose_headers,
|
expose_headers=expose_headers,
|
||||||
max_age=conf.cors.max_age,
|
max_age=max_age,
|
||||||
allow_methods=conf.cors.allow_methods,
|
allow_methods=allow_methods,
|
||||||
allow_headers=conf.cors.allow_headers)
|
allow_headers=allow_headers)
|
||||||
|
|
||||||
# If the default configuration contains an allowed_origin, don't
|
# If the default configuration contains an allowed_origin, don't
|
||||||
# forget to register that.
|
# forget to register that.
|
||||||
if conf.cors.allowed_origin:
|
if allowed_origin:
|
||||||
self.add_origin(**conf.cors)
|
self.add_origin(allowed_origin=allowed_origin,
|
||||||
|
allow_credentials=allow_credentials,
|
||||||
|
expose_headers=expose_headers,
|
||||||
|
max_age=max_age,
|
||||||
|
allow_methods=allow_methods,
|
||||||
|
allow_headers=allow_headers)
|
||||||
|
|
||||||
# Iterate through all the loaded config sections, looking for ones
|
# Iterate through all the loaded config sections, looking for ones
|
||||||
# prefixed with 'cors.'
|
# prefixed with 'cors.'
|
||||||
for section in conf.list_all_sections():
|
for section in self.oslo_conf.list_all_sections():
|
||||||
if section.startswith('cors.'):
|
if section.startswith('cors.'):
|
||||||
# Register with the preconstructed defaults
|
# Register with the preconstructed defaults
|
||||||
conf.register_opts(subgroup_opts, section)
|
self.oslo_conf.register_opts(subgroup_opts, section)
|
||||||
self.add_origin(**conf[section])
|
self.add_origin(**self.oslo_conf[section])
|
||||||
|
|
||||||
def add_origin(self, allowed_origin, allow_credentials=True,
|
def add_origin(self, allowed_origin, allow_credentials=True,
|
||||||
expose_headers=None, max_age=None, allow_methods=None,
|
expose_headers=None, max_age=None, allow_methods=None,
|
||||||
|
@ -84,7 +84,7 @@ class RequestBodySizeLimiter(base.Middleware):
|
|||||||
|
|
||||||
@webob.dec.wsgify
|
@webob.dec.wsgify
|
||||||
def __call__(self, req):
|
def __call__(self, req):
|
||||||
max_size = self.oslo_conf.oslo_middleware.max_request_body_size
|
max_size = self._conf_get('max_request_body_size')
|
||||||
if (req.content_length is not None and
|
if (req.content_length is not None and
|
||||||
req.content_length > max_size):
|
req.content_length > max_size):
|
||||||
msg = _("Request is too large.")
|
msg = _("Request is too large.")
|
||||||
|
@ -37,7 +37,7 @@ class SSLMiddleware(base.Middleware):
|
|||||||
|
|
||||||
def process_request(self, req):
|
def process_request(self, req):
|
||||||
self.header_name = 'HTTP_{0}'.format(
|
self.header_name = 'HTTP_{0}'.format(
|
||||||
self.oslo_conf.oslo_middleware.secure_proxy_ssl_header.upper()
|
self._conf_get('secure_proxy_ssl_header').upper()
|
||||||
.replace('-', '_'))
|
.replace('-', '_'))
|
||||||
req.environ['wsgi.url_scheme'] = req.environ.get(
|
req.environ['wsgi.url_scheme'] = req.environ.get(
|
||||||
self.header_name, req.environ['wsgi.url_scheme'])
|
self.header_name, req.environ['wsgi.url_scheme'])
|
||||||
|
@ -131,11 +131,11 @@ class CORSTestFilterFactory(test_base.BaseTestCase):
|
|||||||
self.assertIn('http://valid.example.com', application.allowed_origins)
|
self.assertIn('http://valid.example.com', application.allowed_origins)
|
||||||
|
|
||||||
config = application.allowed_origins['http://valid.example.com']
|
config = application.allowed_origins['http://valid.example.com']
|
||||||
self.assertEqual('False', config['allow_credentials'])
|
self.assertEqual(False, config['allow_credentials'])
|
||||||
self.assertEqual('', config['max_age'])
|
self.assertEqual(None, config['max_age'])
|
||||||
self.assertEqual('', config['expose_headers'])
|
self.assertEqual([], config['expose_headers'])
|
||||||
self.assertEqual('GET', config['allow_methods'])
|
self.assertEqual(['GET'], config['allow_methods'])
|
||||||
self.assertEqual('', config['allow_headers'])
|
self.assertEqual([], config['allow_headers'])
|
||||||
|
|
||||||
def test_no_origin_fail(self):
|
def test_no_origin_fail(self):
|
||||||
'''Assert that a filter factory with no allowed_origin fails.'''
|
'''Assert that a filter factory with no allowed_origin fails.'''
|
||||||
|
Loading…
x
Reference in New Issue
Block a user