From bc802a91c85bc95b9e1bd0a96ad03b85bf4f2c88 Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Mon, 23 Feb 2015 10:49:39 -0500 Subject: [PATCH] Protect agent startup from import errors in plugins Watch for import errors and log them but do not let them propagate, so that the agent will still run even if a library used by a requested plugin is missing. Change-Id: I0fbb708b0c502ac07b5d5f7c83ac3ed46b0fc46d --- ceilometer/agent/base.py | 9 ++++++++- ceilometer/tests/agent/test_manager.py | 11 +++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ceilometer/agent/base.py b/ceilometer/agent/base.py index ac9a843ed..e00d70fdb 100644 --- a/ceilometer/agent/base.py +++ b/ceilometer/agent/base.py @@ -238,10 +238,17 @@ class AgentManager(os_service.Service): else 'ceilometer.%s' % category) def _catch_extension_load_error(mgr, ep, exc): - # Extension raising ExtensionLoadError can be ignored + # Extension raising ExtensionLoadError can be ignored, + # and ignore anything we can't import as a safety measure. if isinstance(exc, plugin_base.ExtensionLoadError): LOG.error(_("Skip loading extension for %s") % ep.name) return + if isinstance(exc, ImportError): + LOG.error( + _("Failed to import extension for %(name)s: %(error)s"), + {'name': ep.name, 'error': exc}, + ) + return raise exc return extension.ExtensionManager( diff --git a/ceilometer/tests/agent/test_manager.py b/ceilometer/tests/agent/test_manager.py index 373aa845a..9a0c9efb1 100644 --- a/ceilometer/tests/agent/test_manager.py +++ b/ceilometer/tests/agent/test_manager.py @@ -80,6 +80,17 @@ class TestManager(base.BaseTestCase): LOG.error.assert_has_calls(calls=calls, any_order=True) + # Skip loading pollster upon ImportError + @mock.patch('ceilometer.ipmi.pollsters.node._Base.__init__', + mock.Mock(side_effect=ImportError)) + @mock.patch('ceilometer.ipmi.pollsters.sensor.SensorPollster.__init__', + mock.Mock(return_value=None)) + def test_import_error_in_plugin(self): + mgr = manager.AgentManager(namespaces=['ipmi'], + pollster_list=['hardware.ipmi.node.*']) + # 0 pollsters + self.assertEqual(0, len(mgr.extensions)) + # Exceptions other than ExtensionLoadError are propagated @mock.patch('ceilometer.ipmi.pollsters.node._Base.__init__', mock.Mock(side_effect=PollingException))