diff --git a/ceilometer/agent/base.py b/ceilometer/agent/base.py index bbfbe6bb8..ac9a843ed 100644 --- a/ceilometer/agent/base.py +++ b/ceilometer/agent/base.py @@ -65,6 +65,7 @@ class Resources(object): self._resources = [] self._discovery = [] self.blacklist = [] + self.last_dup = [] def setup(self, pipeline): self._resources = pipeline.resources @@ -139,10 +140,32 @@ class PollingTask(object): candidate_res = (source_resources or pollster_resources) - # Exclude the failed resource from polling + # Remove duplicated resources and black resources. Using + # set() requires well defined __hash__ for each resource. + # Since __eq__ is defined, 'not in' is safe here. + seen = [] + duplicated = [] + polling_resources = [] black_res = self.resources[key].blacklist - polling_resources = [ - x for x in candidate_res if x not in black_res] + for x in candidate_res: + if x not in seen: + seen.append(x) + if x not in black_res: + polling_resources.append(x) + else: + duplicated.append(x) + + # Warn duplicated resources for the 1st time + if self.resources[key].last_dup != duplicated: + self.resources[key].last_dup = duplicated + LOG.warning(_( + 'Found following duplicated resoures for ' + '%(name)s in context of %(source)s:%(list)s. ' + 'Check pipeline configuration.') + % ({'name': pollster.name, + 'source': source_name, + 'list': duplicated + })) # If no resources, skip for this pollster if not polling_resources: diff --git a/ceilometer/tests/agent/agentbase.py b/ceilometer/tests/agent/agentbase.py index d4b432896..711013392 100644 --- a/ceilometer/tests/agent/agentbase.py +++ b/ceilometer/tests/agent/agentbase.py @@ -446,6 +446,10 @@ class BaseAgentManagerTestCase(base.BaseTestCase): self.assertEqual(set(self.Discovery.resources), set(self.Pollster.resources)) + # Make sure no duplicated resource from discovery + for x in self.Pollster.resources: + self.assertEqual(1, self.Pollster.resources.count(x)) + def test_per_pollster_discovery(self): self._do_test_per_pollster_discovery(['discovered_1', 'discovered_2'], []) @@ -455,6 +459,14 @@ class BaseAgentManagerTestCase(base.BaseTestCase): self._do_test_per_pollster_discovery(['discovered_1', 'discovered_2'], ['static_1', 'static_2']) + def test_per_pollster_discovery_duplicated(self): + self._do_test_per_pollster_discovery(['dup', 'discovered_1', 'dup'], + []) + + def test_per_pollster_discovery_overridden_by_duplicated_static(self): + self._do_test_per_pollster_discovery(['discovered_1', 'discovered_2'], + ['static_1', 'dup', 'dup']) + def test_per_pollster_discovery_caching(self): # ensure single discovery associated with multiple pollsters # only called once per polling cycle @@ -492,6 +504,10 @@ class BaseAgentManagerTestCase(base.BaseTestCase): self.assertEqual(set(static_resources + discovery), set(self.Pollster.resources)) + # Make sure no duplicated resource from discovery + for x in self.Pollster.resources: + self.assertEqual(1, self.Pollster.resources.count(x)) + def test_per_pipeline_discovery_discovered_only(self): self._do_test_per_pipeline_discovery(['discovered_1', 'discovered_2'], []) @@ -504,6 +520,10 @@ class BaseAgentManagerTestCase(base.BaseTestCase): self._do_test_per_pipeline_discovery(['discovered_1', 'discovered_2'], ['static_1', 'static_2']) + def test_per_pipeline_discovery_discovered_duplicated_static(self): + self._do_test_per_pipeline_discovery(['discovered_1', 'pud'], + ['dup', 'static_1', 'dup']) + def test_multiple_pipelines_different_static_resources(self): # assert that the individual lists of static and discovered resources # for each pipeline with a common interval are passed to individual