Refactoring: Changed all check parameters starting with an 'o' to the new rulespec...
[check_mk.git] / checks / mknotifyd
blob786393647ebaaca237f42ece5c7f05910c012dcf
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 # <<<mknotifyd:sep(0)>>>
29 # [mysite]
30 # Version: 1.2.7i1
31 # Updated: 1425389753 (2015-03-03 14:35:53)
32 # Started: 1425388950 (2015-03-03 14:22:30, 803 sec ago)
33 # Configuration: 1425388950 (2015-03-03 14:22:30, 803 sec ago)
34 # Listening FD: 4
36 # Spool: New
37 # Count: 0
38 # Oldest:
40 # Spool: Deferred
41 # Count: 0
42 # Oldest:
44 # Spool: Corrupted
45 # Count: 4
46 # Oldest: 1425305956 (2015-03-02 15:19:16, 83797 sec ago)
48 # Connection: 127.0.0.1:46906
49 # Type: incoming
50 # State: established
51 # Since: 1425389490 (2015-03-03 14:31:30, 263 sec ago)
52 # Socket FD: 5
53 # HB. Interval: 10 sec
54 # LastHeartbeat: 1425389750 (2015-03-03 14:35:50, 3 sec ago)
55 # InputBuffer: 0 Bytes
56 # OutputBuffer: 0 Bytes
59 def parse_mknotifyd(info):
60 parsed = {}
61 for line in info:
62 if line[0].startswith('['):
63 site = line[0][1:-1]
64 site_entry = {
65 "spools": {},
66 "connections": {},
67 "queues": {},
69 sub_entry = site_entry
70 parsed[site] = site_entry
71 else:
72 varname, value = line[0].split(":", 1)
73 value = value.strip()
75 if varname == "Spool":
76 sub_entry = {}
77 site_entry["spools"][value] = sub_entry
79 elif varname == "Connection":
80 sub_entry = {}
81 site_entry["connections"][value] = sub_entry
83 elif varname == "Queue":
84 sub_entry = {}
85 site_entry["queues"][value] = sub_entry
87 else:
88 if value == "None":
89 value = None
90 elif value and varname == "Listening FD":
91 # May be the listening FD number or an error message
92 try:
93 value = int(value.split()[0])
94 except ValueError:
95 pass
96 elif value and varname not in [
97 "Type",
98 "State",
99 "Version",
100 "Status Message",
101 "Pending Acknowledgements",
102 "Connect Time",
104 value = int(value.split()[0])
105 elif varname == "Connect Time":
106 value = float(value.split()[0])
107 sub_entry[varname] = value
109 # Fixup names of the connections. For incoming connections the remote
110 # port is irrelevant. It changes randomly. But there might anyway be
111 # more than one connection from the same remote host, so we are forced
112 # to create artificial numbers if that is the case
113 for stats in parsed.itervalues():
114 remote_addresses = {}
115 for connection_name, connection in stats["connections"].items():
116 if connection["Type"] == "incoming":
117 remote_address = connection_name.split(":")[0]
118 remote_addresses.setdefault(remote_address, []).append(connection)
119 del stats["connections"][connection_name]
121 for address, connections in remote_addresses.items():
122 if len(connections) == 1:
123 stats["connections"][address] = connections[0]
124 else:
125 for nr, connection in enumerate(connections):
126 stats["connections"][address + "/" + str(nr + 1)] = connection
128 return parsed
131 # .--Spooler Status------------------------------------------------------.
132 # | ____ _ ____ _ _ |
133 # |/ ___| _ __ ___ ___ | | ___ _ __ / ___|| |_ __ _| |_ _ _ ___ |
134 # |\___ \| '_ \ / _ \ / _ \| |/ _ \ '__| \___ \| __/ _` | __| | | / __| |
135 # | ___) | |_) | (_) | (_) | | __/ | ___) | || (_| | |_| |_| \__ \ |
136 # ||____/| .__/ \___/ \___/|_|\___|_| |____/ \__\__,_|\__|\__,_|___/ |
137 # | |_| |
138 # +----------------------------------------------------------------------+
139 # | |
140 # '----------------------------------------------------------------------'
143 def inventory_mknotifyd(parsed):
144 return [(p, {}) for p in parsed]
147 def check_mknotifyd(item, _no_params, parsed):
148 if item not in parsed:
149 yield 2, "No status information, Spooler not running"
150 return
152 now = time.time()
153 stat = parsed[item]
154 version = stat["Version"]
156 # Output Version
157 yield 0, "Version: " + version, []
159 # Check age of status file. It's updated every 20 seconds
160 status_age = now - stat["Updated"]
161 if status_age > 90:
162 state = 2
163 infotext = "Status last updated %s ago, spooler seems crashed or busy" % get_age_human_readable(
164 status_age)
165 else:
166 state = 0
167 infotext = "Spooler running"
168 yield state, infotext, [('last_updated', status_age),
169 ('new_files', stat['spools']['New']['Count'])]
171 # Are there any corrupted files
172 corrupted = stat["spools"]["Corrupted"]
173 if corrupted["Count"]:
174 age = now - corrupted["Youngest"]
175 perf_data = [('corrupted_files', corrupted["Count"])]
176 yield 1, "%d corrupted files: youngest %s ago" % (corrupted["Count"],
177 get_age_human_readable(age)), perf_data
179 # Are there deferred files that are too old?
180 deferred = stat["spools"]["Deferred"]
181 if deferred["Count"]:
182 age = now - deferred["Oldest"]
183 count = deferred["Count"]
184 perf_data = [('deferred_age', age), ('deferred_files', deferred["Count"])]
185 if age > 5:
186 state = 1
187 elif age > 600:
188 state = 2
189 else:
190 state = 0
191 yield state, "%d deferred files: oldest %s ago" % (count,
192 get_age_human_readable(age)), perf_data
194 return
197 check_info["mknotifyd"] = {
198 "parse_function": parse_mknotifyd,
199 "inventory_function": inventory_mknotifyd,
200 "check_function": check_mknotifyd,
201 "has_perfdata": True,
202 "service_description": "OMD %s Notification Spooler",
205 # .--Connections---------------------------------------------------------.
206 # | ____ _ _ |
207 # | / ___|___ _ __ _ __ ___ ___| |_(_) ___ _ __ ___ |
208 # | | | / _ \| '_ \| '_ \ / _ \/ __| __| |/ _ \| '_ \/ __| |
209 # | | |__| (_) | | | | | | | __/ (__| |_| | (_) | | | \__ \ |
210 # | \____\___/|_| |_|_| |_|\___|\___|\__|_|\___/|_| |_|___/ |
211 # | |
212 # '----------------------------------------------------------------------'
215 def inventory_mknotifyd_connection(parsed):
216 for site_name, stats in parsed.items():
217 for connection_name in stats["connections"]:
218 yield site_name + "-" + connection_name, {}
221 def check_mknotifyd_connection(item, _no_params, parsed):
222 states = {
223 "established": (0, "Alive"),
224 "cooldown": (2, "Connection failed or terminated"),
225 "initial": (1, "Initialized"),
226 "connecting": (2, "Trying to connect"),
229 site_name, connection_name = item.split('-', 1)
230 if site_name not in parsed:
231 raise MKCounterWrapped("No status information about spooler available")
233 if connection_name in parsed[site_name]["connections"]:
234 connection = parsed[site_name]["connections"][connection_name]
236 # First check state
237 state, state_name = states[connection["State"]]
238 yield state, state_name
240 if "Status Message" in connection:
241 yield 0, connection["Status Message"]
243 # Show uptime
244 if connection["State"] == "established":
245 now = time.time()
246 age = now - connection["Since"]
247 yield 0, "Uptime: %s" % get_age_human_readable(age)
249 if "Connect Time" in connection:
250 yield 0, "Connect time: %.3f sec" % connection["Connect Time"]
252 # Stats
253 for what in ("Sent", "Received"):
254 num = connection["Notifications " + what]
255 if num:
256 yield 0, "%d Notifications %s" % (num, what.lower())
259 check_info["mknotifyd.connection"] = {
260 "inventory_function": inventory_mknotifyd_connection,
261 "check_function": check_mknotifyd_connection,
262 "service_description": "OMD %s Notify Connection",