2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
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
40 def local_compute_state(perfdata
):
44 def float_ignore_uom(value
):
46 if value
[-1] not in "0123456789.-":
52 def outof_levels(value
, levels
):
57 lower
, upper
= map(float, levels
.split(':'))
62 return " %s > %s" % (value
, upper
)
63 elif lower
is not None and value
< lower
:
64 return " %s < %s" % (value
, lower
)
67 for entry
in perfdata
:
69 continue # No levels attached
71 value
= float_ignore_uom(entry
[1])
78 text
= outof_levels(value
, crit
)
81 text
= "%s%s(!!)" % (varname
, text
)
85 text
= outof_levels(value
, warn
)
88 text
= "%s%s(!)" % (varname
, text
)
92 texts
.append("%s is %s(.)" % (varname
, value
))
97 def inventory_local(info
):
99 # Lines with P do not need to supply a text
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], {}))
105 raise MKGeneralException(
106 "Invalid line in agent section <<<local>>>: %s" % " ".join(stripped_line
))
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
), []
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")
125 for entry
in perftxt
.split('|'):
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
))
136 return 3, "Invalid performance data %s in local check output %s" % \
137 (perftxt
, " ".join(line
)), []
140 state
, texts
= local_compute_state(compute_data
)
142 texts
= [output
] + texts
143 output
= ", ".join(texts
)
147 state
= int(statechar
)
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
156 return state
, output
, perfdata
159 def _calculate_local_best_state(collected_stats
):
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
)
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
):
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"
196 if params
is not None and params
.get("outcome_on_cluster", "worst") == "best":
197 yield _calculate_local_best_state(collected_stats
)
200 for res
in _calculate_local_worst_state(collected_stats
):
204 check_info
["local"] = {
205 'check_function': check_local
,
206 'inventory_function': inventory_local
,
207 'service_description': '%s',
208 'has_perfdata': True,