Refactoring: Changed all check parameters starting with an 'o' to the new rulespec...
[check_mk.git] / checks / services
blob193ed60e88ee5f1f79c60189faaea9556ce105ee
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 # Output of old agent (< 1.1.10i2):
28 # AeLookupSvc running Application Experience Lookup Service
29 # Alerter stopped Alerter
30 # ALG stopped Application Layer Gateway Service
31 # AppMgmt stopped Application Management
32 # appmgr running Remote Server Manager
34 # Output of new agent (>= 1.1.10i2):
35 # Alerter stopped/disabled Warndienst
36 # ALG running/demand Gatewaydienst auf Anwendungsebene
37 # Apple_Mobile_Device running/auto Apple Mobile Device
38 # AppMgmt stopped/demand Anwendungsverwaltung
39 # AudioSrv running/auto Windows Audio
40 # BITS running/demand Intelligenter Hintergrund<FC>bertragungsdienst
41 # Bonjour_Service running/auto Dienst "Bonjour"
43 inventory_services = []
45 # Examples for inventory_services:
46 # inventory_services = [
47 # "HirnTest", # add service, if currently running
48 # "TapiSrv running", # the same
49 # "TermService auto", # add service, if start type is auto (regardless if running)
50 # "BackupSrv running/auto", # add, if start type is auto and it's running
51 # "~Backup.* running/auto", # same, but add all services matching a regex
52 # ( [ "termserver" ] , ALL_HOSTS, [ "HirnTest running", "Sppoller auto" ] ), # same with tags..
53 # ( ALL_HOSTS, [ "!Backup.*", "FooBar auto" ] ),
54 # ]
56 # Implemented in 1.2.1i2:
57 # New rule-style (WATO compatible) notation:
58 # [({'start_mode': 'demand', 'service': ['Netman']}, [], ['@all'], {'docu_url': ''})]
60 # <services> is list of regexes matching the service name
61 # <state> is the expected state to inventorize services of (running, stopped, ...)
62 # <start_mode> is the expected state to inventorize services of (auto, manual, ...)
64 # All above attributes can be set to None or not set to disable this filter option for the entry.
65 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 isinstance(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 isinstance(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 isinstance(entry, str):
157 inventory += add_matching_services(name, description, state, start_type, entry)
158 elif isinstance(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,
181 def check_windows_services(item, params, info):
182 # Hack for old manually defined checks:
183 if params is None:
184 params = factory_settings["services_default_levels"]
186 # A service may appear more than once (due to clusters).
187 # First make a list of all matching entries with their
188 # states
189 found = []
190 for line in info:
191 # allow to match agains the internal name or agains the display name
192 # of the service
193 display_name = " ".join(line[3:])
194 if item == line[1] or item == display_name \
195 or line[1] in params['additional_servicenames'] \
196 or display_name in params['additional_servicenames']:
197 # newer agents also send start type as part of state,
198 # e.g. running/auto
199 if '/' in line[2]:
200 state, start_type = line[2].split('/')
201 else:
202 state = line[2]
203 start_type = "unknown"
204 found.append((line[0], state, start_type, " ".join(line[3:])))
206 if not found:
207 return params["else"], "service not found"
209 # We take the best found state (neccessary for clusters)
210 best_desc, best_state, best_info, best_running_on = None, None, None, None
211 for running_on, state, start_type, desc in found:
212 for t_state, t_start_type, mon_state in params["states"]:
213 if (t_state is None or t_state == state) \
214 and (t_start_type is None or t_start_type == start_type):
215 this_state = mon_state
216 break
217 else:
218 this_state = params["else"]
220 if best_state is None or this_state < best_state:
221 best_state = this_state
222 best_info = state, start_type
223 best_running_on = running_on
224 best_desc = desc
226 infotext = best_desc + ": %s (start type is %s)" % best_info
227 if best_running_on and best_state != 2: #if best state ist critical, there should no message "running on"
228 infotext += " (running on: %s)" % best_running_on
230 return (best_state, infotext)
233 factory_settings["services_default_levels"] = {
234 "states": [("running", None, 0)],
235 "else": 2,
236 "additional_servicenames": [],
239 check_info['services'] = {
240 "check_function": check_windows_services,
241 "inventory_function": inventory_windows_services,
242 "service_description": "Service %s",
243 "node_info": True,
244 "group": "services",
245 "default_levels_variable": "services_default_levels",
248 factory_settings["services_summary_default_levels"] = {"ignored": [], "state_if_stopped": 0}
251 def inventory_services_summary(info):
252 if info[0]:
253 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
306 check_info['services.summary'] = {
307 "check_function": check_services_summary,
308 "inventory_function": inventory_services_summary,
309 "default_levels_variable": "services_summary_default_levels",
310 "service_description": "Services Summary",
311 "node_info": True,
312 "group": "services_summary",