From 41ac7aeec26bdbc6a02826c75330bc2b72d3794d Mon Sep 17 00:00:00 2001 From: Mehdi Abaakouk Date: Thu, 6 Aug 2015 10:53:48 +0200 Subject: [PATCH] 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 --- doc/source/healthcheck_plugins.rst | 3 ++ doc/source/index.rst | 1 + doc/source/oslo_config.rst | 53 ++++++++++++++++++++++++++ oslo_middleware/base.py | 7 ++++ oslo_middleware/cors.py | 60 +++++++++++++++--------------- oslo_middleware/sizelimit.py | 2 +- oslo_middleware/ssl.py | 2 +- oslo_middleware/tests/test_cors.py | 10 ++--- 8 files changed, 101 insertions(+), 37 deletions(-) create mode 100644 doc/source/oslo_config.rst diff --git a/doc/source/healthcheck_plugins.rst b/doc/source/healthcheck_plugins.rst index c3e43ec..04683cc 100644 --- a/doc/source/healthcheck_plugins.rst +++ b/doc/source/healthcheck_plugins.rst @@ -2,5 +2,8 @@ Healthcheck middleware plugins ================================ +.. automodule:: oslo_middleware.healthcheck + :members: + .. automodule:: oslo_middleware.healthcheck.disable_by_file :members: diff --git a/doc/source/index.rst b/doc/source/index.rst index ebca9f6..055768d 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -10,4 +10,5 @@ Contents api healthcheck_plugins cors + oslo_config contributing diff --git a/doc/source/oslo_config.rst b/doc/source/oslo_config.rst new file mode 100644 index 0000000..09c83c6 --- /dev/null +++ b/doc/source/oslo_config.rst @@ -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` + diff --git a/oslo_middleware/base.py b/oslo_middleware/base.py index 6a6c3f5..852bc6a 100644 --- a/oslo_middleware/base.py +++ b/oslo_middleware/base.py @@ -63,6 +63,13 @@ class Middleware(object): # Fallback to global object 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): """Called on each request. diff --git a/oslo_middleware/cors.py b/oslo_middleware/cors.py index e2f00c5..07ff57a 100644 --- a/oslo_middleware/cors.py +++ b/oslo_middleware/cors.py @@ -76,19 +76,11 @@ class CORS(base.Middleware): super(CORS, self).__init__(application, conf) # Begin constructing our configuration hash. self.allowed_origins = {} - - self._init_from_oslo(self.oslo_conf) - self._init_from_conf() + self._init_conf() @classmethod def factory(cls, global_conf, allowed_origin, **local_conf): - # Ensures allowed_origin config exists - return super(CORS, cls).factory(global_conf, - allowed_origin=allowed_origin, - **local_conf) - - def _init_from_conf(self): - """Load configuration from paste.deploy + """factory method for paste.deploy allowed_origin: Protocol, host, and port for the allowed origin. 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. """ - if 'allowed_origin' in self.conf: - self.add_origin( - allowed_origin=self.conf['allowed_origin'], - allow_credentials=self.conf.get('allow_credentials', True), - 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')) + # Ensures allowed_origin config exists + return super(CORS, cls).factory(global_conf, + allowed_origin=allowed_origin, + **local_conf) - def _init_from_oslo(self, conf): + def _init_conf(self): '''Initialize this middleware from an oslo.config instance.''' # 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 # set in the global conf instance. This is done explicitly (instead @@ -119,24 +114,29 @@ class CORS(base.Middleware): # allowed_origin. subgroup_opts = copy.deepcopy(CORS_OPTS) cfg.set_defaults(subgroup_opts, - allow_credentials=conf.cors.allow_credentials, - expose_headers=conf.cors.expose_headers, - max_age=conf.cors.max_age, - allow_methods=conf.cors.allow_methods, - allow_headers=conf.cors.allow_headers) + allow_credentials=allow_credentials, + expose_headers=expose_headers, + max_age=max_age, + allow_methods=allow_methods, + allow_headers=allow_headers) # If the default configuration contains an allowed_origin, don't # forget to register that. - if conf.cors.allowed_origin: - self.add_origin(**conf.cors) + if allowed_origin: + 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 # prefixed with 'cors.' - for section in conf.list_all_sections(): + for section in self.oslo_conf.list_all_sections(): if section.startswith('cors.'): # Register with the preconstructed defaults - conf.register_opts(subgroup_opts, section) - self.add_origin(**conf[section]) + self.oslo_conf.register_opts(subgroup_opts, section) + self.add_origin(**self.oslo_conf[section]) def add_origin(self, allowed_origin, allow_credentials=True, expose_headers=None, max_age=None, allow_methods=None, diff --git a/oslo_middleware/sizelimit.py b/oslo_middleware/sizelimit.py index 2a82bf8..bbe8b6d 100644 --- a/oslo_middleware/sizelimit.py +++ b/oslo_middleware/sizelimit.py @@ -84,7 +84,7 @@ class RequestBodySizeLimiter(base.Middleware): @webob.dec.wsgify 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 req.content_length > max_size): msg = _("Request is too large.") diff --git a/oslo_middleware/ssl.py b/oslo_middleware/ssl.py index 835a8f2..dec22ad 100644 --- a/oslo_middleware/ssl.py +++ b/oslo_middleware/ssl.py @@ -37,7 +37,7 @@ class SSLMiddleware(base.Middleware): def process_request(self, req): 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('-', '_')) req.environ['wsgi.url_scheme'] = req.environ.get( self.header_name, req.environ['wsgi.url_scheme']) diff --git a/oslo_middleware/tests/test_cors.py b/oslo_middleware/tests/test_cors.py index 8eebf5b..86bbc79 100644 --- a/oslo_middleware/tests/test_cors.py +++ b/oslo_middleware/tests/test_cors.py @@ -131,11 +131,11 @@ class CORSTestFilterFactory(test_base.BaseTestCase): self.assertIn('http://valid.example.com', application.allowed_origins) config = application.allowed_origins['http://valid.example.com'] - self.assertEqual('False', config['allow_credentials']) - self.assertEqual('', config['max_age']) - self.assertEqual('', config['expose_headers']) - self.assertEqual('GET', config['allow_methods']) - self.assertEqual('', config['allow_headers']) + self.assertEqual(False, config['allow_credentials']) + self.assertEqual(None, config['max_age']) + self.assertEqual([], config['expose_headers']) + self.assertEqual(['GET'], config['allow_methods']) + self.assertEqual([], config['allow_headers']) def test_no_origin_fail(self): '''Assert that a filter factory with no allowed_origin fails.'''