Refactored snapin server_time to new snapin API
[check_mk.git] / checks / mknotifyd
blob924462ff5d6d7ede59a44f508317c69d19154e0b
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), ('new_files', stat['spools']['New']['Count'])]
170 # Are there any corrupted files
171 corrupted = stat["spools"]["Corrupted"]
172 if corrupted["Count"]:
173 age = now - corrupted["Youngest"]
174 perf_data = [('corrupted_files', corrupted["Count"])]
175 yield 1, "%d corrupted files: youngest %s ago" % (corrupted["Count"],
176 get_age_human_readable(age)), perf_data
178 # Are there deferred files that are too old?
179 deferred = stat["spools"]["Deferred"]
180 if deferred["Count"]:
181 age = now - deferred["Oldest"]
182 count = deferred["Count"]
183 perf_data = [('deferred_age', age), ('deferred_files', deferred["Count"])]
184 if age > 5:
185 state = 1
186 elif age > 600:
187 state = 2
188 else:
189 state = 0
190 yield state, "%d deferred files: oldest %s ago" % (count,
191 get_age_human_readable(age)), perf_data
193 return
196 check_info["mknotifyd"] = {
197 "parse_function": parse_mknotifyd,
198 "inventory_function": inventory_mknotifyd,
199 "check_function": check_mknotifyd,
200 "has_perfdata": True,
201 "service_description": "OMD %s Notification Spooler",
204 # .--Connections---------------------------------------------------------.
205 # | ____ _ _ |
206 # | / ___|___ _ __ _ __ ___ ___| |_(_) ___ _ __ ___ |
207 # | | | / _ \| '_ \| '_ \ / _ \/ __| __| |/ _ \| '_ \/ __| |
208 # | | |__| (_) | | | | | | | __/ (__| |_| | (_) | | | \__ \ |
209 # | \____\___/|_| |_|_| |_|\___|\___|\__|_|\___/|_| |_|___/ |
210 # | |
211 # '----------------------------------------------------------------------'
214 def inventory_mknotifyd_connection(parsed):
215 for site_name, stats in parsed.items():
216 for connection_name in stats["connections"]:
217 yield site_name + "-" + connection_name, {}
220 def check_mknotifyd_connection(item, _no_params, parsed):
221 states = {
222 "established": (0, "Alive"),
223 "cooldown": (2, "Connection failed or terminated"),
224 "initial": (1, "Initialized"),
225 "connecting": (2, "Trying to connect"),
228 site_name, connection_name = item.split('-', 1)
229 if site_name not in parsed:
230 raise MKCounterWrapped("No status information about spooler available")
232 if connection_name in parsed[site_name]["connections"]:
233 connection = parsed[site_name]["connections"][connection_name]
235 # First check state
236 state, state_name = states[connection["State"]]
237 yield state, state_name
239 if "Status Message" in connection:
240 yield 0, connection["Status Message"]
242 # Show uptime
243 if connection["State"] == "established":
244 now = time.time()
245 age = now - connection["Since"]
246 yield 0, "Uptime: %s" % get_age_human_readable(age)
248 if "Connect Time" in connection:
249 yield 0, "Connect time: %.3f sec" % connection["Connect Time"]
251 # Stats
252 for what in ("Sent", "Received"):
253 num = connection["Notifications " + what]
254 if num:
255 yield 0, "%d Notifications %s" % (num, what.lower())
258 check_info["mknotifyd.connection"] = {
259 "inventory_function": inventory_mknotifyd_connection,
260 "check_function": check_mknotifyd_connection,
261 "service_description": "OMD %s Notify Connection",