blob: 8376e8459e639e9e13ce378b3ed55994cbe2d0a8 [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',
Guillaume Thouvenin6faa8622017-02-28 16:40:42 +01007 'alerting_enabled', 'notification_enabled',
8 'notification_handler', 'tag_fields')
Éric Lemoine6a1abe92016-11-03 14:02:43 +00009
10
Éric Lemoine7dc12132016-11-07 16:25:09 +000011def alarm_message_matcher(alarm, triggers):
Éric Lemoine6a1abe92016-11-03 14:02:43 +000012 """
13 Return an Heka message matcher expression for a given alarm and a
14 dict of triggers.
15
16 For example the function may return this:
17
18 Fields[name] == 'cpu_idle' || Fields[name] = 'cpu_wait'
19 """
20 matchers = set()
21 for trigger_name in alarm.get('triggers', []):
22 trigger = triggers.get(trigger_name)
23 if trigger and trigger.get('enabled', True):
24 for rule in trigger.get('rules', []):
25 matcher = "Fields[name] == '{}'".format(rule['metric'])
26 matchers.add(matcher)
27 return ' || '.join(matchers)
28
29
Swann Croiseteed005a2016-11-10 15:37:53 +010030def alarm_activate_alerting(alerting):
Éric Lemoinef45901e2016-11-16 13:02:50 +000031 return ('true' if alerting in ['enabled', 'enabled_with_notification']
32 else 'false')
Swann Croiseteed005a2016-11-10 15:37:53 +010033
34
35def alarm_enable_notification(alerting):
36 return 'true' if alerting == 'enabled_with_notification' else 'false'
37
38
Éric Lemoine7dc12132016-11-07 16:25:09 +000039def alarm_cluster_message_matcher(alarm_cluster):
40 """
41 Return an Heka message matcher expression for a given alarm cluster.
42
43 For example the function may return this:
44
45 Fields[service] == 'rabbitmq-cluster'
46 """
47 matchers = set()
48 match_items = alarm_cluster.get('match', {}).items()
49 for match_name, match_value in match_items:
50 matcher = "Fields[{}] == '{}'".format(match_name, match_value)
51 matchers.add(matcher)
52 match_items = alarm_cluster.get('match_re', {}).items()
53 for match_name, match_value in match_items:
54 matcher = "Fields[{}] =~ /{}/".format(match_name, match_value)
55 matchers.add(matcher)
56 return ' && '.join(matchers)
57
58
Éric Lemoinefc2ae372016-11-08 13:55:03 +000059def dimensions(alarm_or_alarm_cluster):
Éric Lemoine6a1abe92016-11-03 14:02:43 +000060 """
61 Return a dict alarm dimensions. Each dimension is validated, and an
62 Exception is raised if a dimension is invalid.
63
64 Valid characters are a-z, 0-9, _, - and /.
65 """
Éric Lemoinefc2ae372016-11-08 13:55:03 +000066 dimensions = alarm_or_alarm_cluster.get('dimension', {})
Éric Lemoine6a1abe92016-11-03 14:02:43 +000067 for name, value in dimensions.items():
68 if name in _disallowed_dimensions:
69 raise Exception(
70 '{} is not allowed as a dimension name'.format(name))
71 if not _valid_dimension_re.match(name):
72 raise Exception(
73 'Dimension name {} includes disallowed chars'.format(name))
74 if not _valid_dimension_re.match(value):
75 raise Exception(
76 'Dimension value {} includes disallowed chars'.format(value))
77 return dimensions
Éric Lemoine74f7bd32016-11-15 13:18:33 +000078
79
80def grains_for_mine(grains):
81 """
82 Return grains that need to be sent to Salt Mine. Only the alarm
83 and alarm cluster data is to be sent to Mine.
84 """
85 filtered_grains = {}
86 for service_name, service_data in grains.items():
Ilya Tyaptind31484e2016-12-12 19:25:07 +040087 if not service_data:
88 continue
Éric Lemoine74f7bd32016-11-15 13:18:33 +000089 alarm = service_data.get('alarm')
90 if alarm:
91 filtered_grains[service_name] = {'alarm': alarm}
Éric Lemoined26770f2016-11-16 13:01:59 +000092 trigger = service_data.get('trigger')
93 if trigger:
94 if service_name in filtered_grains:
95 filtered_grains[service_name].update(
96 {'trigger': trigger})
97 else:
98 filtered_grains[service_name] = {'trigger': trigger}
Éric Lemoine74f7bd32016-11-15 13:18:33 +000099 alarm_cluster = service_data.get('alarm_cluster')
100 if alarm_cluster:
101 if service_name in filtered_grains:
102 filtered_grains[service_name].update(
103 {'alarm_cluster': alarm_cluster})
104 else:
105 filtered_grains[service_name] = \
106 {'alarm_cluster': alarm_cluster}
107 return filtered_grains