#!/usr/bin/python # # Copyright (C) 2009 Andreas Thienemann # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Library General Public License as published by # the Free Software Foundation; version 2 only # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU Library General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # # Nagios script to query a munin host for plugin values # # Can be used as an active check instead of check_dummy # import optparse import socket import pprint import sys import re parser = optparse.OptionParser("usage: %prog -H -M [-P ] -D [] []") parser.add_option("-H", "--host", dest="host", type="string", help="specify host to poll") parser.add_option("-M", "--module", dest="module", type="string", help="munin module to poll") parser.add_option("-P", "--port", dest="port", default=4949, type="int", help="port number to poll") parser.add_option("-D", "--debug", action="store_true", dest="debug", default=False, help="Debug output") (options, args) = parser.parse_args() HOST = options.host PORT = options.port MODULE = options.module DEBUG = options.debug if HOST == None or MODULE == None: parser.error("options -H and -M are required.") def compare(val, thresh): # Compare value to warning and critical threshoulds # Handle different threshold formats: max, :max, min:, min:max val = float(val) # max match = re.match("^[:]?([-+]?[0-9]+)$", str(thresh)) if match: max = float(match.group(1)) if val > max: return 3 # min match = re.match("^([-+]?[0-9]+):$", str(thresh)) if match: min = float(match.group(1)) if val < min: return 2 # min:max match = re.match("^([-+]?[0-9]+):([-+]?[0-9]+)$", str(thresh)) if match: min, max = float(match.group(1)), float(match.group(2)) if val < min or val > max: return 1 # okay return 0 def output(l, cat, desc, ret): if len(l[cat]) > 0: print MODULE, desc + ";" for line in l["critical"]: print "CRITICAL: " + line + ";" for line in l["warning"]: print "WARNING: " + line + ";" for line in l["ok"]: print "OK: " + line + ";" sys.exit(ret) try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) conn = s.makefile('wb', 0) except: print "Couldn't connect to requested host" sys.exit(3) if conn.readline().startswith("# munin node at"): conn.writelines("config" + MODULE + "\n") order = [] data = {} while True: line = conn.readline() if DEBUG: pprint.pprint(line) # Last message, bail if line == ".\n": break label = "" key, val = line.split(" ", 1) if key.find(".") is not -1: label = key.split(".")[0] if label not in data: data[label] = { "warning" : "", "critical" : "", "value" : "" } order.append(label) # No thresholds passed on the command line if len(args) == 2: data[label]["warning"] = args[0] data[label]["critical"] = args[1] # No thresholds passed on the command line, take the munin supplied ones if len(args) < 2: if key.endswith("warning"): data[label]["warning"] = val[:-1] if key.endswith("critical"): data[label]["critical"] = val[:-1] if data[label]["warning"] == "" or data[label]["critical"] == "": print "UNKNOWN - Couldn't retrieve thresholds, pass some on the command line" sys.exit(3) conn.writelines("fetch " + MODULE + "\n") while True: line = conn.readline() # Last line, bail if line == ".\n": if DEBUG: pprint.pprint(data) break key, val = line.split(" ", 1) label = key.split(".")[0] if key.endswith("value"): data[label]["value"] = val[:-1] conn.writelines("quit\n") else: print "UNKNOWN - No munin node detected" sys.exit(3) conn.close() s.close() l = { "ok" : [], "warning" : [], "critical" : [] } for entry in order: # compare actual data: 3 max exceeded, 2 minimum underrun, 1 outside limit, 0 okay for tresh in ["critical", "warning"]: val = data[entry]["value"] tval = data[entry][tresh] tmp = "" if compare(val, tval) == 3: tmp = entry + ": " + val + " has exceeded the maximum threshold of " + tval break elif compare(val, tval) == 2: tmp = entry + ": " + val + " has underrun the minimum threshold of " + tval break elif compare(val, tval) == 1: tmp = entry + ": " + val + " is outside of range " + tval break if tmp != "": l[tresh].append(tmp) else: l["ok"].append(entry + ": " + val + " is okay") output(l, "critical", "CRITICAL", 2) output(l, "warning", "WARNING", 1) output(l, "ok", "OK", 0)