diff --git a/config.yaml b/config.yaml index 5cf2da3..8a4876c 100644 --- a/config.yaml +++ b/config.yaml @@ -239,6 +239,16 @@ options: OpenStack mostly defaults to using public endpoints for internal communication between services. If set to True this option will configure services to use internal endpoints where possible. + events-publisher: + type: string + default: aodh + description: | + As of the Queens release ceilometer no longer consumes events on the + event.sample queue. Valid options here include "aodh" or "gnocchi" and + if you want to disable publishing events you can specify an empty string + "". The default is set to aodh for backwards compatibility. Note this + setting has no impact on the remote-sink option and is ignored prior to + Queens. remote-sink: type: string default: diff --git a/lib/ceilometer_contexts.py b/lib/ceilometer_contexts.py index 01f73bd..80799f2 100644 --- a/lib/ceilometer_contexts.py +++ b/lib/ceilometer_contexts.py @@ -17,9 +17,13 @@ from charmhelpers.core.hookenv import ( relation_get, related_units, config, + log, + INFO, + WARNING, ) from charmhelpers.contrib.openstack.utils import ( + get_os_codename_package, os_release, CompareOpenStackReleases, ) @@ -168,6 +172,27 @@ class RemoteSinksContext(OSContextGenerator): if not ctxt.get('internal_sinks'): ctxt['internal_sinks'] = {} ctxt['internal_sinks'][unit.split('/')[0]] = publisher + + release = get_os_codename_package('ceilometer-common', fatal=False) + ctxt['event_sink_publisher'] = None + if CompareOpenStackReleases(release) >= 'queens': + # NOTE: see bug LP 1676586 + if config('events-publisher') == "aodh": + ctxt['event_sink_publisher'] = 'notifier://?topic=alarm.all' + elif config('events-publisher') == "gnocchi": + if relation_ids('metric-service'): + ctxt['event_sink_publisher'] = 'gnocchi://' + else: + log("Unable to configure event publisher '{}' since " + "no gnocchi relation found". + format(config('events-publisher')), level=INFO) + elif config('events-publisher') == "": + log("Not configuring any event publishers", level=INFO) + else: + log("Invalid event publisher config provided '{}'. Not " + "configuring any event publishers". + format(config('events-publisher')), level=WARNING) + return ctxt diff --git a/templates/queens/event_pipeline.yaml b/templates/queens/event_pipeline.yaml new file mode 100644 index 0000000..8ad62b4 --- /dev/null +++ b/templates/queens/event_pipeline.yaml @@ -0,0 +1,38 @@ +--- +sources: + - name: event_source + events: + - "*" + sinks: + - event_sink +{%- if remote_sinks %} + - remote_sink +{% endif %} +{%- if internal_sinks %} +{%- for item in internal_sinks.keys() %} + - {{ item }} +{% endfor -%} +{% endif %} +sinks: +{%- if remote_sinks %} + - name: remote_sink + transformers: + publishers: + {% for item in remote_sinks -%} + - {{ item }} + {% endfor %} +{%- endif -%} +{%- if internal_sinks %} +{%- for item, target in internal_sinks.items() -%} + - name: {{ item }} + transformers: + publishers: + - {{ target }} +{%- endfor %} +{% endif %} + - name: event_sink + transformers: + publishers: +{%- if event_sink_publisher %} + - {{ event_sink_publisher }} +{% endif %} diff --git a/unit_tests/test_ceilometer_contexts.py b/unit_tests/test_ceilometer_contexts.py index e70a65e..40154ff 100644 --- a/unit_tests/test_ceilometer_contexts.py +++ b/unit_tests/test_ceilometer_contexts.py @@ -226,13 +226,23 @@ class CeilometerContextsTest(CharmTestCase): } self.assertEqual(contexts.HAProxyContext()(), expected) - def test_remote_sink_context_no_config(self): + @patch.object(contexts, 'get_os_codename_package') + def test_remote_sink_context_no_config(self, mock_get_rel): + mock_get_rel.return_value = 'mitaka' self.relation_ids.return_value = [] self.os_release.return_value = 'mitaka' - self.assertEqual(contexts.RemoteSinksContext()(), {}) + self.assertEqual(contexts.RemoteSinksContext()(), { + 'event_sink_publisher': None}) - def test_remote_sink_context_event_service_relation(self): - self.relation_ids.return_value = ['event-service:0'] + mock_get_rel.return_value = 'queens' + self.assertEqual(contexts.RemoteSinksContext()(), + {'event_sink_publisher': + 'notifier://?topic=alarm.all'}) + + @patch.object(contexts, 'get_os_codename_package') + def test_remote_sink_context_event_service_relation(self, mock_get_rel): + mock_get_rel.return_value = 'mitaka' + self.relation_ids.return_value = ['event-service:0', 'meter-service:0'] self.related_units.return_value = ['panko/0'] self.os_release.return_value = 'mitaka' data = { @@ -240,21 +250,64 @@ class CeilometerContextsTest(CharmTestCase): } self.test_relation.set(data) self.assertEqual(contexts.RemoteSinksContext()(), - {'internal_sinks': {'panko': 'panko://'}}) + {'internal_sinks': {'panko': 'panko://'}, + 'event_sink_publisher': None}) - def test_remote_sink_context_with_single_config(self): - self.relation_ids.return_value = [] + mock_get_rel.return_value = 'queens' + self.assertEqual(contexts.RemoteSinksContext()(), + {'internal_sinks': {'panko': 'panko://'}, + 'event_sink_publisher': + 'notifier://?topic=alarm.all'}) + + self.test_config.set('events-publisher', 'gnocchi') + self.assertEqual(contexts.RemoteSinksContext()(), + {'internal_sinks': {'panko': 'panko://'}, + 'event_sink_publisher': + 'gnocchi://'}) + + @patch.object(contexts, 'get_os_codename_package') + def test_remote_sink_context_with_single_config(self, mock_get_rel): + mock_get_rel.return_value = 'mitaka' + self.relation_ids.return_value = ['meter-service:0'] self.os_release.return_value = 'mitaka' self.test_config.set('remote-sink', 'http://foo') self.assertEqual(contexts.RemoteSinksContext()(), - {'remote_sinks': ['http://foo']}) + {'remote_sinks': ['http://foo'], + 'event_sink_publisher': None}) - def test_remote_sink_context_with_multiple_config(self): - self.relation_ids.return_value = [] + mock_get_rel.return_value = 'queens' + self.assertEqual(contexts.RemoteSinksContext()(), + {'remote_sinks': ['http://foo'], + 'event_sink_publisher': + 'notifier://?topic=alarm.all'}) + + self.test_config.set('events-publisher', 'gnocchi') + self.assertEqual(contexts.RemoteSinksContext()(), + {'remote_sinks': ['http://foo'], + 'event_sink_publisher': + 'gnocchi://'}) + + @patch.object(contexts, 'get_os_codename_package') + def test_remote_sink_context_with_multiple_config(self, mock_get_rel): + mock_get_rel.return_value = 'mitaka' + self.relation_ids.return_value = ['meter-service:0'] self.os_release.return_value = 'mitaka' self.test_config.set('remote-sink', 'http://foo http://bar') self.assertEqual(contexts.RemoteSinksContext()(), - {'remote_sinks': ['http://foo', 'http://bar']}) + {'remote_sinks': ['http://foo', 'http://bar'], + 'event_sink_publisher': None}) + + mock_get_rel.return_value = 'queens' + self.assertEqual(contexts.RemoteSinksContext()(), + {'remote_sinks': ['http://foo', 'http://bar'], + 'event_sink_publisher': + 'notifier://?topic=alarm.all'}) + + self.test_config.set('events-publisher', 'gnocchi') + self.assertEqual(contexts.RemoteSinksContext()(), + {'remote_sinks': ['http://foo', 'http://bar'], + 'event_sink_publisher': + 'gnocchi://'}) @patch.object(contexts, 'AMQPContext') def test_AMQPListenersContext(self, mock_AMQPContext):