Allow to use oslo.config without global CONF

If an application doesn't use a global configuration object and load
the middleware with api paste, they are no ways to read the
configuration options from the application configuration file.

This change fixes that, the api paste config will looks like:

  [filter:authtoken]
  paste.filter_factory = keystonemiddleware.auth_token:filter_factory
  oslo_config_project = aodh

With this, the keystonemiddleware will automatically load
the configuration of the project aodh with a local oslo.config object
instead of the global one.

This allows application to not rely of the global oslo.config object
and continue to use paste and keystonemiddleware.

Closes-bug: #1482078
Related-bug: #1406218
Change-Id: I48c3d6a6a5486c9c035a15a75c025be7f5abaab4
This commit is contained in:
Mehdi Abaakouk 2015-08-04 10:32:47 +02:00
parent e7e5971139
commit ba68a74e65
3 changed files with 73 additions and 1 deletions

View File

@ -271,6 +271,20 @@ and set in ``nova.conf``:
Note that middleware parameters in paste config take priority, they must be
removed to use values in [keystone_authtoken] section.
If the service doesn't use the global oslo.config object (CONF), then the
olso config project name can be set it in paste config and
keystonemiddleware will load the project configuration itself.
Optionally the location of the configuration file can be set if oslo.config
is not able to discover it.
.. code-block:: ini
[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
oslo_config_project = nova
# oslo_config_file = /not_discoverable_location/nova.conf
Configuration Options
---------------------

View File

@ -622,6 +622,27 @@ class AuthProtocol(_BaseAuthProtocol):
# conf value into correct type.
self._conf = _conf_values_type_convert(conf)
# NOTE(sileht): If we don't want to use oslo.config global object
# we can set the paste "oslo_config_project" and the middleware
# will load the configuration with a local oslo.config object.
self._local_oslo_config = None
if 'oslo_config_project' in conf:
if 'oslo_config_file' in conf:
default_config_files = [conf['oslo_config_file']]
else:
default_config_files = None
self._local_oslo_config = cfg.ConfigOpts()
self._local_oslo_config(
{}, project=conf['oslo_config_project'],
default_config_files=default_config_files,
validate_default_values=True)
self._local_oslo_config.register_opts(
_OPTS, group=_base.AUTHTOKEN_GROUP)
auth.register_conf_options(self._local_oslo_config,
group=_base.AUTHTOKEN_GROUP)
super(AuthProtocol, self).__init__(
app,
log=log,
@ -668,6 +689,8 @@ class AuthProtocol(_BaseAuthProtocol):
# try config from paste-deploy first
if name in self._conf:
return self._conf[name]
elif self._local_oslo_config:
return self._local_oslo_config[group][name]
else:
return CONF[group][name]
@ -937,7 +960,8 @@ class AuthProtocol(_BaseAuthProtocol):
plugin_kwargs['log'] = self.log
plugin_opts = plugin_class.get_options()
CONF.register_opts(plugin_opts, group=group)
(self._local_oslo_config or CONF).register_opts(plugin_opts,
group=group)
for opt in plugin_opts:
val = self._conf_get(opt.dest, group=group)
@ -960,6 +984,9 @@ class AuthProtocol(_BaseAuthProtocol):
try:
return self._conf_get('project')
except cfg.NoSuchOptError:
# Prefer local oslo config object
if self._local_oslo_config:
return self._local_oslo_config.project
try:
# CONF.project will exist only if the service uses
# oslo.config. It will only be set when the project

View File

@ -32,6 +32,7 @@ import mock
from oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_utils import timeutils
from oslotest import createfile
import six
import testresources
import testtools
@ -2470,5 +2471,35 @@ class TestAuthPluginUserAgentGeneration(BaseAuthTokenMiddlewareTest):
self.assertEqual(expected_ua, sess.user_agent)
class TestAuthPluginLocalOsloConfig(BaseAuthTokenMiddlewareTest):
def test_project_in_local_oslo_configuration(self):
options = {
'auth_plugin': 'password',
'auth_uri': uuid.uuid4().hex,
'password': uuid.uuid4().hex,
}
content = ("[keystone_authtoken]\n"
"auth_plugin=%(auth_plugin)s\n"
"auth_uri=%(auth_uri)s\n"
"password=%(password)s\n" % options)
conf_file_fixture = self.useFixture(
createfile.CreateFileWithContent("my_app", content))
conf = {'oslo_config_project': 'my_app',
'oslo_config_file': conf_file_fixture.path}
app = self._create_app(conf, uuid.uuid4().hex)
for option in options:
self.assertEqual(options[option], app._conf_get(option))
def _create_app(self, conf, project_version):
fake_pkg_resources = mock.Mock()
fake_pkg_resources.get_distribution().version = project_version
body = uuid.uuid4().hex
with mock.patch('keystonemiddleware.auth_token.pkg_resources',
new=fake_pkg_resources):
return self.create_simple_middleware(body=body, conf=conf)
def load_tests(loader, tests, pattern):
return testresources.OptimisingTestSuite(tests)