diff --git a/keystoneclient/auth/base.py b/keystoneclient/auth/base.py index a6c54f19a..91cf86adc 100644 --- a/keystoneclient/auth/base.py +++ b/keystoneclient/auth/base.py @@ -255,13 +255,11 @@ class BaseAuthPlugin(object): :returns: An auth plugin, or None if a name is not provided. :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` """ - for opt in cls.get_options(): - val = getattr(namespace, 'os_%s' % opt.dest) - if val is not None: - val = opt.type(val) - kwargs.setdefault(opt.dest, val) - return cls.load_from_options(**kwargs) + def _getter(opt): + return getattr(namespace, 'os_%s' % opt.dest) + + return cls.load_from_options_getter(_getter, **kwargs) @classmethod def register_conf_options(cls, conf, group): @@ -287,10 +285,34 @@ class BaseAuthPlugin(object): :returns: An authentication Plugin. :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` """ + + def _getter(opt): + return conf[group][opt.dest] + + return cls.load_from_options_getter(_getter, **kwargs) + + @classmethod + def load_from_options_getter(cls, getter, **kwargs): + """Load a plugin from a getter function that returns appropriate values + + To handle cases other than the provided CONF and CLI loading you can + specify a custom loader function that will be queried for the option + value. + + The getter is a function that takes one value, an + :py:class:`oslo_config.cfg.Opt` and returns a value to load with. + + :param getter: A function that returns a value for the given opt. + :type getter: callable + + :returns: An authentication Plugin. + :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` + """ + plugin_opts = cls.get_options() for opt in plugin_opts: - val = conf[group][opt.dest] + val = getter(opt) if val is not None: val = opt.type(val) kwargs.setdefault(opt.dest, val) diff --git a/keystoneclient/tests/unit/auth/test_loading.py b/keystoneclient/tests/unit/auth/test_loading.py new file mode 100644 index 000000000..f8ef3b75a --- /dev/null +++ b/keystoneclient/tests/unit/auth/test_loading.py @@ -0,0 +1,47 @@ +# 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 uuid + +import six + +from keystoneclient.tests.unit.auth import utils + + +class TestOtherLoading(utils.TestCase): + + def test_loading_getter(self): + + called_opts = [] + + vals = {'a-int': 44, + 'a-bool': False, + 'a-float': 99.99, + 'a-str': 'value'} + + val = uuid.uuid4().hex + + def _getter(opt): + called_opts.append(opt.name) + # return str because oslo.config should convert them back + return str(vals[opt.name]) + + p = utils.MockPlugin.load_from_options_getter(_getter, other=val) + + self.assertEqual(set(vals), set(called_opts)) + + for k, v in six.iteritems(vals): + # replace - to _ because it's the dest used to create kwargs + self.assertEqual(v, p[k.replace('-', '_')]) + + # check that additional kwargs get passed through + self.assertEqual(val, p['other'])