diff --git a/ceilometer/agent/base.py b/ceilometer/agent/base.py index d3e70205..de3511c5 100644 --- a/ceilometer/agent/base.py +++ b/ceilometer/agent/base.py @@ -227,11 +227,17 @@ class AgentManager(service_base.BaseService): # be passed extensions = (self._extensions('poll', namespace).extensions for namespace in namespaces) + # get the extensions from pollster builder + extensions_fb = (self._extensions_from_builder('poll', namespace) + for namespace in namespaces) if pollster_list: extensions = (moves.filter(_match, exts) for exts in extensions) + extensions_fb = (moves.filter(_match, exts) + for exts in extensions_fb) - self.extensions = list(itertools.chain(*list(extensions))) + self.extensions = list(itertools.chain(*list(extensions))) + list( + itertools.chain(*list(extensions_fb))) self.discovery_manager = self._extensions('discover') self.context = context.RequestContext('admin', 'admin', is_admin=True) @@ -249,10 +255,7 @@ class AgentManager(service_base.BaseService): publisher_id="ceilometer.api") @staticmethod - def _extensions(category, agent_ns=None): - namespace = ('ceilometer.%s.%s' % (category, agent_ns) if agent_ns - else 'ceilometer.%s' % category) - + def _get_ext_mgr(namespace): def _catch_extension_load_error(mgr, ep, exc): # Extension raising ExtensionLoadError can be ignored, # and ignore anything we can't import as a safety measure. @@ -260,10 +263,9 @@ class AgentManager(service_base.BaseService): 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}, - ) + LOG.error(_("Failed to import extension for %(name)s: " + "%(error)s"), + {'name': ep.name, 'error': exc}) return raise exc @@ -273,6 +275,26 @@ class AgentManager(service_base.BaseService): on_load_failure_callback=_catch_extension_load_error, ) + def _extensions(self, category, agent_ns=None): + namespace = ('ceilometer.%s.%s' % (category, agent_ns) if agent_ns + else 'ceilometer.%s' % category) + return self._get_ext_mgr(namespace) + + def _extensions_from_builder(self, category, agent_ns=None): + ns = ('ceilometer.builder.%s.%s' % (category, agent_ns) if agent_ns + else 'ceilometer.builder.%s' % category) + mgr = self._get_ext_mgr(ns) + + def _build(ext): + return ext.plugin.get_pollsters_extensions() + + # NOTE: this seems a stevedore bug. if no extensions are found, + # map will raise runtimeError which is not documented. + if mgr.names(): + return list(itertools.chain(*mgr.map(_build))) + else: + return [] + def join_partitioning_groups(self): self.groups = set([self.construct_group_id(d.obj.group_id) for d in self.discovery_manager]) diff --git a/ceilometer/tests/unit/agent/test_manager.py b/ceilometer/tests/unit/agent/test_manager.py index 3f61f13d..3ccd191f 100644 --- a/ceilometer/tests/unit/agent/test_manager.py +++ b/ceilometer/tests/unit/agent/test_manager.py @@ -39,6 +39,12 @@ class PollingException(Exception): pass +class TestPollsterBuilder(agentbase.TestPollster): + @classmethod + def build_pollsters(cls): + return [('builder1', cls()), ('builder2', cls())] + + @mock.patch('ceilometer.compute.pollsters.' 'BaseComputePollster.setup_environment', mock.Mock(return_value=None)) @@ -126,6 +132,36 @@ class TestManager(base.BaseTestCase): pollster_list=['disk.*']) manager.cfg.CONF.reset() + def test_builder(self): + @staticmethod + def fake_get_ext_mgr(namespace): + if 'builder' in namespace: + return extension.ExtensionManager.make_test_instance( + [ + extension.Extension('builder', + None, + TestPollsterBuilder, + None), + ] + ) + else: + return extension.ExtensionManager.make_test_instance( + [ + extension.Extension('test', + None, + None, + agentbase.TestPollster()), + ] + ) + + with mock.patch.object(manager.AgentManager, '_get_ext_mgr', + new=fake_get_ext_mgr): + mgr = manager.AgentManager(namespaces=['central']) + self.assertEqual(3, len(mgr.extensions)) + for ext in mgr.extensions: + self.assertIn(ext.name, ['builder1', 'builder2', 'test']) + self.assertIsInstance(ext.obj, agentbase.TestPollster) + class TestPollsterKeystone(agentbase.TestPollster): @plugin_base.check_keystone