ceilometer/ceilometer/tests/agentbase.py

494 lines
19 KiB
Python

# -*- encoding: utf-8 -*-
#
# Copyright © 2012 New Dream Network, LLC (DreamHost)
# Copyright © 2013 Intel corp.
# Copyright © 2013 eNovance
# Copyright © 2014 Red Hat, Inc
#
# Authors: Yunhong Jiang <yunhong.jiang@intel.com>
# Julien Danjou <julien@danjou.info>
# Eoghan Glynn <eglynn@redhat.com>
#
# 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 create_pollster_manager(self):
return extension.ExtensionManager.make_test_instance(
[
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_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']))