From 0a5248e13291c41243b88f2e19f07cad5160e303 Mon Sep 17 00:00:00 2001 From: Claudiu Popa Date: Mon, 11 May 2015 16:00:19 +0300 Subject: [PATCH] Don't hard fail when a plugin can't be imported This patch tries to fix a common problem with a lot of configuration files out there, which contains invalid plugin paths. Instead of failing with a traceback, which might be confusing to users, we emit an error which should be clearer and easily debuggable by a non-Python user. Change-Id: I1390136b37055207787151ebd80ac83dfaefea4c --- cloudbaseinit/plugins/common/factory.py | 11 ++++++++++- cloudbaseinit/tests/plugins/test_factory.py | 11 +++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/cloudbaseinit/plugins/common/factory.py b/cloudbaseinit/plugins/common/factory.py index 50ba7918..b74f4139 100644 --- a/cloudbaseinit/plugins/common/factory.py +++ b/cloudbaseinit/plugins/common/factory.py @@ -14,6 +14,7 @@ from oslo.config import cfg +from cloudbaseinit.openstack.common import log as logging from cloudbaseinit.utils import classloader opts = [ @@ -44,11 +45,19 @@ opts = [ CONF = cfg.CONF CONF.register_opts(opts) +LOG = logging.getLogger(__name__) def load_plugins(): plugins = [] cl = classloader.ClassLoader() for class_path in CONF.plugins: - plugins.append(cl.load_class(class_path)()) + try: + plugin_cls = cl.load_class(class_path) + except ImportError: + LOG.error("Could not import plugin module %r", class_path) + continue + + plugin = plugin_cls() + plugins.append(plugin) return plugins diff --git a/cloudbaseinit/tests/plugins/test_factory.py b/cloudbaseinit/tests/plugins/test_factory.py index eec6c49d..ff05240e 100644 --- a/cloudbaseinit/tests/plugins/test_factory.py +++ b/cloudbaseinit/tests/plugins/test_factory.py @@ -21,6 +21,7 @@ except ImportError: from oslo.config import cfg from cloudbaseinit.plugins.common import factory +from cloudbaseinit.tests import testutils CONF = cfg.CONF @@ -35,3 +36,13 @@ class PluginFactoryTests(unittest.TestCase): response = factory.load_plugins() self.assertEqual(expected, mock_load_class.call_args_list) self.assertTrue(response is not None) + + @testutils.ConfPatcher('plugins', ['missing.plugin']) + def test_load_plugins_plugin_failed(self): + with testutils.LogSnatcher('cloudbaseinit.plugins.' + 'common.factory') as snatcher: + plugins = factory.load_plugins() + + self.assertEqual([], plugins) + self.assertEqual(["Could not import plugin module 'missing.plugin'"], + snatcher.output)