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 # <<<mknotifyd:sep(0)>>>
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)
46 # Oldest: 1425305956 (2015-03-02 15:19:16, 83797 sec ago)
48 # Connection: 127.0.0.1:46906
51 # Since: 1425389490 (2015-03-03 14:31:30, 263 sec ago)
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
):
62 if line
[0].startswith('['):
69 sub_entry
= site_entry
70 parsed
[site
] = site_entry
72 varname
, value
= line
[0].split(":", 1)
75 if varname
== "Spool":
77 site_entry
["spools"][value
] = sub_entry
79 elif varname
== "Connection":
81 site_entry
["connections"][value
] = sub_entry
83 elif varname
== "Queue":
85 site_entry
["queues"][value
] = sub_entry
90 elif value
and varname
== "Listening FD":
91 # May be the listening FD number or an error message
93 value
= int(value
.split()[0])
96 elif value
and varname
not in [
101 "Pending Acknowledgements",
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]
125 for nr
, connection
in enumerate(connections
):
126 stats
["connections"][address
+ "/" + str(nr
+ 1)] = connection
131 # .--Spooler Status------------------------------------------------------.
132 # | ____ _ ____ _ _ |
133 # |/ ___| _ __ ___ ___ | | ___ _ __ / ___|| |_ __ _| |_ _ _ ___ |
134 # |\___ \| '_ \ / _ \ / _ \| |/ _ \ '__| \___ \| __/ _` | __| | | / __| |
135 # | ___) | |_) | (_) | (_) | | __/ | ___) | || (_| | |_| |_| \__ \ |
136 # ||____/| .__/ \___/ \___/|_|\___|_| |____/ \__\__,_|\__|\__,_|___/ |
138 # +----------------------------------------------------------------------+
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"
151 # There are dummy-entries created during the parsing. So the
152 # dict will never be completely empty. We check for Version
153 # because this should be always present in a valid state file.
154 elif not parsed
[item
].get("Version"):
155 yield 2, "The state file seems to be empty. It is very likely that the spooler is not working properly"
160 version
= stat
["Version"]
163 yield 0, "Version: " + version
, []
165 # Check age of status file. It's updated every 20 seconds
166 status_age
= now
- stat
["Updated"]
169 infotext
= "Status last updated %s ago, spooler seems crashed or busy" % get_age_human_readable(
173 infotext
= "Spooler running"
174 yield state
, infotext
, [('last_updated', status_age
),
175 ('new_files', stat
['spools']['New']['Count'])]
177 # Are there any corrupted files
178 corrupted
= stat
["spools"]["Corrupted"]
179 if corrupted
["Count"]:
180 age
= now
- corrupted
["Youngest"]
181 perf_data
= [('corrupted_files', corrupted
["Count"])]
182 yield 1, "%d corrupted files: youngest %s ago" % (corrupted
["Count"],
183 get_age_human_readable(age
)), perf_data
185 # Are there deferred files that are too old?
186 deferred
= stat
["spools"]["Deferred"]
187 if deferred
["Count"]:
188 age
= now
- deferred
["Oldest"]
189 count
= deferred
["Count"]
190 perf_data
= [('deferred_age', age
), ('deferred_files', deferred
["Count"])]
197 yield state
, "%d deferred files: oldest %s ago" % (count
,
198 get_age_human_readable(age
)), perf_data
203 check_info
["mknotifyd"] = {
204 "parse_function": parse_mknotifyd
,
205 "inventory_function": inventory_mknotifyd
,
206 "check_function": check_mknotifyd
,
207 "has_perfdata": True,
208 "service_description": "OMD %s Notification Spooler",
211 # .--Connections---------------------------------------------------------.
213 # | / ___|___ _ __ _ __ ___ ___| |_(_) ___ _ __ ___ |
214 # | | | / _ \| '_ \| '_ \ / _ \/ __| __| |/ _ \| '_ \/ __| |
215 # | | |__| (_) | | | | | | | __/ (__| |_| | (_) | | | \__ \ |
216 # | \____\___/|_| |_|_| |_|\___|\___|\__|_|\___/|_| |_|___/ |
218 # '----------------------------------------------------------------------'
221 def inventory_mknotifyd_connection(parsed
):
222 for site_name
, stats
in parsed
.items():
223 for connection_name
in stats
["connections"]:
224 yield site_name
+ "-" + connection_name
, {}
227 def check_mknotifyd_connection(item
, _no_params
, parsed
):
229 "established": (0, "Alive"),
230 "cooldown": (2, "Connection failed or terminated"),
231 "initial": (1, "Initialized"),
232 "connecting": (2, "Trying to connect"),
235 site_name
, connection_name
= item
.split('-', 1)
236 if site_name
not in parsed
:
237 raise MKCounterWrapped("No status information about spooler available")
239 if connection_name
in parsed
[site_name
]["connections"]:
240 connection
= parsed
[site_name
]["connections"][connection_name
]
243 state
, state_name
= states
[connection
["State"]]
244 yield state
, state_name
246 if "Status Message" in connection
:
247 yield 0, connection
["Status Message"]
250 if connection
["State"] == "established":
252 age
= now
- connection
["Since"]
253 yield 0, "Uptime: %s" % get_age_human_readable(age
)
255 if "Connect Time" in connection
:
256 yield 0, "Connect time: %.3f sec" % connection
["Connect Time"]
259 for what
in ("Sent", "Received"):
260 num
= connection
["Notifications " + what
]
262 yield 0, "%d Notifications %s" % (num
, what
.lower())
265 check_info
["mknotifyd.connection"] = {
266 "inventory_function": inventory_mknotifyd_connection
,
267 "check_function": check_mknotifyd_connection
,
268 "service_description": "OMD %s Notify Connection",