Cleanup config.nodes_of
[check_mk.git] / active_checks / check_bi_aggr
blob0110af2b4a42a6981e292a04bf34433e5906e434
1 #!/usr/bin/env 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 import getopt
28 import os
29 import sys
30 import time
31 import traceback
32 import urllib
33 import ast
35 import requests
36 import urllib3 # type: ignore
37 from pathlib2 import Path
39 import cmk.utils.password_store
41 cmk.utils.password_store.replace_passwords()
43 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
45 # tell requests not to honour "http(s)_proxy" env variables
46 proxies = {
47 'http': None,
48 'https': None,
52 def usage():
53 sys.stderr.write("""
54 USAGE: check_bi_aggr -b <BASE_URL> -a <AGGR_NAME> -u <USER> -s <SECRET>
55 [-m <AUTH_MODE>] [-r] [-n <HOSTNAME>] [-t <TIMEOUT>] [-d]
57 OPTIONS:
58 -b BASE_URL The base URL to the monitoring environment, e.g.
59 http://<hostname>/<site-id>
60 -a AGGR_NAME Name of the aggregation, not the aggregation group.
61 It is possible that there are multiple aggregations
62 with an equal name, but you should ensure, that it
63 is a unique one to prevent confusions
64 -u USER User-ID of an automation user which is permitted to
65 see all contents of the aggregation
66 -s SECRET Automation secret of the user
67 --use-automation-user Use credentials from the local "automation" user
68 -m AUTH_MODE Authentication mode, either "cookie", "basic", "digest"
69 or "kerberos", defaults to "cookie"
70 -t TIMEOUT HTTP connect timeout in seconds (Default: 60)
71 -r track downtimes. This requires the hostname to be set.
72 -n HOSTNAME The hostname for which this check is run.
73 --in-downtime S S can be "ok" or "warn". Force this state if the
74 aggregate is in scheduled downtime. OK states will always
75 be unchanged.
76 --acknowledged S Same as --in-downtime, but for acknowledged aggregates.
77 -d Enable debug mode
78 -h, --help Show this help message and exit
80 """)
83 short_options = 'b:a:u:s:m:t:n:dhr'
84 long_options = ["help", "in-downtime=", "acknowledged=", "use-automation-user"]
86 try:
87 opts, args = getopt.getopt(sys.argv[1:], short_options, long_options)
88 except getopt.GetoptError, err:
89 sys.stderr.write("%s\n" % err)
90 sys.exit(1)
92 base_url = None
93 aggr_name = None
95 username = None
96 password = None
97 use_automation_user = False
99 auth_mode = 'cookie'
100 timeout = 60
101 debug = False
102 opt_in_downtime = None
103 opt_acknowledged = None
104 track_downtime = False
105 hostname = None
107 for o, a in opts:
108 if o in ['-h', '--help']:
109 usage()
110 sys.exit(0)
111 elif o == '-b':
112 base_url = a
113 elif o == '-a':
114 aggr_name = a
115 elif o == '-u':
116 username = a
117 elif o == '-s':
118 password = a
119 elif o == '-m':
120 auth_mode = a
121 elif o == '-t':
122 timeout = int(a)
123 elif o == '-r':
124 track_downtime = True
125 elif o == '-n':
126 hostname = a
127 elif o == '-d':
128 debug = True
129 elif o == '--in-downtime':
130 opt_in_downtime = a
131 elif o == '--acknowledged':
132 opt_acknowledged = a
133 elif o == '--use-automation-user':
134 use_automation_user = True
136 if not base_url:
137 sys.stderr.write('Please provide the URL to the monitoring instance.\n')
138 usage()
139 sys.exit(1)
141 if not aggr_name:
142 sys.stderr.write('Please provide the name of the aggregation.\n')
143 usage()
144 sys.exit(1)
146 if use_automation_user:
147 username = "automation"
148 secret_file_path = Path(cmk.utils.paths.var_dir) / "web" / username / "automation.secret"
149 try:
150 with secret_file_path.open(encoding="utf-8") as f: # pylint: disable=no-member
151 password = f.read()
152 except IOError:
153 sys.stderr.write('Unable to read credentials for "automation" user.\n')
154 sys.exit(1)
156 if not username or not password:
157 sys.stderr.write('Please provide valid user credentials.\n')
158 usage()
159 sys.exit(1)
161 if track_downtime and not hostname:
162 sys.stderr.write('Please provide a hostname when using downtime tracking.\n')
163 usage()
164 sys.exit(1)
167 def init_auth():
168 auth_obj = None
169 if username and password:
170 if auth_mode == 'kerberos':
171 from requests_kerberos import HTTPKerberosAuth # type: ignore
173 from subprocess import Popen, PIPE
174 kinit = Popen(["kinit", username], stdin=PIPE, stdout=PIPE, stderr=PIPE)
175 output, errors = kinit.communicate("%s\n" % password)
176 kinit.wait()
177 if kinit.returncode or errors:
178 sys.stderr.write("Error getting Kerberos Ticket:\n")
179 sys.stderr.write(
180 "stdout: %s\nstderr: %s\nrc: %s" % (output, errors, kinit.returncode))
181 sys.exit(1)
183 auth_obj = HTTPKerberosAuth(principal=username)
184 elif auth_mode == 'digest':
185 auth_obj = requests.auth.HTTPDigestAuth(username, password)
186 else:
187 auth_obj = requests.auth.HTTPBasicAuth(username, password)
188 return auth_obj
190 url = "%s/check_mk/view.py" \
191 "?view_name=aggr_single_api" \
192 "&aggr_name=%s&output_format=python" % \
193 (base_url.rstrip('/'), urllib.quote(aggr_name))
195 auth = None
196 if auth_mode in ['basic', 'digest', 'kerberos']:
197 auth = init_auth()
198 else:
199 url += "&_username=%s&_secret=%s" % \
200 (username, password)
202 if debug:
203 sys.stderr.write('URL: %s\n' % url)
205 try:
206 r = requests.get(url, timeout=timeout, auth=auth, proxies=proxies)
207 r.raise_for_status()
208 raw_response = r.text
209 except requests.Timeout:
210 sys.stdout.write('ERROR: Socket timeout while opening URL: %s\n' % (url))
211 sys.exit(3)
212 except requests.URLRequired, e:
213 sys.stdout.write("UNKNOWN: %s\n" % e)
214 sys.exit(3)
215 except Exception, e:
216 sys.stdout.write(
217 'ERROR: Exception while opening URL: %s - %s\n%s' % (url, e, traceback.format_exc()))
218 sys.exit(3)
220 if raw_response.startswith("ERROR:"):
221 sys.stdout.write(raw_response.rstrip() + "\n")
222 sys.exit(3)
224 try:
225 obj = ast.literal_eval(raw_response)
226 except Exception, e:
227 sys.stdout.write('ERROR: Invalid response (%s): %s\n' % (e, raw_response))
228 sys.exit(3)
230 if len(obj) == 1:
231 sys.stdout.write(
232 'ERROR: Aggregation "%s" does not exist or user is not permitted\n' % aggr_name)
233 sys.exit(3)
235 if not isinstance(obj, list):
236 sys.stdout.write('ERROR: Invalid response: %s\n' % (raw_response.replace("\n", "")))
237 sys.exit(3)
239 headers = obj[0]
240 row = dict(zip(headers, obj[1]))
242 aggr_output = row["aggr_output"]
243 aggr_state = int(row["aggr_state_num"])
245 if aggr_state == -1:
246 aggr_state = 3
248 if aggr_output == '':
249 aggr_output = 'Aggregation state is %s' % ['OK', 'WARN', 'CRIT', 'UNKNOWN'][aggr_state]
251 # Handle downtimes and acknowledgements
252 if opt_in_downtime and row["aggr_in_downtime"] == '1':
253 aggr_output += ", currently in downtime"
254 if opt_in_downtime == "ok":
255 aggr_state = 0
256 else: # "warn"
257 aggr_state = min(aggr_state, 1)
259 if track_downtime:
260 # connect to livestatus
261 try:
262 import livestatus
263 except ImportError:
264 sys.stderr.write('The python livestatus api module is missing. Please install from\n'
265 'Check_MK livestatus sources to a python import path.\n')
266 sys.exit(1)
268 socket_path = os.environ['OMD_ROOT'] + '/tmp/run/live'
270 conn = livestatus.SingleSiteConnection('unix:' + socket_path)
272 now = time.time()
273 # find out if, according to previous tracking, there already is a downtime
274 ids = conn.query_table(("GET downtimes\n"
275 "Columns: id\n"
276 "Filter: service_description = Aggr Host %s\n"
277 "Filter: author = tracking\n"
278 "Filter: end_time > %d") % (hostname, now))
279 downtime_tracked = len(ids) > 0
280 if downtime_tracked != (row["aggr_in_downtime"] == '1'):
281 # there is a discrepance between tracked downtime state and the real state
282 if row["aggr_in_downtime"] == '1':
283 # need to track downtime
284 conn.command("[%d] SCHEDULE_SVC_DOWNTIME;%s;Aggr Host %s;%d;%d;1;0;0;"
285 "tracking;Automatic downtime" % (now, hostname, hostname, now, 2147483647))
286 else:
287 for dt_id in ids:
288 conn.command("[%d] DEL_SVC_DOWNTIME;%d" % (now, dt_id[0]))
290 if opt_acknowledged and row["aggr_acknowledged"] == '1':
291 aggr_output += ", is acknowledged"
292 if opt_acknowledged == "ok":
293 aggr_state = 0
294 else: # "warn"
295 aggr_state = min(aggr_state, 1)
297 sys.stdout.write('%s\n' % aggr_output)
298 sys.exit(aggr_state)