root / tools / nagios / check_munin @ master
Historique | Voir | Annoter | Télécharger (4,84 ko)
| 1 | 3c669294 | Andreas Thienemann | #!/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) |
