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 |
def compare(val, thresh): |
---|
49 |
# Compare value to warning and critical threshoulds |
---|
50 |
# Handle different threshold formats: max, :max, min:, min:max |
---|
51 |
|
---|
52 |
val = float(val) |
---|
53 |
|
---|
54 |
# max |
---|
55 |
match = re.match("^[:]?([-+]?[0-9]+)$", str(thresh)) |
---|
56 |
if match: |
---|
57 |
max = float(match.group(1)) |
---|
58 |
if val > max: |
---|
59 |
return 3 |
---|
60 |
|
---|
61 |
|
---|
62 |
# min |
---|
63 |
match = re.match("^([-+]?[0-9]+):$", str(thresh)) |
---|
64 |
if match: |
---|
65 |
min = float(match.group(1)) |
---|
66 |
if val < min: |
---|
67 |
return 2 |
---|
68 |
|
---|
69 |
# min:max |
---|
70 |
match = re.match("^([-+]?[0-9]+):([-+]?[0-9]+)$", str(thresh)) |
---|
71 |
if match: |
---|
72 |
min, max = float(match.group(1)), float(match.group(2)) |
---|
73 |
if val < min or val > max: |
---|
74 |
return 1 |
---|
75 |
|
---|
76 |
# okay |
---|
77 |
return 0 |
---|
78 |
|
---|
79 |
def output(l, cat, desc, ret): |
---|
80 |
if len(l[cat]) > 0: |
---|
81 |
print MODULE, desc + ";" |
---|
82 |
for line in l["critical"]: |
---|
83 |
print "CRITICAL: " + line + ";" |
---|
84 |
for line in l["warning"]: |
---|
85 |
print "WARNING: " + line + ";" |
---|
86 |
for line in l["ok"]: |
---|
87 |
print "OK: " + line + ";" |
---|
88 |
sys.exit(ret) |
---|
89 |
|
---|
90 |
try: |
---|
91 |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
---|
92 |
s.connect((HOST, PORT)) |
---|
93 |
conn = s.makefile('wb', 0) |
---|
94 |
except: |
---|
95 |
print "Couldn't connect to requested host" |
---|
96 |
sys.exit(3) |
---|
97 |
|
---|
98 |
|
---|
99 |
if conn.readline().startswith("# munin node at"): |
---|
100 |
conn.writelines("config" + MODULE + "\n") |
---|
101 |
order = [] |
---|
102 |
data = {} |
---|
103 |
while True: |
---|
104 |
line = conn.readline() |
---|
105 |
if DEBUG: |
---|
106 |
pprint.pprint(line) |
---|
107 |
# Last message, bail |
---|
108 |
if line == ".\n": |
---|
109 |
break |
---|
110 |
|
---|
111 |
label = "" |
---|
112 |
|
---|
113 |
key, val = line.split(" ", 1) |
---|
114 |
if key.find(".") is not -1: |
---|
115 |
label = key.split(".")[0] |
---|
116 |
if label not in data: |
---|
117 |
data[label] = { "warning" : "", "critical" : "", "value" : "" } |
---|
118 |
order.append(label) |
---|
119 |
# No thresholds passed on the command line |
---|
120 |
if len(args) == 2: |
---|
121 |
data[label]["warning"] = args[0] |
---|
122 |
data[label]["critical"] = args[1] |
---|
123 |
|
---|
124 |
# No thresholds passed on the command line, take the munin supplied ones |
---|
125 |
if len(args) < 2: |
---|
126 |
if key.endswith("warning"): |
---|
127 |
data[label]["warning"] = val[:-1] |
---|
128 |
if key.endswith("critical"): |
---|
129 |
data[label]["critical"] = val[:-1] |
---|
130 |
|
---|
131 |
if data[label]["warning"] == "" or data[label]["critical"] == "": |
---|
132 |
print "UNKNOWN - Couldn't retrieve thresholds, pass some on the command line" |
---|
133 |
sys.exit(3) |
---|
134 |
|
---|
135 |
|
---|
136 |
conn.writelines("fetch " + MODULE + "\n") |
---|
137 |
while True: |
---|
138 |
line = conn.readline() |
---|
139 |
# Last line, bail |
---|
140 |
if line == ".\n": |
---|
141 |
if DEBUG: |
---|
142 |
pprint.pprint(data) |
---|
143 |
break |
---|
144 |
|
---|
145 |
key, val = line.split(" ", 1) |
---|
146 |
label = key.split(".")[0] |
---|
147 |
if key.endswith("value"): |
---|
148 |
data[label]["value"] = val[:-1] |
---|
149 |
|
---|
150 |
conn.writelines("quit\n") |
---|
151 |
|
---|
152 |
else: |
---|
153 |
print "UNKNOWN - No munin node detected" |
---|
154 |
sys.exit(3) |
---|
155 |
|
---|
156 |
conn.close() |
---|
157 |
s.close() |
---|
158 |
|
---|
159 |
l = { "ok" : [], "warning" : [], "critical" : [] } |
---|
160 |
for entry in order: |
---|
161 |
# compare actual data: 3 max exceeded, 2 minimum underrun, 1 outside limit, 0 okay |
---|
162 |
for tresh in ["critical", "warning"]: |
---|
163 |
val = data[entry]["value"] |
---|
164 |
tval = data[entry][tresh] |
---|
165 |
tmp = "" |
---|
166 |
if compare(val, tval) == 3: |
---|
167 |
tmp = entry + ": " + val + " has exceeded the maximum threshold of " + tval |
---|
168 |
break |
---|
169 |
elif compare(val, tval) == 2: |
---|
170 |
tmp = entry + ": " + val + " has underrun the minimum threshold of " + tval |
---|
171 |
break |
---|
172 |
elif compare(val, tval) == 1: |
---|
173 |
tmp = entry + ": " + val + " is outside of range " + tval |
---|
174 |
break |
---|
175 |
|
---|
176 |
if tmp != "": |
---|
177 |
l[tresh].append(tmp) |
---|
178 |
else: |
---|
179 |
l["ok"].append(entry + ": " + val + " is okay") |
---|
180 |
|
---|
181 |
|
---|
182 |
output(l, "critical", "CRITICAL", 2) |
---|
183 |
output(l, "warning", "WARNING", 1) |
---|
184 |
output(l, "ok", "OK", 0) |
---|