Refactored snapin server_time to new snapin API
[check_mk.git] / checks / services
blobbf2f852e10b2a91ad34acfcada230b0c621642e1
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.
28 # Output of old agent (< 1.1.10i2):
29 # AeLookupSvc running Application Experience Lookup Service
30 # Alerter stopped Alerter
31 # ALG stopped Application Layer Gateway Service
32 # AppMgmt stopped Application Management
33 # appmgr running Remote Server Manager
35 # Output of new agent (>= 1.1.10i2):
36 # Alerter stopped/disabled Warndienst
37 # ALG running/demand Gatewaydienst auf Anwendungsebene
38 # Apple_Mobile_Device running/auto Apple Mobile Device
39 # AppMgmt stopped/demand Anwendungsverwaltung
40 # AudioSrv running/auto Windows Audio
41 # BITS running/demand Intelligenter Hintergrund<FC>bertragungsdienst
42 # Bonjour_Service running/auto Dienst "Bonjour"
44 inventory_services = []
46 # Examples for inventory_services:
47 # inventory_services = [
48 # "HirnTest", # add service, if currently running
49 # "TapiSrv running", # the same
50 # "TermService auto", # add service, if start type is auto (regardless if running)
51 # "BackupSrv running/auto", # add, if start type is auto and it's running
52 # "~Backup.* running/auto", # same, but add all services matching a regex
53 # ( [ "termserver" ] , ALL_HOSTS, [ "HirnTest running", "Sppoller auto" ] ), # same with tags..
54 # ( ALL_HOSTS, [ "!Backup.*", "FooBar auto" ] ),
55 # ]
57 # Implemented in 1.2.1i2:
58 # New rule-style (WATO compatible) notation:
59 # [({'start_mode': 'demand', 'service': ['Netman']}, [], ['@all'], {'docu_url': ''})]
61 # <services> is list of regexes matching the service name
62 # <state> is the expected state to inventorize services of (running, stopped, ...)
63 # <start_mode> is the expected state to inventorize services of (auto, manual, ...)
65 # All above attributes can be set to None or not set to disable this filter option for the entry.
66 inventory_services_rules = []
68 def inventory_windows_services(info):
69 # Handle single entries (type str)
70 def add_matching_services(name, description, state, start_type, entry):
71 if type(entry) == tuple:
72 # New wato rule handling
73 svc = entry[0]
74 statespec = entry[1:]
76 elif ' ' in entry and len(entry.split()) == 2:
77 svc, statespec = entry.split()
79 else:
80 svc = entry
81 statespec = "running"
83 # First match name or description (optional since rule based config option available)
84 if svc:
85 if svc.startswith("~"):
86 r = regex(svc[1:])
87 if not r.match(name) and not r.match(description):
88 return []
89 elif svc != name and svc != description:
90 return []
92 if type(statespec) == tuple:
93 # New wato rule handling (always given as tuple of two)
94 if (statespec[0] and statespec[0] != state) \
95 or (statespec[1] and statespec[1] != start_type):
96 return []
98 else:
99 for n in statespec.split("/"):
100 if n not in [ state, start_type ]:
101 return []
103 return [(name, {})]
105 # Handle entries like ( [ "term" ], ALL_HOSTS, [ "FooBar auto", ".*TEST running" ] )
106 def add_services_with_tags(name, description, state, start_type, entry):
107 matching = []
108 if len(entry) == 2:
109 entry = ( [], ) + entry
110 taglist, hostlist, svclist = entry
111 if hosttags_match_taglist(tags_of_host(host_name()), taglist):
112 if in_extraconf_hostlist(hostlist, host_name()):
113 for svc in svclist:
114 matching += add_matching_services(name, description, state, start_type, svc)
115 return matching
117 # Filter WATO compatible rules by tags/hostlist
118 rules = []
119 for rule in inventory_services_rules:
120 if len(rule) >= 4:
121 options = rule[3]
122 if options.get("disabled"):
123 continue
125 # 1. Get all rules matching the current host
126 taglist, hostlist = rule[1:3]
127 if not hosttags_match_taglist(tags_of_host(host_name()), taglist) \
128 or not in_extraconf_hostlist(hostlist, host_name()):
129 continue
131 # 2. Now extract the list of service regexes
132 value = rule[0]
133 svcs = value.get('services', [])
134 state = value.get('state', None)
135 start_mode = value.get('start_mode', None)
136 if svcs:
137 for svc in svcs:
138 rules.append(('~' + svc, state, start_mode))
139 else:
140 rules.append((None, state, start_mode))
142 inventory = []
143 for line in info:
144 name = line[1]
145 description = " ".join(line[3:])
146 if '/' in line[2]:
147 state, start_type = line[2].split('/')
148 else:
149 state = line[2]
150 start_type = "unknown"
153 # Handle "old" inventory_services notation
155 for entry in inventory_services:
156 if type(entry) == str:
157 inventory += add_matching_services(name, description, state, start_type, entry)
158 elif type(entry) == tuple:
159 inventory += add_services_with_tags(name, description, state, start_type, entry)
160 else:
161 raise MKGeneralException("Invalid entry %r in inventory_services" % entry)
164 # New WATO compatible rule matching
167 for rule in rules:
168 inventory += add_matching_services(name, description, state, start_type, rule)
170 return inventory
173 # Format of parameters
175 # "states" : [ ( "running", "demand", 1 ),
176 # ( "stopped", None, 2 ) ],
177 # "else" : 2,
180 def check_windows_services(item, params, info):
181 # Hack for old manually defined checks:
182 if params is None:
183 params = factory_settings["services_default_levels"]
185 # A service may appear more than once (due to clusters).
186 # First make a list of all matching entries with their
187 # states
188 found = []
189 for line in info:
190 # allow to match agains the internal name or agains the display name
191 # of the service
192 display_name = " ".join(line[3:])
193 if item == line[1] or item == display_name \
194 or line[1] in params['additional_servicenames'] \
195 or display_name in params['additional_servicenames']:
196 # newer agents also send start type as part of state,
197 # e.g. running/auto
198 if '/' in line[2]:
199 state, start_type = line[2].split('/')
200 else:
201 state = line[2]
202 start_type = "unknown"
203 found.append((line[0], state, start_type, " ".join(line[3:])))
205 if not found:
206 return params["else"], "service not found"
208 # We take the best found state (neccessary for clusters)
209 best_desc, best_state, best_info, best_running_on = None, None, None, None
210 for running_on, state, start_type, desc in found:
211 for t_state, t_start_type, mon_state in params["states"]:
212 if (t_state is None or t_state == state) \
213 and (t_start_type is None or t_start_type == start_type):
214 this_state = mon_state
215 break
216 else:
217 this_state = params["else"]
219 if best_state is None or this_state < best_state:
220 best_state = this_state
221 best_info = state, start_type
222 best_running_on = running_on
223 best_desc = desc
225 infotext = best_desc + ": %s (start type is %s)" % best_info
226 if best_running_on and best_state != 2: #if best state ist critical, there should no message "running on"
227 infotext += " (running on: %s)" % best_running_on
229 return (best_state, infotext)
232 factory_settings["services_default_levels"] = {
233 "states" : [ ( "running", None, 0 ) ],
234 "else" : 2,
235 "additional_servicenames" : [],
238 check_info['services'] = {
239 "check_function" : check_windows_services,
240 "inventory_function" : inventory_windows_services,
241 "service_description" : "Service %s",
242 "node_info" : True,
243 "group" : "services",
244 "default_levels_variable" : "services_default_levels",
247 factory_settings["services_summary_default_levels"] = {
248 "ignored": [],
249 "state_if_stopped": 0
252 def inventory_services_summary(info):
253 if info[0]:
254 return [ (None, "services_summary_default_levels") ]
256 def check_services_summary(item, params, info):
257 blacklist = params.get("ignored", () )
258 stoplist = []
259 num_blacklist = 0
260 num_auto = 0
261 for line in info:
262 # newer agents also send start type as part of state,
263 # e.g. running/auto
264 if '/' in line[2]:
265 startstop, auto = line[2].split('/')
266 else:
267 startstop = line[2]
268 auto = "unknown"
269 srv_name = line[1]
270 if auto == "auto":
271 num_auto += 1
272 if startstop == "stopped":
273 match = False
274 for srv in blacklist:
275 if re.match(srv,srv_name):
276 match = True
277 if match is False:
278 stoplist.append(srv_name)
279 else:
280 num_blacklist += 1
282 num_stoplist = len(stoplist)
283 num_srv = len(info)
285 if len(stoplist) > 0:
286 stopped_srvs = " ("+", ".join(stoplist)+")"
287 state = params.get("state_if_stopped")
288 if state == 1:
289 sym = "(!)"
290 elif state == 2:
291 sym="(!!)"
292 else:
293 sym = ""
294 else:
295 stopped_srvs = ""
296 state = 0
297 sym = ""
300 infotext = "%d services, %d services in autostart - of which %d services are stopped%s%s, %d services stopped but ignored" % \
301 ( num_srv, num_auto, num_stoplist, sym, stopped_srvs, num_blacklist )
303 return state, infotext
305 check_info['services.summary'] = {
306 "check_function" : check_services_summary,
307 "inventory_function" : inventory_services_summary,
308 "default_levels_variable" : "services_summary_default_levels",
309 "service_description" : "Services Summary",
310 "node_info" : True,
311 "group" : "services_summary",