root/check_munin

Revision 10, 4.8 kB (checked in by ixs, 16 years ago)

better error handling

  • Property svn:executable set to *
Line 
1 #!/usr/bin/python
2 #
3 # Copyright (C) 2009 Andreas Thienemann <andreas@bawue.net>
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU Library General Public License as published by
7 # the Free Software Foundation; version 2 only
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU Library General Public License for more details.
13 #
14 # You should have received a copy of the GNU Library General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 #
18
19 #
20 # Nagios script to query a munin host for plugin values
21 #
22 # Can be used as an active check instead of check_dummy
23 #
24
25 import optparse
26 import socket
27 import pprint
28 import sys
29 import re
30
31 parser = optparse.OptionParser("usage: %prog -H <Host> -M <Module> [-P <Port>] -D [<warn>] [<crit>]")
32 parser.add_option("-H", "--host", dest="host", type="string",
33                         help="specify host to poll")
34 parser.add_option("-M", "--module", dest="module", type="string",
35                         help="munin module to poll")
36 parser.add_option("-P", "--port", dest="port", default=4949,
37                         type="int", help="port number to poll")
38 parser.add_option("-D", "--debug", action="store_true", dest="debug", default=False,
39                         help="Debug output")
40
41 (options, args) = parser.parse_args()
42
43 HOST = options.host
44 PORT = options.port
45 MODULE = options.module
46 DEBUG = options.debug
47
48 if HOST == None or MODULE == None:
49         parser.error("options -H and -M are required.")
50
51 def compare(val, thresh):
52         # Compare value to warning and critical threshoulds
53         # Handle different threshold formats: max, :max, min:, min:max
54
55         val = float(val)
56
57         # max
58         match = re.match("^[:]?([-+]?[0-9]+)$", str(thresh))
59         if match:
60                 max = float(match.group(1))
61                 if val > max:
62                         return 3
63
64
65         # min
66         match = re.match("^([-+]?[0-9]+):$", str(thresh))
67         if match:
68                 min = float(match.group(1))
69                 if val < min:
70                         return 2
71
72         # min:max
73         match = re.match("^([-+]?[0-9]+):([-+]?[0-9]+)$", str(thresh))
74         if match:
75                 min, max = float(match.group(1)), float(match.group(2))
76                 if val <  min or val > max:
77                         return 1
78
79         # okay
80         return 0
81
82 def output(l, cat, desc, ret):
83         if len(l[cat]) > 0:
84                 print MODULE, desc + ";"
85                 for line in l["critical"]:
86                         print "CRITICAL: " + line + ";"
87                 for line in l["warning"]:
88                         print "WARNING: " + line + ";"
89                 for line in l["ok"]:
90                         print "OK: " + line + ";"
91                 sys.exit(ret)
92
93 try:
94         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
95         s.connect((HOST, PORT))
96         conn = s.makefile('wb', 0)
97 except:
98         print "Couldn't connect to requested host"
99         sys.exit(3)
100
101
102 if conn.readline().startswith("# munin node at"):
103         conn.writelines("config" + MODULE + "\n")
104         order = []
105         data = {}
106         while True:
107                 line = conn.readline()
108                 if DEBUG:
109                         pprint.pprint(line)
110                 # Last message, bail
111                 if line == ".\n":
112                         break
113
114                 label = ""
115
116                 key, val = line.split(" ", 1)
117                 if key.find(".") is not -1:
118                         label = key.split(".")[0]
119                         if label not in data:
120                                 data[label] = { "warning" : "", "critical" : "", "value" : "" }
121                                 order.append(label)
122                                 # No thresholds passed on the command line
123                                 if len(args) == 2:
124                                         data[label]["warning"] = args[0]
125                                         data[label]["critical"] = args[1]
126
127                 # No thresholds passed on the command line, take the munin supplied ones
128                 if len(args) < 2:
129                         if key.endswith("warning"):
130                                 data[label]["warning"] = val[:-1]
131                         if key.endswith("critical"):
132                                 data[label]["critical"] = val[:-1]
133
134         if data[label]["warning"] == "" or data[label]["critical"] == "":
135                 print "UNKNOWN - Couldn't retrieve thresholds, pass some on the command line"
136                 sys.exit(3)
137
138
139         conn.writelines("fetch " + MODULE + "\n")
140         while True:
141                 line = conn.readline()
142                 # Last line, bail
143                 if line == ".\n":
144                         if DEBUG:
145                                 pprint.pprint(data)
146                         break
147
148                 key, val = line.split(" ", 1)
149                 label = key.split(".")[0]
150                 if key.endswith("value"):
151                         data[label]["value"] = val[:-1]
152
153         conn.writelines("quit\n")
154
155 else:
156         print "UNKNOWN - No munin node detected"
157         sys.exit(3)
158
159 conn.close()
160 s.close()
161
162 l = { "ok" : [], "warning" : [], "critical" : [] }
163 for entry in order:
164         # compare actual data: 3 max exceeded, 2 minimum underrun, 1 outside limit, 0 okay
165         for tresh in ["critical", "warning"]:
166                 val = data[entry]["value"]
167                 tval = data[entry][tresh]
168                 tmp = ""
169                 if compare(val, tval) == 3:
170                         tmp = entry + ": " + val + " has exceeded the maximum threshold of " + tval
171                         break
172                 elif compare(val, tval) == 2:
173                         tmp = entry + ": " + val + " has underrun the minimum threshold of " + tval
174                         break
175                 elif compare(val, tval) == 1:
176                         tmp = entry + ": " + val + " is outside of range " + tval
177                         break
178
179         if tmp != "":
180                 l[tresh].append(tmp)
181         else:
182                 l["ok"].append(entry + ": " + val + " is okay")
183
184
185 output(l, "critical", "CRITICAL", 2)
186 output(l, "warning", "WARNING", 1)
187 output(l, "ok", "OK", 0)
Note: See TracBrowser for help on using the browser.