Merge "Expose root cause plugin exceptions"

This commit is contained in:
Jenkins
2015-05-09 14:01:07 +00:00
committed by Gerrit Code Review
6 changed files with 204 additions and 53 deletions

View File

@@ -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

View File

@@ -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()

View File

@@ -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()

View 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]

View File

@@ -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)

View 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)