blob: 8f86efdb3c230b347cbf84d29d5fcddf35ee30c8 [file] [log] [blame]
Éric Lemoine6a1abe92016-11-03 14:02:43 +00001# -*- coding: utf-8 -*-
2
3import re
4
5_valid_dimension_re = re.compile(r'^[a-z0-9_/-]+$')
6_disallowed_dimensions = ('name', 'value', 'hostname', 'member',
7 'no_alerting', 'tag_fields')
8
9
Éric Lemoine7dc12132016-11-07 16:25:09 +000010def alarm_message_matcher(alarm, triggers):
Éric Lemoine6a1abe92016-11-03 14:02:43 +000011 """
12 Return an Heka message matcher expression for a given alarm and a
13 dict of triggers.
14
15 For example the function may return this:
16
17 Fields[name] == 'cpu_idle' || Fields[name] = 'cpu_wait'
18 """
19 matchers = set()
20 for trigger_name in alarm.get('triggers', []):
21 trigger = triggers.get(trigger_name)
22 if trigger and trigger.get('enabled', True):
23 for rule in trigger.get('rules', []):
24 matcher = "Fields[name] == '{}'".format(rule['metric'])
25 matchers.add(matcher)
26 return ' || '.join(matchers)
27
28
Swann Croiseteed005a2016-11-10 15:37:53 +010029def alarm_activate_alerting(alerting):
Éric Lemoinef45901e2016-11-16 13:02:50 +000030 return ('true' if alerting in ['enabled', 'enabled_with_notification']
31 else 'false')
Swann Croiseteed005a2016-11-10 15:37:53 +010032
33
34def alarm_enable_notification(alerting):
35 return 'true' if alerting == 'enabled_with_notification' else 'false'
36
37
Éric Lemoine7dc12132016-11-07 16:25:09 +000038def alarm_cluster_message_matcher(alarm_cluster):
39 """
40 Return an Heka message matcher expression for a given alarm cluster.
41
42 For example the function may return this:
43
44 Fields[service] == 'rabbitmq-cluster'
45 """
46 matchers = set()
47 match_items = alarm_cluster.get('match', {}).items()
48 for match_name, match_value in match_items:
49 matcher = "Fields[{}] == '{}'".format(match_name, match_value)
50 matchers.add(matcher)
51 match_items = alarm_cluster.get('match_re', {}).items()
52 for match_name, match_value in match_items:
53 matcher = "Fields[{}] =~ /{}/".format(match_name, match_value)
54 matchers.add(matcher)
55 return ' && '.join(matchers)
56
57
Éric Lemoinefc2ae372016-11-08 13:55:03 +000058def dimensions(alarm_or_alarm_cluster):
Éric Lemoine6a1abe92016-11-03 14:02:43 +000059 """
60 Return a dict alarm dimensions. Each dimension is validated, and an
61 Exception is raised if a dimension is invalid.
62
63 Valid characters are a-z, 0-9, _, - and /.
64 """
Éric Lemoinefc2ae372016-11-08 13:55:03 +000065 dimensions = alarm_or_alarm_cluster.get('dimension', {})
Éric Lemoine6a1abe92016-11-03 14:02:43 +000066 for name, value in dimensions.items():
67 if name in _disallowed_dimensions:
68 raise Exception(
69 '{} is not allowed as a dimension name'.format(name))
70 if not _valid_dimension_re.match(name):
71 raise Exception(
72 'Dimension name {} includes disallowed chars'.format(name))
73 if not _valid_dimension_re.match(value):
74 raise Exception(
75 'Dimension value {} includes disallowed chars'.format(value))
76 return dimensions
Éric Lemoine74f7bd32016-11-15 13:18:33 +000077
78
79def grains_for_mine(grains):
80 """
81 Return grains that need to be sent to Salt Mine. Only the alarm
82 and alarm cluster data is to be sent to Mine.
83 """
84 filtered_grains = {}
85 for service_name, service_data in grains.items():
86 alarm = service_data.get('alarm')
87 if alarm:
88 filtered_grains[service_name] = {'alarm': alarm}
Éric Lemoined26770f2016-11-16 13:01:59 +000089 trigger = service_data.get('trigger')
90 if trigger:
91 if service_name in filtered_grains:
92 filtered_grains[service_name].update(
93 {'trigger': trigger})
94 else:
95 filtered_grains[service_name] = {'trigger': trigger}
Éric Lemoine74f7bd32016-11-15 13:18:33 +000096 alarm_cluster = service_data.get('alarm_cluster')
97 if alarm_cluster:
98 if service_name in filtered_grains:
99 filtered_grains[service_name].update(
100 {'alarm_cluster': alarm_cluster})
101 else:
102 filtered_grains[service_name] = \
103 {'alarm_cluster': alarm_cluster}
104 return filtered_grains