Add support for remote consumers of Ceilometer event data.
There is a use-case to forward events received by ceilometer from OpenStack services to an external system via http/udp. It comes from the fact that aodh does not include all information about an event alarm into POSTed data. Raw event data can be published by ceilometer via http/udp to an external system without giving a user direct access to rabbitmq. This patch adds a context generator, associated templates, and configuration entry for configuring multiple event-sinks in /etc/ceilometer/event_pipeline.yaml. This also modifies the ceilometer.conf templates to reflect the correct naming of the same file to align with upstream Ceilometer. Also adds support for a future Panko charm event consumer using the event-service interface in the above context with associated metadata and hook symlinks. This change will only effect Mitaka and later clouds. Closes Bug: 1763321 Change-Id: I931438c720272bd9a3d2b958ebabcd3584790bd0
This commit is contained in:
parent
9dc9ce6e09
commit
668a289862
10
config.yaml
10
config.yaml
@ -239,3 +239,13 @@ 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.
|
||||
remote-sink:
|
||||
type: string
|
||||
default:
|
||||
description: |
|
||||
Space delimited list of remote consumers of Ceilometer event reporting
|
||||
which reside outside of the deployed model. Only supported for Mitaka
|
||||
and later clouds. e.g.
|
||||
.
|
||||
'udp://<host>:<port>/'
|
||||
'prometheus://pushgateway-host:9091/metrics/job/openstack-telemetry'
|
||||
|
@ -153,7 +153,9 @@ def metric_service_joined():
|
||||
"identity-credentials-relation-changed",
|
||||
"identity-credentials-relation-departed",
|
||||
"metric-service-relation-changed",
|
||||
"metric-service-relation-departed")
|
||||
"metric-service-relation-departed",
|
||||
"event-service-relation-changed",
|
||||
"event-service-relation-departed",)
|
||||
@restart_on_change(restart_map())
|
||||
def any_changed():
|
||||
CONFIGS.write_all()
|
||||
|
1
hooks/event-service-relation-broken
Symbolic link
1
hooks/event-service-relation-broken
Symbolic link
@ -0,0 +1 @@
|
||||
ceilometer_hooks.py
|
1
hooks/event-service-relation-changed
Symbolic link
1
hooks/event-service-relation-changed
Symbolic link
@ -0,0 +1 @@
|
||||
ceilometer_hooks.py
|
1
hooks/event-service-relation-departed
Symbolic link
1
hooks/event-service-relation-departed
Symbolic link
@ -0,0 +1 @@
|
||||
ceilometer_hooks.py
|
1
hooks/event-service-relation-joined
Symbolic link
1
hooks/event-service-relation-joined
Symbolic link
@ -0,0 +1 @@
|
||||
ceilometer_hooks.py
|
@ -140,6 +140,26 @@ class HAProxyContext(OSContextGenerator):
|
||||
return ctxt
|
||||
|
||||
|
||||
class RemoteSinksContext(OSContextGenerator):
|
||||
interfaces = ['event-service']
|
||||
|
||||
def __call__(self):
|
||||
'''Generates context for remote sinks for Panko and other compatible
|
||||
remote consumers of Ceilometer event data.
|
||||
'''
|
||||
ctxt = {}
|
||||
if config('remote-sink'):
|
||||
ctxt['remote_sinks'] = config('remote-sink').split(' ')
|
||||
for relid in relation_ids('event-service'):
|
||||
for unit in related_units(relid):
|
||||
publisher = relation_get('publisher', unit=unit, rid=relid)
|
||||
if publisher:
|
||||
if not ctxt.get('internal_sinks'):
|
||||
ctxt['internal_sinks'] = {}
|
||||
ctxt['internal_sinks'][unit.split('/')[0]] = publisher
|
||||
return ctxt
|
||||
|
||||
|
||||
class ApacheSSLContext(SSLContext):
|
||||
|
||||
external_ports = [CEILOMETER_PORT]
|
||||
|
@ -31,6 +31,7 @@ from ceilometer_contexts import (
|
||||
HAProxyContext,
|
||||
MetricServiceContext,
|
||||
CEILOMETER_PORT,
|
||||
RemoteSinksContext,
|
||||
)
|
||||
from charmhelpers.contrib.openstack.utils import (
|
||||
get_os_codename_package,
|
||||
@ -51,6 +52,7 @@ from charmhelpers.core.hookenv import (
|
||||
is_leader,
|
||||
log,
|
||||
DEBUG,
|
||||
relation_ids,
|
||||
)
|
||||
from charmhelpers.fetch import apt_update, apt_install, apt_upgrade
|
||||
from charmhelpers.core.host import init_is_systemd
|
||||
@ -67,6 +69,7 @@ HTTPS_APACHE_24_CONF = "/etc/apache2/sites-available/" \
|
||||
"openstack_https_frontend.conf"
|
||||
CLUSTER_RES = 'grp_ceilometer_vips'
|
||||
MEMCACHED_CONF = '/etc/memcached.conf'
|
||||
PIPELINE_CONF = '/etc/ceilometer/event_pipeline.yaml'
|
||||
|
||||
CEILOMETER_BASE_SERVICES = [
|
||||
'ceilometer-agent-central',
|
||||
@ -238,6 +241,8 @@ def register_configs():
|
||||
CeilometerContext(),
|
||||
HAProxyContext()]
|
||||
)
|
||||
if CompareOpenStackReleases(release) >= 'mitaka':
|
||||
configs.register(PIPELINE_CONF, [RemoteSinksContext()])
|
||||
return configs
|
||||
|
||||
|
||||
@ -420,6 +425,17 @@ def set_shared_secret(secret):
|
||||
secret_file.write(secret)
|
||||
|
||||
|
||||
def get_optional_relations():
|
||||
"""Return a dictionary of optional relations.
|
||||
|
||||
@returns {relation: relation_name}
|
||||
"""
|
||||
optional_interfaces = {}
|
||||
if relation_ids('event-service'):
|
||||
optional_interfaces['event-service'] = ['event-service']
|
||||
return optional_interfaces
|
||||
|
||||
|
||||
def assess_status(configs):
|
||||
"""Assess status of current unit
|
||||
|
||||
@ -444,6 +460,7 @@ def resolve_required_interfaces():
|
||||
@returns dict - a dictionary keyed by high-level type of interfaces names
|
||||
"""
|
||||
required_ints = deepcopy(REQUIRED_INTERFACES)
|
||||
required_ints.update(get_optional_relations())
|
||||
if CompareOpenStackReleases(os_release('ceilometer-common')) >= 'mitaka':
|
||||
required_ints['database'].append('metric-service')
|
||||
if CompareOpenStackReleases(os_release('ceilometer-common')) >= 'queens':
|
||||
|
@ -43,6 +43,8 @@ requires:
|
||||
scope: container
|
||||
metric-service:
|
||||
interface: gnocchi
|
||||
event-service:
|
||||
interface: event-service
|
||||
peers:
|
||||
cluster:
|
||||
interface: ceilometer-ha
|
||||
|
@ -12,7 +12,7 @@ api_workers = {{ workers }}
|
||||
collector_workers = {{ workers }}
|
||||
notification_workers = {{ workers }}
|
||||
|
||||
event_pipeline_cfg_file = /etc/ceilometer/event_pipeline_alarm.yaml
|
||||
event_pipeline_cfg_file = /etc/ceilometer/event_pipeline.yaml
|
||||
|
||||
{% if gnocchi_url -%}
|
||||
meter_dispatchers = gnocchi
|
||||
|
37
templates/mitaka/event_pipeline.yaml
Normal file
37
templates/mitaka/event_pipeline.yaml
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
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:
|
||||
- notifier://
|
||||
- notifier://?topic=alarm.all
|
@ -8,7 +8,7 @@
|
||||
debug = {{ debug }}
|
||||
verbose = {{ verbose }}
|
||||
use_syslog = {{ use_syslog }}
|
||||
event_pipeline_cfg_file = /etc/ceilometer/event_pipeline_alarm.yaml
|
||||
event_pipeline_cfg_file = /etc/ceilometer/event_pipeline.yaml
|
||||
|
||||
{% if gnocchi_url -%}
|
||||
meter_dispatchers = gnocchi
|
||||
|
@ -141,7 +141,7 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
|
||||
}
|
||||
if self._get_openstack_release() >= self.xenial_pike:
|
||||
configs['ceph-osd'] = {'osd-devices': '/dev/vdb',
|
||||
'osd-reformat': 'yes',
|
||||
'osd-reformat': True,
|
||||
'ephemeral-unmount': '/mnt'}
|
||||
super(CeilometerBasicDeployment, self)._configure_services(configs)
|
||||
|
||||
|
@ -193,3 +193,33 @@ class CeilometerContextsTest(CharmTestCase):
|
||||
'port': api_port
|
||||
}
|
||||
self.assertEqual(contexts.HAProxyContext()(), expected)
|
||||
|
||||
def test_remote_sink_context_no_config(self):
|
||||
self.relation_ids.return_value = []
|
||||
self.os_release.return_value = 'mitaka'
|
||||
self.assertEqual(contexts.RemoteSinksContext()(), {})
|
||||
|
||||
def test_remote_sink_context_event_service_relation(self):
|
||||
self.relation_ids.return_value = ['event-service:0']
|
||||
self.related_units.return_value = ['panko/0']
|
||||
self.os_release.return_value = 'mitaka'
|
||||
data = {
|
||||
'publisher': 'panko://'
|
||||
}
|
||||
self.test_relation.set(data)
|
||||
self.assertEqual(contexts.RemoteSinksContext()(),
|
||||
{'internal_sinks': {'panko': 'panko://'}})
|
||||
|
||||
def test_remote_sink_context_with_single_config(self):
|
||||
self.relation_ids.return_value = []
|
||||
self.os_release.return_value = 'mitaka'
|
||||
self.test_config.set('remote-sink', 'http://foo')
|
||||
self.assertEqual(contexts.RemoteSinksContext()(),
|
||||
{'remote_sinks': ['http://foo']})
|
||||
|
||||
def test_remote_sink_context_with_multiple_config(self):
|
||||
self.relation_ids.return_value = []
|
||||
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']})
|
||||
|
@ -39,6 +39,7 @@ TO_PATCH = [
|
||||
'os_release',
|
||||
'is_leader',
|
||||
'reset_os_release',
|
||||
'relation_ids',
|
||||
]
|
||||
|
||||
|
||||
@ -275,6 +276,7 @@ class CeilometerUtilsTest(CharmTestCase):
|
||||
def test_resolve_required_interfaces(self):
|
||||
self.os_release.side_effect = None
|
||||
self.os_release.return_value = 'icehouse'
|
||||
self.relation_ids.return_value = None
|
||||
self.assertEqual(
|
||||
utils.resolve_required_interfaces(),
|
||||
{
|
||||
@ -287,6 +289,7 @@ class CeilometerUtilsTest(CharmTestCase):
|
||||
def test_resolve_required_interfaces_mitaka(self):
|
||||
self.os_release.side_effect = None
|
||||
self.os_release.return_value = 'mitaka'
|
||||
self.relation_ids.return_value = None
|
||||
self.assertEqual(
|
||||
utils.resolve_required_interfaces(),
|
||||
{
|
||||
@ -299,6 +302,7 @@ class CeilometerUtilsTest(CharmTestCase):
|
||||
def test_resolve_required_interfaces_queens(self):
|
||||
self.os_release.side_effect = None
|
||||
self.os_release.return_value = 'queens'
|
||||
self.relation_ids.return_value = None
|
||||
self.assertEqual(
|
||||
utils.resolve_required_interfaces(),
|
||||
{
|
||||
@ -308,6 +312,20 @@ class CeilometerUtilsTest(CharmTestCase):
|
||||
}
|
||||
)
|
||||
|
||||
def test_resolve_optional_interfaces(self):
|
||||
self.os_release.side_effect = None
|
||||
self.os_release.return_value = 'icehouse'
|
||||
self.relation_ids.return_value = [0]
|
||||
self.assertEqual(
|
||||
utils.resolve_required_interfaces(),
|
||||
{
|
||||
'database': ['mongodb'],
|
||||
'messaging': ['amqp'],
|
||||
'identity': ['identity-service'],
|
||||
'event-service': ['event-service'],
|
||||
}
|
||||
)
|
||||
|
||||
@patch.object(utils, 'subprocess')
|
||||
def test_ceilometer_upgrade(self, mock_subprocess):
|
||||
self.is_leader.return_value = True
|
||||
|
Loading…
Reference in New Issue
Block a user