From 8980bf7da55dd084ad84c84534fe937f0d43b9c0 Mon Sep 17 00:00:00 2001 From: Davanum Srinivas Date: Fri, 14 Jul 2017 14:51:20 -0400 Subject: [PATCH] Use Stevedore for better extensions Since all Oslo library drivers are discoverable via stevedore, we should use stevedore in Castellan as well. This will make it easier for folks to write their own custom drivers. Stevedore uses setuptools entry points for implementing the common patterns for dynamically loading extensions. We add [key_manager]/backend as the new option to set the custom driver. For a while, we should support the older values that used to be specified using [key_manager]/apiclass. Change-Id: I2610459839806a5591da1efa314dfa52bcfb7cda --- castellan/key_manager/__init__.py | 29 +++++++++++++++---- castellan/options.py | 11 ++++--- .../key_manager/test_barbican_key_manager.py | 3 +- .../unit/key_manager/test_key_manager.py | 21 ++++++++++++++ castellan/tests/unit/test_options.py | 14 +++++++-- requirements.txt | 1 + setup.cfg | 3 ++ 7 files changed, 67 insertions(+), 15 deletions(-) diff --git a/castellan/key_manager/__init__.py b/castellan/key_manager/__init__.py index 0a7435a2..362ba3da 100644 --- a/castellan/key_manager/__init__.py +++ b/castellan/key_manager/__init__.py @@ -13,13 +13,21 @@ # License for the specific language governing permissions and limitations # under the License. from oslo_config import cfg +from oslo_log import log as logging from oslo_utils import importutils +from stevedore import driver +from stevedore import exception + +LOG = logging.getLogger(__name__) key_manager_opts = [ - cfg.StrOpt('api_class', - default='castellan.key_manager.barbican_key_manager' - '.BarbicanKeyManager', - help='The full class name of the key manager API class'), + cfg.StrOpt('backend', + default='barbican', + deprecated_name='api_class', + deprecated_group='key_manager', + help='Specify the key manager implementation. Default is ' + '"barbican".Will support the values earlier set using ' + '[key_manager]/api_class for some time.'), ] @@ -27,5 +35,14 @@ def API(configuration=None): conf = configuration or cfg.CONF conf.register_opts(key_manager_opts, group='key_manager') - cls = importutils.import_class(conf.key_manager.api_class) - return cls(configuration=conf) + try: + mgr = driver.DriverManager("castellan.drivers", + conf.key_manager.backend, + invoke_on_load=True, + invoke_args=[conf]) + return mgr.driver + except exception.NoMatches: + LOG.warning("Deprecation Warning : %s is not a stevedore based driver," + " trying to load it as a class", conf.key_manager.backend) + cls = importutils.import_class(conf.key_manager.backend) + return cls(configuration=conf) diff --git a/castellan/options.py b/castellan/options.py index ee4165f8..6f443446 100644 --- a/castellan/options.py +++ b/castellan/options.py @@ -30,9 +30,10 @@ _DEFAULT_LOGGING_CONTEXT_FORMAT = ('%(asctime)s.%(msecs)03d %(process)d ' '%(message)s') -def set_defaults(conf, api_class=None, barbican_endpoint=None, +def set_defaults(conf, backend=None, barbican_endpoint=None, barbican_api_version=None, auth_endpoint=None, - retry_delay=None, number_of_retries=None, verify_ssl=None): + retry_delay=None, number_of_retries=None, verify_ssl=None, + api_class=None): """Set defaults for configuration values. Overrides the default options values. @@ -49,8 +50,10 @@ def set_defaults(conf, api_class=None, barbican_endpoint=None, if bkm: conf.register_opts(bkm.barbican_opts, group=bkm.BARBICAN_OPT_GROUP) - if api_class is not None: - conf.set_default('api_class', api_class, group='key_manager') + # Use the new backend option if set or fall back to the older api_class + default_backend = backend or api_class + if default_backend is not None: + conf.set_default('backend', default_backend, group='key_manager') if bkm is not None: if barbican_endpoint is not None: diff --git a/castellan/tests/unit/key_manager/test_barbican_key_manager.py b/castellan/tests/unit/key_manager/test_barbican_key_manager.py index 44ca09de..5d5668cf 100644 --- a/castellan/tests/unit/key_manager/test_barbican_key_manager.py +++ b/castellan/tests/unit/key_manager/test_barbican_key_manager.py @@ -20,7 +20,6 @@ import calendar from barbicanclient import exceptions as barbican_exceptions import mock -from oslo_config import cfg from oslo_utils import timeutils from castellan.common import exception @@ -32,7 +31,7 @@ from castellan.tests.unit.key_manager import test_key_manager class BarbicanKeyManagerTestCase(test_key_manager.KeyManagerTestCase): def _create_key_manager(self): - return barbican_key_manager.BarbicanKeyManager(cfg.CONF) + return barbican_key_manager.BarbicanKeyManager(self.conf) def setUp(self): super(BarbicanKeyManagerTestCase, self).setUp() diff --git a/castellan/tests/unit/key_manager/test_key_manager.py b/castellan/tests/unit/key_manager/test_key_manager.py index 5b29b1da..926e91a6 100644 --- a/castellan/tests/unit/key_manager/test_key_manager.py +++ b/castellan/tests/unit/key_manager/test_key_manager.py @@ -17,8 +17,15 @@ Test cases for the key manager. """ +from oslo_config import cfg +from oslo_config import fixture + +from castellan import key_manager +from castellan.key_manager import barbican_key_manager from castellan.tests import base +CONF = cfg.CONF + class KeyManagerTestCase(base.TestCase): @@ -28,4 +35,18 @@ class KeyManagerTestCase(base.TestCase): def setUp(self): super(KeyManagerTestCase, self).setUp() + self.conf = self.useFixture(fixture.Config()).conf + self.key_mgr = self._create_key_manager() + + +class DefaultKeyManagerImplTestCase(KeyManagerTestCase): + + def _create_key_manager(self): + return key_manager.API(self.conf) + + def test_default_key_manager(self): + self.assertEqual("barbican", self.conf.key_manager.backend) + self.assertIsNotNone(self.key_mgr) + self.assertIsInstance(self.key_mgr, + barbican_key_manager.BarbicanKeyManager) diff --git a/castellan/tests/unit/test_options.py b/castellan/tests/unit/test_options.py index 280e4e6f..e1ac3f3b 100644 --- a/castellan/tests/unit/test_options.py +++ b/castellan/tests/unit/test_options.py @@ -15,9 +15,11 @@ from oslo_config import cfg +from castellan import key_manager from castellan.key_manager import barbican_key_manager as bkm from castellan import options from castellan.tests import base +from castellan.tests.unit.key_manager import mock_key_manager class TestOptions(base.TestCase): @@ -25,9 +27,15 @@ class TestOptions(base.TestCase): def test_set_defaults(self): conf = cfg.ConfigOpts() - api_class = 'test.api.class' - options.set_defaults(conf, api_class=api_class) - self.assertEqual(api_class, conf.key_manager.api_class) + self.assertTrue(isinstance(key_manager.API(conf), + bkm.BarbicanKeyManager)) + + cls = mock_key_manager.MockKeyManager + backend = '%s.%s' % (cls.__module__, cls.__name__) + options.set_defaults(conf, backend=backend) + self.assertEqual(backend, conf.key_manager.backend) + self.assertIsInstance(key_manager.API(conf), + mock_key_manager.MockKeyManager) barbican_endpoint = 'http://test-server.org:9311/' options.set_defaults(conf, barbican_endpoint=barbican_endpoint) diff --git a/requirements.txt b/requirements.txt index 4a944730..47b034c2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,4 +11,5 @@ oslo.context>=2.14.0 # Apache-2.0 oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0 oslo.log>=3.22.0 # Apache-2.0 oslo.utils>=3.20.0 # Apache-2.0 +stevedore>=1.20.0 # Apache-2.0 keystoneauth1>=3.1.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg index eba5c55b..e71a9df4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -27,6 +27,9 @@ oslo.config.opts = castellan.tests.functional.config = castellan.tests.functional.config:list_opts castellan.config = castellan.options:list_opts +castellan.drivers = + barbican = castellan.key_manager.barbican_key_manager:BarbicanKeyManager + [build_sphinx] source-dir = doc/source build-dir = doc/build