Merge "Expose root cause plugin exceptions"
This commit is contained in:
@@ -18,6 +18,8 @@ from barbican.common import utils
|
||||
from barbican import i18n as u
|
||||
from barbican.plugin.crypto import crypto
|
||||
from barbican.plugin.interface import secret_store
|
||||
from barbican.plugin.util import utils as plugin_utils
|
||||
|
||||
|
||||
_PLUGIN_MANAGER = None
|
||||
|
||||
@@ -43,8 +45,7 @@ CONF.register_opts(crypto_opts, group=crypto_opt_group)
|
||||
|
||||
|
||||
class _CryptoPluginManager(named.NamedExtensionManager):
|
||||
def __init__(self, conf=CONF, invoke_on_load=True,
|
||||
invoke_args=(), invoke_kwargs={}):
|
||||
def __init__(self, conf=CONF, invoke_args=(), invoke_kwargs={}):
|
||||
"""Crypto Plugin Manager
|
||||
|
||||
Each time this class is initialized it will load a new instance
|
||||
@@ -55,11 +56,14 @@ class _CryptoPluginManager(named.NamedExtensionManager):
|
||||
super(_CryptoPluginManager, self).__init__(
|
||||
conf.crypto.namespace,
|
||||
conf.crypto.enabled_crypto_plugins,
|
||||
invoke_on_load=invoke_on_load,
|
||||
invoke_on_load=False, # Defer creating plugins to utility below.
|
||||
invoke_args=invoke_args,
|
||||
invoke_kwds=invoke_kwargs
|
||||
)
|
||||
|
||||
plugin_utils.instantiate_plugins(
|
||||
self, invoke_args, invoke_kwargs)
|
||||
|
||||
def get_plugin_store_generate(self, type_needed, algorithm=None,
|
||||
bit_length=None, mode=None):
|
||||
"""Gets a secret store or generate plugin that supports provided type.
|
||||
@@ -68,18 +72,19 @@ class _CryptoPluginManager(named.NamedExtensionManager):
|
||||
type of plugin required
|
||||
:returns: CryptoPluginBase plugin implementation
|
||||
"""
|
||||
active_plugins = plugin_utils.get_active_plugins(self)
|
||||
|
||||
if len(self.extensions) < 1:
|
||||
if len(active_plugins) < 1:
|
||||
raise crypto.CryptoPluginNotFound()
|
||||
|
||||
for ext in self.extensions:
|
||||
if ext.obj.supports(type_needed, algorithm, bit_length, mode):
|
||||
plugin = ext.obj
|
||||
for generating_plugin in active_plugins:
|
||||
if generating_plugin.supports(
|
||||
type_needed, algorithm, bit_length, mode):
|
||||
break
|
||||
else:
|
||||
raise secret_store.SecretStorePluginNotFound()
|
||||
|
||||
return plugin
|
||||
return generating_plugin
|
||||
|
||||
def get_plugin_retrieve(self, plugin_name_for_store):
|
||||
"""Gets a secret retrieve plugin that supports the provided type.
|
||||
@@ -88,12 +93,12 @@ class _CryptoPluginManager(named.NamedExtensionManager):
|
||||
type of plugin required
|
||||
:returns: CryptoPluginBase plugin implementation
|
||||
"""
|
||||
active_plugins = plugin_utils.get_active_plugins(self)
|
||||
|
||||
if len(self.extensions) < 1:
|
||||
if len(active_plugins) < 1:
|
||||
raise crypto.CryptoPluginNotFound()
|
||||
|
||||
for ext in self.extensions:
|
||||
decrypting_plugin = ext.obj
|
||||
for decrypting_plugin in active_plugins:
|
||||
plugin_name = utils.generate_fullname_for(decrypting_plugin)
|
||||
if plugin_name == plugin_name_for_store:
|
||||
break
|
||||
|
||||
@@ -32,6 +32,7 @@ import barbican.common.utils as utils
|
||||
from barbican import i18n as u
|
||||
from barbican.model import models
|
||||
from barbican.model import repositories as repos
|
||||
from barbican.plugin.util import utils as plugin_utils
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
@@ -501,17 +502,19 @@ class BarbicanMetaDTO(object):
|
||||
|
||||
|
||||
class CertificatePluginManager(named.NamedExtensionManager):
|
||||
def __init__(self, conf=CONF, invoke_on_load=True,
|
||||
invoke_args=(), invoke_kwargs={}):
|
||||
def __init__(self, conf=CONF, invoke_args=(), invoke_kwargs={}):
|
||||
self.ca_repo = repos.get_ca_repository()
|
||||
super(CertificatePluginManager, self).__init__(
|
||||
conf.certificate.namespace,
|
||||
conf.certificate.enabled_certificate_plugins,
|
||||
invoke_on_load=invoke_on_load,
|
||||
invoke_on_load=False, # Defer creating plugins to utility below.
|
||||
invoke_args=invoke_args,
|
||||
invoke_kwds=invoke_kwargs
|
||||
)
|
||||
|
||||
plugin_utils.instantiate_plugins(
|
||||
self, invoke_args, invoke_kwargs)
|
||||
|
||||
def get_plugin(self, certificate_spec):
|
||||
"""Gets a supporting certificate plugin.
|
||||
|
||||
@@ -523,13 +526,13 @@ class CertificatePluginManager(named.NamedExtensionManager):
|
||||
REQUEST_TYPE,
|
||||
CertificateRequestType.CUSTOM_REQUEST)
|
||||
|
||||
for ext in self.extensions:
|
||||
supported_request_types = ext.obj.supported_request_types()
|
||||
for plugin in plugin_utils.get_active_plugins(self):
|
||||
supported_request_types = plugin.supported_request_types()
|
||||
if request_type not in supported_request_types:
|
||||
continue
|
||||
|
||||
if ext.obj.supports(certificate_spec):
|
||||
return ext.obj
|
||||
if plugin.supports(certificate_spec):
|
||||
return plugin
|
||||
|
||||
raise CertificatePluginNotFound()
|
||||
|
||||
@@ -539,9 +542,9 @@ class CertificatePluginManager(named.NamedExtensionManager):
|
||||
:param plugin_name: Name of the plugin to invoke
|
||||
:returns: CertificatePluginBase plugin implementation
|
||||
"""
|
||||
for ext in self.extensions:
|
||||
if utils.generate_fullname_for(ext.obj) == plugin_name:
|
||||
return ext.obj
|
||||
for plugin in plugin_utils.get_active_plugins(self):
|
||||
if utils.generate_fullname_for(plugin) == plugin_name:
|
||||
return plugin
|
||||
raise CertificatePluginNotFound(plugin_name)
|
||||
|
||||
def get_plugin_by_ca_id(self, ca_id):
|
||||
@@ -558,8 +561,8 @@ class CertificatePluginManager(named.NamedExtensionManager):
|
||||
|
||||
def refresh_ca_table(self):
|
||||
"""Refreshes the CertificateAuthority table."""
|
||||
for ext in self.extensions:
|
||||
plugin_name = utils.generate_fullname_for(ext.obj)
|
||||
for plugin in plugin_utils.get_active_plugins(self):
|
||||
plugin_name = utils.generate_fullname_for(plugin)
|
||||
cas, offset, limit, total = self.ca_repo.get_by_create_date(
|
||||
plugin_name=plugin_name,
|
||||
suppress_exception=True)
|
||||
@@ -567,7 +570,7 @@ class CertificatePluginManager(named.NamedExtensionManager):
|
||||
# if no entries are found, then the plugin has not yet been
|
||||
# queried or that plugin's entries have expired.
|
||||
# Most of the time, this will be a no-op for plugins.
|
||||
self.update_ca_info(ext.obj)
|
||||
self.update_ca_info(plugin)
|
||||
|
||||
def update_ca_info(self, cert_plugin):
|
||||
"""Update the CA info for a particular plugin."""
|
||||
@@ -624,24 +627,26 @@ class _CertificateEventPluginManager(named.NamedExtensionManager,
|
||||
new instance of this class use the EVENT_PLUGIN_MANAGER at the module
|
||||
level.
|
||||
"""
|
||||
def __init__(self, conf=CONF, invoke_on_load=True,
|
||||
invoke_args=(), invoke_kwargs={}):
|
||||
def __init__(self, conf=CONF, invoke_args=(), invoke_kwargs={}):
|
||||
super(_CertificateEventPluginManager, self).__init__(
|
||||
conf.certificate_event.namespace,
|
||||
conf.certificate_event.enabled_certificate_event_plugins,
|
||||
invoke_on_load=invoke_on_load,
|
||||
invoke_on_load=False, # Defer creating plugins to utility below.
|
||||
invoke_args=invoke_args,
|
||||
invoke_kwds=invoke_kwargs
|
||||
)
|
||||
|
||||
plugin_utils.instantiate_plugins(
|
||||
self, invoke_args, invoke_kwargs)
|
||||
|
||||
def get_plugin_by_name(self, plugin_name):
|
||||
"""Gets a supporting certificate event plugin.
|
||||
|
||||
:returns: CertificateEventPluginBase plugin implementation
|
||||
"""
|
||||
for ext in self.extensions:
|
||||
if utils.generate_fullname_for(ext.obj) == plugin_name:
|
||||
return ext.obj
|
||||
for plugin in plugin_utils.get_active_plugins(self):
|
||||
if utils.generate_fullname_for(plugin) == plugin_name:
|
||||
return plugin
|
||||
raise CertificateEventPluginNotFound(plugin_name)
|
||||
|
||||
def notify_certificate_is_ready(
|
||||
@@ -658,11 +663,13 @@ class _CertificateEventPluginManager(named.NamedExtensionManager,
|
||||
|
||||
def _invoke_certificate_plugins(self, method, *args, **kwargs):
|
||||
"""Invoke same function on plugins as calling function."""
|
||||
if len(self.extensions) < 1:
|
||||
active_plugins = plugin_utils.get_active_plugins(self)
|
||||
|
||||
if len(active_plugins) < 1:
|
||||
raise CertificateEventPluginNotFound()
|
||||
|
||||
for ext in self.extensions:
|
||||
getattr(ext.obj, method)(*args, **kwargs)
|
||||
for plugin in active_plugins:
|
||||
getattr(plugin, method)(*args, **kwargs)
|
||||
|
||||
|
||||
EVENT_PLUGIN_MANAGER = _CertificateEventPluginManager()
|
||||
|
||||
@@ -22,6 +22,8 @@ from stevedore import named
|
||||
from barbican.common import exception
|
||||
from barbican.common import utils
|
||||
from barbican import i18n as u
|
||||
from barbican.plugin.util import utils as plugin_utils
|
||||
|
||||
|
||||
_SECRET_STORE = None
|
||||
|
||||
@@ -480,16 +482,18 @@ def _enforce_extensions_configured(plugin_related_function):
|
||||
|
||||
|
||||
class SecretStorePluginManager(named.NamedExtensionManager):
|
||||
def __init__(self, conf=CONF, invoke_on_load=True,
|
||||
invoke_args=(), invoke_kwargs={}):
|
||||
def __init__(self, conf=CONF, invoke_args=(), invoke_kwargs={}):
|
||||
super(SecretStorePluginManager, self).__init__(
|
||||
conf.secretstore.namespace,
|
||||
conf.secretstore.enabled_secretstore_plugins,
|
||||
invoke_on_load=invoke_on_load,
|
||||
invoke_on_load=False, # Defer creating plugins to utility below.
|
||||
invoke_args=invoke_args,
|
||||
invoke_kwds=invoke_kwargs
|
||||
)
|
||||
|
||||
plugin_utils.instantiate_plugins(
|
||||
self, invoke_args, invoke_kwargs)
|
||||
|
||||
@_enforce_extensions_configured
|
||||
def get_plugin_store(self, key_spec, plugin_name=None,
|
||||
transport_key_needed=False):
|
||||
@@ -501,23 +505,24 @@ class SecretStorePluginManager(named.NamedExtensionManager):
|
||||
key is required.
|
||||
:returns: SecretStoreBase plugin implementation
|
||||
"""
|
||||
active_plugins = plugin_utils.get_active_plugins(self)
|
||||
|
||||
if plugin_name is not None:
|
||||
for ext in self.extensions:
|
||||
if utils.generate_fullname_for(ext.obj) == plugin_name:
|
||||
return ext.obj
|
||||
for plugin in active_plugins:
|
||||
if utils.generate_fullname_for(plugin) == plugin_name:
|
||||
return plugin
|
||||
raise SecretStorePluginNotFound(plugin_name)
|
||||
|
||||
if not transport_key_needed:
|
||||
for ext in self.extensions:
|
||||
if ext.obj.store_secret_supports(key_spec):
|
||||
return ext.obj
|
||||
for plugin in active_plugins:
|
||||
if plugin.store_secret_supports(key_spec):
|
||||
return plugin
|
||||
|
||||
else:
|
||||
for ext in self.extensions:
|
||||
if (ext.obj.get_transport_key() is not None and
|
||||
ext.obj.store_secret_supports(key_spec)):
|
||||
return ext.obj
|
||||
for plugin in active_plugins:
|
||||
if (plugin.get_transport_key() is not None and
|
||||
plugin.store_secret_supports(key_spec)):
|
||||
return plugin
|
||||
|
||||
raise SecretStoreSupportedPluginNotFound()
|
||||
|
||||
@@ -537,9 +542,9 @@ class SecretStorePluginManager(named.NamedExtensionManager):
|
||||
configured on the database side.
|
||||
"""
|
||||
|
||||
for ext in self.extensions:
|
||||
if utils.generate_fullname_for(ext.obj) == plugin_name:
|
||||
return ext.obj
|
||||
for plugin in plugin_utils.get_active_plugins(self):
|
||||
if utils.generate_fullname_for(plugin) == plugin_name:
|
||||
return plugin
|
||||
raise StorePluginNotAvailableOrMisconfigured(plugin_name)
|
||||
|
||||
@_enforce_extensions_configured
|
||||
@@ -551,9 +556,9 @@ class SecretStorePluginManager(named.NamedExtensionManager):
|
||||
:returns: SecretStoreBase plugin implementation
|
||||
"""
|
||||
|
||||
for ext in self.extensions:
|
||||
if ext.obj.generate_supports(key_spec):
|
||||
return ext.obj
|
||||
for plugin in plugin_utils.get_active_plugins(self):
|
||||
if plugin.generate_supports(key_spec):
|
||||
return plugin
|
||||
raise SecretStoreSupportedPluginNotFound()
|
||||
|
||||
|
||||
|
||||
54
barbican/plugin/util/utils.py
Normal file
54
barbican/plugin/util/utils.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# Copyright (c) 2015 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Utilities to support plugins and plugin managers.
|
||||
"""
|
||||
from barbican.common import utils
|
||||
from barbican import i18n as u
|
||||
|
||||
LOG = utils.getLogger(__name__)
|
||||
|
||||
|
||||
def instantiate_plugins(extension_manager, invoke_args=(), invoke_kwargs={}):
|
||||
"""Attempt to create each plugin managed by a stevedore manager.
|
||||
|
||||
While we could have let the stevedore 'extension_manager' create our
|
||||
plugins by passing 'invoke_on_load=True' to its initializer, its logic
|
||||
handles and suppresses any root cause exceptions emanating from the
|
||||
plugins' initializers. This function allows those exceptions to be exposed.
|
||||
|
||||
:param extension_manager: A :class:`NamedExtensionManager` instance that
|
||||
has already processed the configured plugins, but has not yet created
|
||||
instances of these plugins.
|
||||
:param invoke_args: Arguments to pass to the new plugin instance.
|
||||
:param invoke_kwargs: Keyword arguments to pass to the new plugin instance.
|
||||
"""
|
||||
for ext in extension_manager.extensions:
|
||||
if not ext.obj:
|
||||
try:
|
||||
plugin_instance = ext.plugin(*invoke_args, **invoke_kwargs)
|
||||
except Exception:
|
||||
LOG.logger.disabled = False # Ensure not suppressing logs.
|
||||
LOG.exception(
|
||||
u._LE("Problem seen creating plugin: '%s'"),
|
||||
ext.name
|
||||
)
|
||||
else:
|
||||
ext.obj = plugin_instance
|
||||
|
||||
|
||||
def get_active_plugins(extension_manager):
|
||||
return [ext.obj for ext in extension_manager.extensions if ext.obj]
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import mock
|
||||
|
||||
from barbican.common import utils as common_utils
|
||||
from barbican.plugin.interface import secret_store as str
|
||||
from barbican.tests import utils
|
||||
|
||||
@@ -92,7 +93,7 @@ class WhenTestingSecretStorePluginManager(utils.BaseTestCase):
|
||||
super(WhenTestingSecretStorePluginManager, self).setUp()
|
||||
self.manager = str.SecretStorePluginManager()
|
||||
|
||||
def test_get_store_supported_plugin(self):
|
||||
def test_get_store_supported_plugin_no_plugin_name(self):
|
||||
plugin = TestSecretStore([str.KeyAlgorithm.AES])
|
||||
plugin_mock = mock.MagicMock(obj=plugin)
|
||||
self.manager.extensions = [plugin_mock]
|
||||
@@ -101,6 +102,15 @@ class WhenTestingSecretStorePluginManager(utils.BaseTestCase):
|
||||
self.assertEqual(plugin,
|
||||
self.manager.get_plugin_store(keySpec))
|
||||
|
||||
def test_get_store_supported_plugin_with_plugin_name(self):
|
||||
plugin = TestSecretStore([str.KeyAlgorithm.AES])
|
||||
plugin_mock = mock.MagicMock(obj=plugin)
|
||||
self.manager.extensions = [plugin_mock]
|
||||
|
||||
plugin_found = self.manager.get_plugin_store(
|
||||
None, plugin_name=common_utils.generate_fullname_for(plugin))
|
||||
self.assertEqual(plugin, plugin_found)
|
||||
|
||||
def test_get_generate_supported_plugin(self):
|
||||
plugin = TestSecretStore([str.KeyAlgorithm.AES])
|
||||
plugin_mock = mock.MagicMock(obj=plugin)
|
||||
|
||||
70
barbican/tests/plugin/util/test_utils.py
Normal file
70
barbican/tests/plugin/util/test_utils.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# Copyright (c) 2015 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from barbican.plugin.util import utils as plugin_utils
|
||||
from barbican.tests import utils as test_utils
|
||||
|
||||
|
||||
class ExtensionStub(object):
|
||||
|
||||
def __init__(self):
|
||||
self.name = 'my_name'
|
||||
self.plugin_instance = 'my_instance'
|
||||
self.obj = None
|
||||
self.exc = None
|
||||
self.args = None
|
||||
self.kwargs = None
|
||||
|
||||
def plugin(self, *args, **kwargs):
|
||||
if self.exc:
|
||||
raise self.exc
|
||||
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
return self.plugin_instance
|
||||
|
||||
def set_raise_exception(self, exc):
|
||||
self.exc = exc
|
||||
|
||||
|
||||
class ManagerStub(object):
|
||||
def __init__(self, extensions):
|
||||
self.extensions = extensions
|
||||
|
||||
|
||||
class WhenInvokingInstantiatePlugins(test_utils.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(WhenInvokingInstantiatePlugins, self).setUp()
|
||||
|
||||
self.extension = ExtensionStub()
|
||||
self.manager = ManagerStub([self.extension])
|
||||
|
||||
def test_creates_plugin_instance(self):
|
||||
args = ('foo', 'bar')
|
||||
kwargs = {'foo': 1}
|
||||
|
||||
plugin_utils.instantiate_plugins(
|
||||
self.manager, invoke_args=args, invoke_kwargs=kwargs)
|
||||
|
||||
self.assertEqual('my_instance', self.extension.obj)
|
||||
self.assertEqual(args, self.extension.args)
|
||||
self.assertEqual(kwargs, self.extension.kwargs)
|
||||
|
||||
def test_does_not_create_plugin_instance_due_to_error(self):
|
||||
self.extension.set_raise_exception(ValueError())
|
||||
|
||||
plugin_utils.instantiate_plugins(self.manager)
|
||||
|
||||
self.assertIsNone(self.extension.obj)
|
||||
Reference in New Issue
Block a user