# # Copyright 2012 New Dream Network, LLC (DreamHost) # Copyright 2013 Intel corp. # Copyright 2013 eNovance # Copyright 2014 Red Hat, Inc # # Authors: Yunhong Jiang # Julien Danjou # Eoghan Glynn # # 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. import abc import copy import datetime import mock import six from stevedore import extension from ceilometer.openstack.common.fixture import config from ceilometer.openstack.common.fixture import mockpatch from ceilometer import pipeline from ceilometer import plugin from ceilometer import publisher from ceilometer.publisher import test as test_publisher from ceilometer import sample from ceilometer.tests import base from ceilometer import transformer class TestSample(sample.Sample): def __init__(self, name, type, unit, volume, user_id, project_id, resource_id, timestamp, resource_metadata, source=None): super(TestSample, self).__init__(name, type, unit, volume, user_id, project_id, resource_id, timestamp, resource_metadata, source) def __eq__(self, other): if isinstance(other, self.__class__): return self.__dict__ == other.__dict__ return False def __ne__(self, other): return not self.__eq__(other) default_test_data = TestSample( name='test', type=sample.TYPE_CUMULATIVE, unit='', volume=1, user_id='test', project_id='test', resource_id='test_run_tasks', timestamp=datetime.datetime.utcnow().isoformat(), resource_metadata={'name': 'Pollster'}, ) class TestPollster(plugin.PollsterBase): test_data = default_test_data def get_samples(self, manager, cache, resources=None): resources = resources or [] self.samples.append((manager, resources)) self.resources.extend(resources) c = copy.copy(self.test_data) c.resource_metadata['resources'] = resources return [c] class TestPollsterException(TestPollster): def get_samples(self, manager, cache, resources=None): resources = resources or [] self.samples.append((manager, resources)) self.resources.extend(resources) raise Exception() class TestDiscovery(plugin.DiscoveryBase): def discover(self, param=None): self.params.append(param) return self.resources class TestDiscoveryException(plugin.DiscoveryBase): def discover(self, param=None): self.params.append(param) raise Exception() @six.add_metaclass(abc.ABCMeta) class BaseAgentManagerTestCase(base.BaseTestCase): class Pollster(TestPollster): samples = [] resources = [] test_data = default_test_data class PollsterAnother(TestPollster): samples = [] resources = [] test_data = TestSample( name='testanother', type=default_test_data.type, unit=default_test_data.unit, volume=default_test_data.volume, user_id=default_test_data.user_id, project_id=default_test_data.project_id, resource_id=default_test_data.resource_id, timestamp=default_test_data.timestamp, resource_metadata=default_test_data.resource_metadata) class PollsterException(TestPollsterException): samples = [] resources = [] test_data = TestSample( name='testexception', type=default_test_data.type, unit=default_test_data.unit, volume=default_test_data.volume, user_id=default_test_data.user_id, project_id=default_test_data.project_id, resource_id=default_test_data.resource_id, timestamp=default_test_data.timestamp, resource_metadata=default_test_data.resource_metadata) class PollsterExceptionAnother(TestPollsterException): samples = [] resources = [] test_data = TestSample( name='testexceptionanother', type=default_test_data.type, unit=default_test_data.unit, volume=default_test_data.volume, user_id=default_test_data.user_id, project_id=default_test_data.project_id, resource_id=default_test_data.resource_id, timestamp=default_test_data.timestamp, resource_metadata=default_test_data.resource_metadata) class Discovery(TestDiscovery): params = [] resources = [] class DiscoveryAnother(TestDiscovery): params = [] resources = [] class DiscoveryException(TestDiscoveryException): params = [] def setup_pipeline(self): self.transformer_manager = transformer.TransformerExtensionManager( 'ceilometer.transformer', ) self.mgr.pipeline_manager = pipeline.PipelineManager( self.pipeline_cfg, self.transformer_manager) def get_extention_list(self): return [extension.Extension('test', None, None, self.Pollster(), ), extension.Extension('testanother', None, None, self.PollsterAnother(), ), extension.Extension('testexception', None, None, self.PollsterException(), ), extension.Extension('testexceptionanother', None, None, self.PollsterExceptionAnother(), )] def create_pollster_manager(self): return extension.ExtensionManager.make_test_instance( self.get_extention_list(), ) def create_discovery_manager(self): return extension.ExtensionManager.make_test_instance( [ extension.Extension( 'testdiscovery', None, None, self.Discovery(), ), extension.Extension( 'testdiscoveryanother', None, None, self.DiscoveryAnother(), ), extension.Extension( 'testdiscoveryexception', None, None, self.DiscoveryException(), ), ], ) @abc.abstractmethod def create_manager(self): """Return subclass specific manager.""" @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) def setUp(self): super(BaseAgentManagerTestCase, self).setUp() self.mgr = self.create_manager() self.mgr.pollster_manager = self.create_pollster_manager() self.pipeline_cfg = [{ 'name': "test_pipeline", 'interval': 60, 'counters': ['test'], 'resources': ['test://'] if self.source_resources else [], 'transformers': [], 'publishers': ["test"], }, ] self.setup_pipeline() self.CONF = self.useFixture(config.Config()).conf self.CONF.set_override( 'pipeline_cfg_file', self.path_get('etc/ceilometer/pipeline.yaml') ) self.useFixture(mockpatch.PatchObject( publisher, 'get_publisher', side_effect=self.get_publisher)) def get_publisher(self, url, namespace=''): fake_drivers = {'test://': test_publisher.TestPublisher, 'new://': test_publisher.TestPublisher, 'rpc://': test_publisher.TestPublisher} return fake_drivers[url](url) def tearDown(self): self.Pollster.samples = [] self.PollsterAnother.samples = [] self.PollsterException.samples = [] self.PollsterExceptionAnother.samples = [] self.Pollster.resources = [] self.PollsterAnother.resources = [] self.PollsterException.resources = [] self.PollsterExceptionAnother.resources = [] self.Discovery.params = [] self.DiscoveryAnother.params = [] self.DiscoveryException.params = [] self.Discovery.resources = [] self.DiscoveryAnother.resources = [] super(BaseAgentManagerTestCase, self).tearDown() def test_setup_polling_tasks(self): polling_tasks = self.mgr.setup_polling_tasks() self.assertEqual(1, len(polling_tasks)) self.assertTrue(60 in polling_tasks.keys()) per_task_resources = polling_tasks[60].resources self.assertEqual(1, len(per_task_resources)) self.assertEqual(set(self.pipeline_cfg[0]['resources']), set(per_task_resources['test'].resources)) self.mgr.interval_task(polling_tasks.values()[0]) pub = self.mgr.pipeline_manager.pipelines[0].publishers[0] del pub.samples[0].resource_metadata['resources'] self.assertEqual(self.Pollster.test_data, pub.samples[0]) def test_setup_polling_tasks_multiple_interval(self): self.pipeline_cfg.append({ 'name': "test_pipeline", 'interval': 10, 'counters': ['test'], 'resources': ['test://'] if self.source_resources else [], 'transformers': [], 'publishers': ["test"], }) self.setup_pipeline() polling_tasks = self.mgr.setup_polling_tasks() self.assertEqual(2, len(polling_tasks)) self.assertTrue(60 in polling_tasks.keys()) self.assertTrue(10 in polling_tasks.keys()) def test_setup_polling_tasks_mismatch_counter(self): self.pipeline_cfg.append( { 'name': "test_pipeline_1", 'interval': 10, 'counters': ['test_invalid'], 'resources': ['invalid://'], 'transformers': [], 'publishers': ["test"], }) polling_tasks = self.mgr.setup_polling_tasks() self.assertEqual(1, len(polling_tasks)) self.assertTrue(60 in polling_tasks.keys()) def test_setup_polling_task_same_interval(self): self.pipeline_cfg.append({ 'name': "test_pipeline", 'interval': 60, 'counters': ['testanother'], 'resources': ['testanother://'] if self.source_resources else [], 'transformers': [], 'publishers': ["test"], }) self.setup_pipeline() polling_tasks = self.mgr.setup_polling_tasks() self.assertEqual(1, len(polling_tasks)) pollsters = polling_tasks.get(60).pollsters self.assertEqual(2, len(pollsters)) per_task_resources = polling_tasks[60].resources self.assertEqual(2, len(per_task_resources)) self.assertEqual(set(self.pipeline_cfg[0]['resources']), set(per_task_resources['test'].resources)) self.assertEqual(set(self.pipeline_cfg[1]['resources']), set(per_task_resources['testanother'].resources)) def test_interval_exception_isolation(self): self.pipeline_cfg = [ { 'name': "test_pipeline_1", 'interval': 10, 'counters': ['testexceptionanother'], 'resources': ['test://'] if self.source_resources else [], 'transformers': [], 'publishers': ["test"], }, { 'name': "test_pipeline_2", 'interval': 10, 'counters': ['testexception'], 'resources': ['test://'] if self.source_resources else [], 'transformers': [], 'publishers': ["test"], }, ] self.mgr.pipeline_manager = pipeline.PipelineManager( self.pipeline_cfg, self.transformer_manager) polling_tasks = self.mgr.setup_polling_tasks() self.assertEqual(1, len(polling_tasks.keys())) polling_tasks.get(10) self.mgr.interval_task(polling_tasks.get(10)) pub = self.mgr.pipeline_manager.pipelines[0].publishers[0] self.assertEqual(0, len(pub.samples)) def test_agent_manager_start(self): mgr = self.create_manager() mgr.pollster_manager = self.mgr.pollster_manager mgr.create_polling_task = mock.MagicMock() mgr.tg = mock.MagicMock() mgr.start() self.assertTrue(mgr.tg.add_timer.called) def test_manager_exception_persistency(self): self.pipeline_cfg.append({ 'name': "test_pipeline", 'interval': 60, 'counters': ['testanother'], 'transformers': [], 'publishers': ["test"], }) self.setup_pipeline() def _verify_discovery_params(self, expected): self.assertEqual(expected, self.Discovery.params) self.assertEqual(expected, self.DiscoveryAnother.params) self.assertEqual(expected, self.DiscoveryException.params) def _do_test_per_agent_discovery(self, discovered_resources, static_resources): self.mgr.discovery_manager = self.create_discovery_manager() if discovered_resources: self.mgr.default_discovery = [d.name for d in self.mgr.discovery_manager] self.Discovery.resources = discovered_resources self.DiscoveryAnother.resources = [d[::-1] for d in discovered_resources] self.pipeline_cfg[0]['resources'] = static_resources self.setup_pipeline() polling_tasks = self.mgr.setup_polling_tasks() self.mgr.interval_task(polling_tasks.get(60)) self._verify_discovery_params([None] if discovered_resources else []) discovery = self.Discovery.resources + self.DiscoveryAnother.resources # compare resource lists modulo ordering self.assertEqual(set(static_resources or discovery), set(self.Pollster.resources)) def test_per_agent_discovery_discovered_only(self): self._do_test_per_agent_discovery(['discovered_1', 'discovered_2'], []) def test_per_agent_discovery_static_only(self): self._do_test_per_agent_discovery([], ['static_1', 'static_2']) def test_per_agent_discovery_discovered_overridden_by_static(self): self._do_test_per_agent_discovery(['discovered_1', 'discovered_2'], ['static_1', 'static_2']) def test_per_agent_discovery_overridden_by_per_pipeline_discovery(self): discovered_resources = ['discovered_1', 'discovered_2'] self.mgr.discovery_manager = self.create_discovery_manager() self.Discovery.resources = discovered_resources self.DiscoveryAnother.resources = [d[::-1] for d in discovered_resources] self.pipeline_cfg[0]['discovery'] = ['testdiscoveryanother', 'testdiscoverynonexistent', 'testdiscoveryexception'] self.pipeline_cfg[0]['resources'] = [] self.setup_pipeline() polling_tasks = self.mgr.setup_polling_tasks() self.mgr.interval_task(polling_tasks.get(60)) self.assertEqual(set(self.DiscoveryAnother.resources), set(self.Pollster.resources)) def _do_test_per_pipeline_discovery(self, discovered_resources, static_resources): self.mgr.discovery_manager = self.create_discovery_manager() self.Discovery.resources = discovered_resources self.DiscoveryAnother.resources = [d[::-1] for d in discovered_resources] self.pipeline_cfg[0]['discovery'] = ['testdiscovery', 'testdiscoveryanother', 'testdiscoverynonexistent', 'testdiscoveryexception'] self.pipeline_cfg[0]['resources'] = static_resources self.setup_pipeline() polling_tasks = self.mgr.setup_polling_tasks() self.mgr.interval_task(polling_tasks.get(60)) discovery = self.Discovery.resources + self.DiscoveryAnother.resources # compare resource lists modulo ordering self.assertEqual(set(static_resources + discovery), set(self.Pollster.resources)) def test_per_pipeline_discovery_discovered_only(self): self._do_test_per_pipeline_discovery(['discovered_1', 'discovered_2'], []) def test_per_pipeline_discovery_static_only(self): self._do_test_per_pipeline_discovery([], ['static_1', 'static_2']) def test_per_pipeline_discovery_discovered_augmented_by_static(self): self._do_test_per_pipeline_discovery(['discovered_1', 'discovered_2'], ['static_1', 'static_2']) def test_multiple_pipelines_different_static_resources(self): # assert that the amalgation of all static resources for a set # of pipelines with a common interval is passed to individual # pollsters matching those pipelines self.pipeline_cfg[0]['resources'] = ['test://'] self.pipeline_cfg.append({ 'name': "another_pipeline", 'interval': 60, 'counters': ['test'], 'resources': ['another://'], 'transformers': [], 'publishers': ["new"], }) self.mgr.discovery_manager = self.create_discovery_manager() self.Discovery.resources = [] self.setup_pipeline() polling_tasks = self.mgr.setup_polling_tasks() self.assertEqual(1, len(polling_tasks)) self.assertTrue(60 in polling_tasks.keys()) self.mgr.interval_task(polling_tasks.get(60)) self._verify_discovery_params([]) self.assertEqual(1, len(self.Pollster.samples)) amalgamated_resources = set(['test://', 'another://']) self.assertEqual(amalgamated_resources, set(self.Pollster.samples[0][1])) for pipeline in self.mgr.pipeline_manager.pipelines: self.assertEqual(1, len(pipeline.publishers[0].samples)) published = pipeline.publishers[0].samples[0] self.assertEqual(amalgamated_resources, set(published.resource_metadata['resources']))