Refactoring: Changed all check parameters starting with an 'o' to the new rulespec...
[check_mk.git] / checks / local
blob7a64587add0f89659f622519343e5c7ad7f6dae6
1 #!/usr/bin/python
2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
9 # | |
10 # | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
27 # Example output from agent:
28 # 0 Service_FOO V=1 This Check is OK
29 # 1 Bar_Service - This is WARNING and has no performance data
30 # 2 NotGood V=120;50;100;0;1000 A critical check
31 # P Some_other_Service value1=10;30;50|value2=20;10:20;0:50;0;100 Result is computed from two values
32 # P This_is_OK foo=18;20;50
33 # P Some_yet_other_Service temp=40;30;50|humidity=28;50:100;0:50;0;100
34 # P Has-no-var - This has no variable
35 # P No-Text hirn=-8;-20
38 # Compute state according to warn/crit levels contained in the
39 # performance data.
40 def local_compute_state(perfdata):
41 texts = []
43 # 16MB -> 16.0
44 def float_ignore_uom(value):
45 while value:
46 if value[-1] not in "0123456789.-":
47 value = value[:-1]
48 else:
49 return float(value)
50 return 0.0
52 def outof_levels(value, levels):
53 if levels is None:
54 return
56 if ':' in levels:
57 lower, upper = map(float, levels.split(':'))
58 else:
59 lower = None
60 upper = float(levels)
61 if value > upper:
62 return " %s > %s" % (value, upper)
63 elif lower is not None and value < lower:
64 return " %s < %s" % (value, lower)
66 worst = 0
67 for entry in perfdata:
68 if len(entry) < 3:
69 continue # No levels attached
70 varname = entry[0]
71 value = float_ignore_uom(entry[1])
72 warn = entry[2]
73 if len(entry) >= 4:
74 crit = entry[3]
75 else:
76 crit = None
78 text = outof_levels(value, crit)
79 if text:
80 worst = 2
81 text = "%s%s(!!)" % (varname, text)
82 texts.append(text)
84 else:
85 text = outof_levels(value, warn)
86 if text:
87 worst = max(worst, 1)
88 text = "%s%s(!)" % (varname, text)
89 texts.append(text)
91 else:
92 texts.append("%s is %s(.)" % (varname, value))
94 return worst, texts
97 def inventory_local(info):
98 inventory = []
99 # Lines with P do not need to supply a text
100 for line in info:
101 stripped_line = line[1:]
102 if len(stripped_line) >= 4 or len(stripped_line) == 3 and stripped_line[0] == 'P':
103 inventory.append((stripped_line[1], {}))
104 else:
105 raise MKGeneralException(
106 "Invalid line in agent section <<<local>>>: %s" % " ".join(stripped_line))
107 return inventory
110 # Some helper functions
111 def _parse_local_line(line):
112 if not (len(line) >= 4 or (len(line) == 3 and line[0] == 'P')):
113 return 3, "Incomplete line in local check output: %s" % " ".join(line), []
115 statechar = line[0]
116 perftxt = line[2]
118 # convert eventually escaped newinfo_line chars to real newinfo_lines
119 # (will be converted back later individually for the different cores)
120 output = " ".join(line[3:]).replace("\\n", "\n")
122 perfdata = []
123 compute_data = []
124 if perftxt != "-":
125 for entry in perftxt.split('|'):
126 try:
127 varname, valuetxt = entry.split('=')
128 values = valuetxt.split(';')
129 compute_data.append(tuple([varname] + values))
130 # perfdata must not contain values with colons. So we split
131 # these values and use the upper levels only.
132 upper_values = [v.split(':')[-1] for v in values]
133 perfdata.append(tuple([varname] + upper_values))
135 except ValueError:
136 return 3, "Invalid performance data %s in local check output %s" % \
137 (perftxt, " ".join(line)), []
139 if statechar == 'P':
140 state, texts = local_compute_state(compute_data)
141 if output:
142 texts = [output] + texts
143 output = ", ".join(texts)
145 else:
146 try:
147 state = int(statechar)
148 except:
149 return 3, "Invalid state %s in local check output %s: must be P, 0, 1, 2 or 3" % \
150 (statechar, " ".join(line)), []
152 if state not in range(0, 4):
153 output += ", local check has sent invalid state %d" % state
154 state = 3
156 return state, output, perfdata
159 def _calculate_local_best_state(collected_stats):
160 states = []
161 infotexts = []
162 perfdatas = []
163 for nodename, attrs in collected_stats.items():
164 for state, output, perfdata in attrs.itervalues():
165 if nodename is not None:
166 output = "On node %s: %s" % (nodename, output)
167 states.append(state)
168 infotexts.append(output)
169 perfdatas += perfdata
170 return min(states), ", ".join(infotexts), perfdatas
173 def _calculate_local_worst_state(collected_stats):
174 for nodename, attrs in collected_stats.items():
175 for state, output, perfdata in attrs.itervalues():
176 if nodename is not None:
177 output = "On node %s: %s" % (nodename, output)
178 yield state, output, perfdata
181 def check_local(item, params, info):
182 collected_stats = {}
183 for line in info:
184 nodename = line[0]
185 stripped_line = line[1:]
186 # Ignore invalid lines, tolerate bugs in local checks
187 # of unexperienced users
188 if len(stripped_line) >= 2 and stripped_line[1] == item:
189 collected_stats.setdefault(nodename, {})
190 collected_stats[nodename].setdefault(item, _parse_local_line(stripped_line))
192 if collected_stats == {}:
193 yield 3, "No data found in agent output"
194 return
196 if params is not None and params.get("outcome_on_cluster", "worst") == "best":
197 yield _calculate_local_best_state(collected_stats)
198 return
199 else:
200 for res in _calculate_local_worst_state(collected_stats):
201 yield res
204 check_info["local"] = {
205 'check_function': check_local,
206 'inventory_function': inventory_local,
207 'service_description': '%s',
208 'has_perfdata': True,
209 'node_info': True,
210 'group': 'local',