blob: 8f86efdb3c230b347cbf84d29d5fcddf35ee30c8 [file] [log] [blame]
# -*- coding: utf-8 -*-
import re
_valid_dimension_re = re.compile(r'^[a-z0-9_/-]+$')
_disallowed_dimensions = ('name', 'value', 'hostname', 'member',
'no_alerting', 'tag_fields')
def alarm_message_matcher(alarm, triggers):
"""
Return an Heka message matcher expression for a given alarm and a
dict of triggers.
For example the function may return this:
Fields[name] == 'cpu_idle' || Fields[name] = 'cpu_wait'
"""
matchers = set()
for trigger_name in alarm.get('triggers', []):
trigger = triggers.get(trigger_name)
if trigger and trigger.get('enabled', True):
for rule in trigger.get('rules', []):
matcher = "Fields[name] == '{}'".format(rule['metric'])
matchers.add(matcher)
return ' || '.join(matchers)
def alarm_activate_alerting(alerting):
return ('true' if alerting in ['enabled', 'enabled_with_notification']
else 'false')
def alarm_enable_notification(alerting):
return 'true' if alerting == 'enabled_with_notification' else 'false'
def alarm_cluster_message_matcher(alarm_cluster):
"""
Return an Heka message matcher expression for a given alarm cluster.
For example the function may return this:
Fields[service] == 'rabbitmq-cluster'
"""
matchers = set()
match_items = alarm_cluster.get('match', {}).items()
for match_name, match_value in match_items:
matcher = "Fields[{}] == '{}'".format(match_name, match_value)
matchers.add(matcher)
match_items = alarm_cluster.get('match_re', {}).items()
for match_name, match_value in match_items:
matcher = "Fields[{}] =~ /{}/".format(match_name, match_value)
matchers.add(matcher)
return ' && '.join(matchers)
def dimensions(alarm_or_alarm_cluster):
"""
Return a dict alarm dimensions. Each dimension is validated, and an
Exception is raised if a dimension is invalid.
Valid characters are a-z, 0-9, _, - and /.
"""
dimensions = alarm_or_alarm_cluster.get('dimension', {})
for name, value in dimensions.items():
if name in _disallowed_dimensions:
raise Exception(
'{} is not allowed as a dimension name'.format(name))
if not _valid_dimension_re.match(name):
raise Exception(
'Dimension name {} includes disallowed chars'.format(name))
if not _valid_dimension_re.match(value):
raise Exception(
'Dimension value {} includes disallowed chars'.format(value))
return dimensions
def grains_for_mine(grains):
"""
Return grains that need to be sent to Salt Mine. Only the alarm
and alarm cluster data is to be sent to Mine.
"""
filtered_grains = {}
for service_name, service_data in grains.items():
alarm = service_data.get('alarm')
if alarm:
filtered_grains[service_name] = {'alarm': alarm}
trigger = service_data.get('trigger')
if trigger:
if service_name in filtered_grains:
filtered_grains[service_name].update(
{'trigger': trigger})
else:
filtered_grains[service_name] = {'trigger': trigger}
alarm_cluster = service_data.get('alarm_cluster')
if alarm_cluster:
if service_name in filtered_grains:
filtered_grains[service_name].update(
{'alarm_cluster': alarm_cluster})
else:
filtered_grains[service_name] = \
{'alarm_cluster': alarm_cluster}
return filtered_grains