Index: /sd_speed =================================================================== --- /sd_speed (revision 1) +++ /sd_speed (revision 1) @@ -0,0 +1,140 @@ +#!/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. +# + +# +# Munin Plugin to get storage device throughput for Bacula by parsing the bconsole +# output. +# +# Parameters: +# +# config (required) +# autoconf (optional - only used by munin-config) +# + +# Magic markers (optional - only used by munin-config and some +# installation scripts): +# +#%# family=contrib +#%# capabilities=autoconf + +import subprocess +import time +import sys +import re +import os + +def parse_devices(): + """ Parse the bconsole output once to get the device names """ + + bconsole = subprocess.Popen("bconsole", stdin=subprocess.PIPE, stdout=subprocess.PIPE) + stdout, stderr = bconsole.communicate("status\n2") + + devs = [] + + # Hold the line numbers for devices + dev_line = [] + input = stdout.split("\n") + + for line, i in zip(input, range(0, len(input))): + if line.startswith("Connecting to Storage daemon "): + hostname = line.split()[-1].split(":")[0] + if line.startswith("Device \""): + dev_line.append(i) + + for pos in dev_line: + # Get the device name + dev_name = input[pos].split()[1][1:-1] + dev_dev = input[pos].split()[2][1:-1] + dev_dev_clean = re.sub("^[^A-Za-z_]", "_", dev_dev, 1) + dev_dev_clean = re.sub("[^A-Za-z0-9_]", "_", dev_dev_clean, 0) + devs.append([dev_name, dev_dev, dev_dev_clean]) + + return hostname, devs + + +def parse(): + """ Parse the bconsole output """ + + bconsole = subprocess.Popen("bconsole", stdin=subprocess.PIPE, stdout=subprocess.PIPE) + stdout, stderr = bconsole.communicate("status\n2") + + devstats = [] + + # Hold the line numbers for devices + dev_line = [] + input = stdout.split("\n") + + for line, i in zip(input, range(0, len(input))): + if line.startswith("Device \""): + dev_line.append(i) + + for pos in dev_line: + # Get the device name + dev_dev = input[pos].split()[2][1:-1] + dev_dev_clean = re.sub("^[^A-Za-z_]", "_", dev_dev, 1) + dev_dev_clean = re.sub("[^A-Za-z0-9_]", "_", dev_dev_clean, 0) + + # Get the current bytes + if input[pos].endswith("is mounted with:"): + bytes = long(input[pos+5].split()[1].split("=")[1].replace(",", "")) + devstats.append([dev_dev, dev_dev_clean, bytes]) + else: + devstats.append([dev_dev, dev_dev_clean, 0]) + + return devstats + + +def print_config(): + hostname, devstats = parse_devices() + print "graph_title Bacula Storage Daemon throughput" + print "graph_vlabel bytes per ${graph_period}" + print "graph_args --base 1024 -l 0" + print "graph_scale yes" + print "graph_info Bacula Storage Daemon througput measurement based on written bytes. This may be somewhat inacurate whenever a tape is changed." + print "graph_category Bacula" + print "graph_order", + for dev in devstats: + print dev[2], + print + if os.getenv("report_hostname") is not None and \ + os.getenv("report_hostname").upper() in ["YES", "TRUE", "1", "Y"]: + print "host_name", hostname + for dev in devstats: + print "%s.label %s" % (dev[2], dev[1]) + print "%s.type DERIVE" % (dev[2]) + print "%s.min 0" % (dev[2]) +# print "%s.max %s" % (dev[2], str(1024*1024*1024*16)) +# print "%s.cdef up,8,*" (dev[2]) + sys.exit(0) + + +if "config" in sys.argv[1:]: + print_config() +elif "autoconf" in sys.argv[1:]: + for dir in os.getenv("PATH").split(":"): + for root, dirs, files in os.walk(dir): + if "bconsole" in files: + print "yes" + sys.exit(0) + print "no" + sys.exit(1) +elif "suggest" in sys.argv[1:]: + sys.exit(1) +else: + for dev in parse(): + print "%s.value %s" % (dev[1], dev[2]) Index: /cyrus-imapd =================================================================== --- /cyrus-imapd (revision 18) +++ /cyrus-imapd (revision 1) @@ -1,7 +1,5 @@ #!/bin/sh -# -# $Id$ -# -# Copyright (C) 2009-2011 Andreas Thienemann + +# Copyright (C) 2009 Andreas Thienemann # # This program is free software; you can redistribute it and/or modify @@ -19,52 +17,19 @@ # -: <<=cut - -=head1 NAME - -cyrus-imapd - Munin plugin to monitor the load on a cyrus imapd server - -=head1 CONFIGURATION - -The user running this plugin needs read and write access to the -cyrus-imapd proc directory. You will need to add the following to the -munin-node/plugin configuration: - - [cyrus-imapd] - user root - -=head1 INTERPRETATION - -This plugin should be pretty self explanatory. - -It displays the following three datapoints: - - - Total number of open connections (both in authenticated and - non-authenticated state) - - Number of authenticated sessions - - Number of unique users - -=head1 MAGIC MARKERS - - #%# family=contrib - #%# capabilities=autoconf - -=head1 VERSION - - $Revision$ - -=head1 BUGS - -None known. If you find any, please put in a ticket at . - -=head1 AUTHOR - -Andreas Thienemann - -=head1 LICENSE - -GPLv2 - -=cut +# +# Plugin to monitor the load on a cyrus imapd server +# +# Usage: Link or copy into the munin-node plugin directory +# +# Installation node: Should most likely run as root: +# [cyrus-imapd] +# user root +# +# +# Magic markers (optional - only used by munin-config and some +# installation scripts): +# +#%# family=contrib +#%# capabilities=autoconf # IMAP Configuration Directory @@ -76,5 +41,5 @@ echo yes else - echo "no (no cyrus-imapd procdir found)" + echo no fi exit 0 @@ -82,5 +47,5 @@ # Check if we actually got some sensible data -if [ "x${CONFIGDIR}x" = "xx" ]; then +if [ "x${CONFIGDIR}x" == "xx" ]; then exit 1 fi @@ -96,5 +61,5 @@ echo 'graph_category cyrus' echo 'graph_info Current connections to the imap server. bawue.net e.V. Trac repository.' - echo 'graph_order connections authenticated_users unique_users' + echo 'graph_oder connections authenticated_users unique_users' echo 'connections.label Connections' echo 'connections.info Number of connections to the imap server.' @@ -109,20 +74,14 @@ fi -cons=$(ls ${PROCDIR} | wc -l) +# Print the number of connections to the imap server +echo -n "connections.value " +ls ${PROCDIR} | wc -l -if [ $cons -gt 0 ]; then - # Print the number of connections to the imap server - echo "connections.value $cons" +# Read the proc files and get the logged in users +echo -n "authenticated_users.value " +awk '{ split(substr($0, match($0, "]")+1), a); if (a[1] != "") print a[1] }' ${PROCDIR}/* | wc -l - # Read the proc files and get the logged in users - echo -n "authenticated_users.value " - awk '{ split(substr($0, match($0, "]")+1), a); if (a[1] != "") print a[1] }' ${PROCDIR}/* | wc -l +# Read the proc files and get the number of unique users +echo -n "unique_users.value " +awk '{ split(substr($0, match($0, "]")+1), a); if (a[1] != "") print a[1] }' ${PROCDIR}/* | sort -u | wc -l - # Read the proc files and get the number of unique users - echo -n "unique_users.value " - awk '{ split(substr($0, match($0, "]")+1), a); if (a[1] != "") print a[1] }' ${PROCDIR}/* | sort -u | wc -l -else - echo "connections.value 0" - echo "authenticated_users.value 0" - echo "unique_users.value 0" -fi Index: /eeipmi_ =================================================================== --- /freeipmi_ (revision 16) +++ (revision ) @@ -1,226 +1,0 @@ -#!/usr/bin/python -# -# Copyright (C) 2011 Andreas Thienemann -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -""" -=head1 NAME - -freeipmi_ - Munin plugin to retreive temperature and fan speed measurements -from a local machine via IPMI. - -=head1 APPLICABLE SYSTEMS - -All machines with an IPMI capable baseboard management controller. - -=head1 CONFIGURATION - -On most supported systems this plugin works nearly out of the box as long as -both Python and the freeipmi binaries in a semi-recent version are installed. - -If the machine works out of the box can be tested by calling bmc-info. -If there's text output, a bmc card was detected. If there's an entry for -"Sensor Device" visible in the "Additional Device Support" entry you're good. - -If you get a "ipmi_cmd_get_device_id: driver timeout" message you have most -likely no bmc to query. - -In certain cases however bmc-info will just seem to hang for quite some time. -In this case, autodetection does not work because the smbios table has -incorrect information. One system know to experience this problem is the -HP Proliant Microserver. - -Adding env.freeipmi_args "--no-probing --driver-type=KCS --driver-address=0xca2 --register-spacing=1" -to the munin plugin configuration will make the plugin work. - -Basic configuration for every system is that the plugin needs to be called as root. - -Add the following to your /etc/munin/plugin-conf.d/freeipmi: - - [freeipmi_*] - user root - -=head1 INTERPRETATION - -The plugin shows the temperature in Celsius or the fanspeed in rotations per minute. - -=head1 MAGIC MARKERS - - #%# family=contrib - #%# capabilities=autoconf suggest - -=head1 VERSION - -0.0.1 - -=head1 BUGS - -Only local support for now. Remote could be hacked in via freeipmi_args for now. - -=head1 AUTHOR - -Andreas Thienemann - -=head1 LICENSE - -GPLv3+ - -=cut -""" - -import subprocess -import sys -import os -import re -import pprint - -# Parse some environment variables -if os.getenv("freeipmi_args") is not None: - freeipmi_args = " %s" % (os.getenv("freeipmi_args")) -else: - freeipmi_args = "" - -# We are a wildcard plugin, figure out whether we are called for temp or fan -if sys.argv[0].split("_")[1] == "temp": - mode = "Temperature" -elif sys.argv[0].split("_")[1] == "fan": - mode = "Fan" -else: - mode = None - -def whereis(prog): - """Check if prog can be found in the path and if yes, return the full pathname""" - prog = os.path.basename(prog) - for dir in os.getenv("PATH").split(":"): - for root, dirs, files in os.walk(dir): - if prog in files: - return os.path.join(dir, prog) - return None - -def normalize_sensor(name): - name = name.lower().replace("-","M").replace("+","P") - name = re.sub("[^a-z0-9A-Z]","_", name) - return name - -# Code sniplet from Philipp Keller -# http://code.pui.ch/2007/02/19/set-timeout-for-a-shell-command-in-python/ -def timeout_command(command, timeout): - """call shell-command and either return its output or kill it - if it doesn't normally exit within timeout seconds and return None""" - import subprocess, datetime, os, time, signal - start = datetime.datetime.now() - process = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) - while process.poll() is None: - time.sleep(0.1) - now = datetime.datetime.now() - if (now - start).seconds> timeout: - os.kill(process.pid, signal.SIGKILL) - os.waitpid(-1, os.WNOHANG) - return None - return process.stdout.read() - -def bmc_detect(): - """Check whether there's a baseboard management controller we can query.""" - if whereis("bmc-info") is None: - print "no (bmc-info not found in path. Please install FreeIPMI.)" - sys.exit(0) - else: - out = timeout_command("bmc-info%s" % (freeipmi_args), 2) - if out is not None and "[Sensor Device]" in out: - print "yes" - sys.exit(0) - else: - print "no (no supported bmc found)" - sys.exit(0) - -def read_sensors(): - """Return all sensor data as a dict""" - out = timeout_command("ipmi-sensors --verbose%s" % (freeipmi_args), 2) - sensors = dict() - sensor = dict() - sensor_id = None - for line in out.split("\n"): - if ":" in line: - k,v = line.split(": ") - if k == "Record ID": - sensor = dict() - sensor_id = int(v) - sensor[k] = v - else: - sensor[k] = v - else: - sensors[sensor_id] = sensor - return sensors - -def print_config(): - """Return configuration arguments for munin""" - print "graph_title FreeIPMI Sensors: %s" % (mode) - if mode == "Fan": - print "graph_vlabel RPM" - print "graph_info This graph shows the RPMs of the fans as reported by IPMI" - elif mode == "Temperature": - print "graph_vlabel Degrees C" - print "graph_info This graph shows the temperatures as reported by IPMI" - print "graph_category sensors" - sensors = read_sensors() - - for id in sorted(sensors): - if sensors[id]["Group Name"] == mode: - label = normalize_sensor(sensors[id]["Sensor Name"]) - for n in ["Normal Max.", "Normal Min.", "Sensor Reading", "Lower Critical Threshold", "Upper Critical Threshold", "Lower Non-Critical Threshold", "Upper Non-Critical Threshold"]: - sensors[id][n] = sensors[id][n].replace("NA","") - sensors[id][n] = sensors[id][n].split('.')[0] - - print "%s.label %s" % (label, label) - print "%s.warning %s:%s" % (label, sensors[id]["Lower Non-Critical Threshold"], sensors[id]["Upper Non-Critical Threshold"]) - print "%s.critical %s:%s" % (label, sensors[id]["Lower Critical Threshold"], sensors[id]["Upper Critical Threshold"]) - print "%s.graph_args --base 1000 -l 0" % (label) - print "%s.graph_scale no" % (label) -# pprint.pprint(sensors[id]) - sys.exit(0) - -def fetch(): - sensors = read_sensors() - - for id in sorted(sensors): - if sensors[id]["Group Name"] == mode: - label = normalize_sensor(sensors[id]["Sensor Name"]) - print "%s.value %s" % (label, sensors[id]["Sensor Reading"].split(".")[0]) - sys.exit(0) - - -if "config" in sys.argv[1:]: - print_config() - -elif "autoconf" in sys.argv[1:]: - bmc_detect() - -elif "suggest" in sys.argv[1:]: - sensors = read_sensors() - fan, temperature = [0, 0] - for id in sensors: - if sensors[id]["Group Name"] == "Fan": - fan += 1 - elif sensors[id]["Group Name"] == "Temperature": - temperature += 1 - if fan > 0: - print "fan" - if temperature > 0: - print "temp" - sys.exit(0) - -else: - fetch() Index: /cula_job =================================================================== --- /bacula_job (revision 5) +++ (revision ) @@ -1,166 +1,0 @@ -#!/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. -# - -# -# Munin Plugin to get job throughput for Bacula by parsing the bconsole -# output. -# -# Parameters: -# -# config (required) -# autoconf (optional - only used by munin-config) -# - -# Magic markers (optional - only used by munin-config and some -# installation scripts): -# -#%# family=contrib -#%# capabilities=autoconf - -import subprocess -import time -import sys -import re -import os - -def parse_running_jobs(): - """ Parse the bconsole output once to get the running jobs """ - - bconsole = subprocess.Popen("bconsole", stdin=subprocess.PIPE, stdout=subprocess.PIPE) - stdout, stderr = bconsole.communicate("status\n1\nstatus\n3\n.") - - jobs = [] - clients = [] - clientlist = False - - # Hold the line numbers for devices - dev_line = [] - input = stdout.split("\n") - - for line, i in zip(input, range(0, len(input))): - if line.startswith("Connecting to Director "): - hostname = line.split()[-1].split(":")[0] - - if line.endswith(" is running"): - jobs.append(line.split()[2].split(".")[0]) - - # Parse the clientlist, warning, order of statements is important - if line.startswith("Select Client (File daemon) resource"): - clientlist = False - - if clientlist is True: - client_id, client_name = line.split() - client_clean = re.sub("^[^A-Za-z_]", "_", client_name, 1) - client_clean = re.sub("[^A-Za-z0-9_]", "_", client_clean, 0) - clients.append((client_name, client_clean, client_id[:-1])) - - if line.startswith("The defined Client resources are:"): - clientlist = True - - return hostname, jobs, clients - - -def parse(clients): - """ Parse the bconsole output """ - - query_str = "" - for client in clients: - query_str = query_str + "status\n3\n" + client[1] + "\n" - query_str = query_str + "quit" - - bconsole = subprocess.Popen("bconsole", stdin=subprocess.PIPE, stdout=subprocess.PIPE) - stdout, stderr = bconsole.communicate(query_str) - - input = stdout.split("\n") - - jobstats = [] - - for line, pos in zip(input, range(0, len(input))): - - # Get the client name - if line.startswith("Connecting to Client "): - # client_name = input[pos].split()[3].split(".")[0] - client_name = line.split()[3] - client_clean = re.sub("^[^A-Za-z_]", "_", client_name, 1) - client_clean = re.sub("[^A-Za-z0-9_]", "_", client_clean, 0) - - # Get the current bytes - if line.endswith(" is running."): - bytes = long(input[pos+2].split()[1].split("=")[1].replace(",", "")) - jobstats.append([client_name, client_clean, bytes]) - - job_dict = {} - for job in jobstats: - job_dict[job[0].split("-")[0]] = job - - return job_dict - - -def print_config(): - hostname, jobs, clients = parse_running_jobs() - print "graph_title Bacula Job throughput" - print "graph_vlabel bytes per ${graph_period}" - print "graph_args --base 1024 -l 0" - print "graph_scale yes" - print "graph_info Bacula Job measurement." - print "graph_category Bacula" - print "graph_order", - for fd in clients: - print fd[1], - print - if os.getenv("report_hostname") is not None and \ - os.getenv("report_hostname").upper() in ["YES", "TRUE", "1", "Y"]: - print "host_name", hostname - for client in clients: - print "%s.label %s" % (client[1], client[0]) - print "%s.type DERIVE" % (client[1]) - print "%s.min 0" % (client[1]) -# print "%s.max %s" % (client[1], str(1024*1024*1024*16)) -# print "%s.cdef up,8,*" (client[1]) - sys.exit(0) - - -if "config" in sys.argv[1:]: - print_config() -elif "autoconf" in sys.argv[1:]: - for dir in os.getenv("PATH").split(":"): - for root, dirs, files in os.walk(dir): - if "bconsole" in files: - print "yes" - sys.exit(0) - print "no" - sys.exit(1) -elif "suggest" in sys.argv[1:]: - sys.exit(1) -else: - hostname, jobs, clients = parse_running_jobs() - str = [] - for client in clients: - if client[0].split("-")[0] in jobs: - str.append((client[0], client[2])) - - client_values = parse(str) - - for client in clients: - client_name_short = client[0].split("-")[0] - if client_name_short in client_values: - print "%s.value %s" % (client_values[client_name_short][1], client_values[client_name_short][2]) - else: - print "%s.value %s" % (client[1], "0") - - sys.exit(0) Index: /stools_ =================================================================== --- /smstools_ (revision 4) +++ (revision ) @@ -1,147 +1,0 @@ -#!/bin/bash - -# 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. -# - -# -# Plugin to monitor an smstools installation -# -# Usage: Link or copy into the munin-node plugin directory, name it according -# to your SMS Modem as known to smsd. e.g. smstools_GSM1 -# -# -# Installation: -# -# SMSD: -# Configure smsd to output his statistics by adding the following to /etc/smsd.conf: -# -# stats = /var/log/smsd_stats -# stats_interval = 300 -# -# -# Munin: -# If your statistics directory is non-standard, configure it as -# statsdir in the munin-plugin configuration -# In case you do not want your statistics-dump from smsd deleted after reading, -# set env.cleanup to false. If you want cleanup to work, run the plugin as root. -# -# [smstools*] -# user root -# env.statsdir /var/log/smsd_stats -# env.cleanup true -# -# -# Magic markers (optional - only used by munin-config and some -# installation scripts): -# -#%# family=contrib -#%# capabilities=autoconf suggest -# - -STATSDIR=${statsdir:-/var/log/smsd_stats} -CLEANUP=${cleanup:-false} -MODEM=`basename $0 | sed 's/^smstools_//g'` - -if [ "$1" = "autoconf" ]; then - if [ -d $STATSDIR ]; then - echo yes - exit 0 - else - echo "no ($STATSDIR not found)" - exit 1 - fi -fi - -if [ "$1" = "suggest" ]; then - if [ -d $STATSDIR ]; then - # Find the newest statistics file - FILE=$(ls -rt ${STATSDIR}/[0-9]*.[0-9]* | tail -n 1) - - awk ' - FS="," { - if (NR > 4) { - print $1 - } - } - ' < $FILE - exit 0 - else - exit 1 - fi -fi - - -# If run with the "config"-parameter, give out information on how the -# graphs should look. - -if [ "$1" = "config" ]; then - echo 'graph_title SMSTools Report for '${MODEM} - echo 'graph_args --base 1000 -l 0' - echo 'graph_vlabel ' - echo 'graph_scale no' - echo 'graph_category SMSTools' - echo 'graph_info SMSTools Statistics' - echo 'graph_oder succeeded received failed multiple_failed rejected' - echo 'rejected.label Rejected' - echo 'rejected.info Number of rejected SMS' - echo 'succeeded.label Succeeded' - echo 'succeeded.info Number of sucessfully sent SMS' - echo 'failed.label Failed' - echo 'failed.info Number of failed SMS' - echo 'received.label Received' - echo 'received.info Number of received SMS' - echo 'multiple_failed.label Consecutive failures' - echo 'multiple_failed.info Number of consecutive failures' -# echo 'usage_s.label Time sent' -# echo 'usage_s.info Modem time sending' -# echo 'usage_r.label Time sent' -# echo 'usage_r.info Modem time receiving' - - # Last, if run with the "config"-parameter, quit here (don't - # display any data) - exit 0 -fi - -# Find the newest statistics file -FILE=$(ls -rt ${STATSDIR}/[0-9]*.[0-9]* | tail -n 1) - -awk ' -FS="," { - if (NR == 2) - a[0] = "rejected.value " $2 - - if (NR > 4 && $1 == "'$MODEM'") { - a[1] = "succeeded.value " $2 - a[2] = "failed.value " $3 - a[3] = "received.value " $4 - a[4] = "multiple_failed.value " $5 - a[5] = "usage_s.value " $6 - a[6] = "usage_r.value " $7 - } - - # Did we actually get more then just the rejected.value line? - # Then we must have parsed the right modem, output everything - if (1 in a) { - for (i = 0; i < 7; i++) { - print a[i] - } - } -} -' < $FILE - -if [ ${CLEANUP} == "true" ]; then - rm -f $FILE -fi Index: /eck_munin =================================================================== --- /check_munin (revision 10) +++ (revision ) @@ -1,187 +1,0 @@ -#!/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) Index: /mp__areca_ =================================================================== --- /snmp__areca_ (revision 11) +++ (revision ) @@ -1,241 +1,0 @@ -#!/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. -# - -# -# Munin Plugin to get Temperature, Voltage or Fanspeed from Areca Controllers -# via SNMP. -# -# Parameters: -# -# config (required) -# autoconf (optional - only used by munin-config) -# - -# Magic markers (optional - only used by munin-config and some -# installation scripts): - -import pprint -import time -import sys -import re -import os -from pysnmp import v1, v2c, role, asn1 - -request_conf = { - "volt" : { - "label" : "Voltages", - "vlabel" : "Volt", - "graph" : "--base 1000 --logarithmic", - "oid" : ".1.3.6.1.4.1.18928.1.2.2.1.8" - }, - "fan" : { - "label" : "Fans", - "vlabel" : "RPM", - "graph" : "--base 1000 -l 0", - "oid" : ".1.3.6.1.4.1.18928.1.2.2.1.9" - }, - "temp" : { - "label" : "Temperatures", - "vlabel" : "Celsius", - "graph" : "--base 1000 -l 0", - "oid" : ".1.3.6.1.4.1.18928.1.2.2.1.10" - } -} - -# Sanity check and parsing of the commandline -host = None -port = 161 -request = None -try: - match = re.search("^(?:|.*\/)snmp_([^_]+)_areca_(.+)$", sys.argv[0]) - host = match.group(1) - request = match.group(2) - match = re.search("^([^:]+):(\d+)$", host) - if match is not None: - host = match.group(1) - port = match.group(2) -except: - pass - -if host is None or request is None: - print "# Error: Incorrect filename. Cannot parse host or request." - sys.exit(1) - -# Parse env variables -if os.getenv("community") is not None: - community = os.getenv("community") -else: - community = "public" -if os.getenv("version") is not None: - version = os.getenv("version") -else: - version = "1" - - -def get_data(): - # Fetch the data - results = snmpwalk(request_conf[request]["oid"]) - - # parse data - vals = [] - for i in range(0, len(results)): - idx, res = results[i][0].split(request_conf[request]["oid"])[1].split(".")[1:], results[i][1] - if idx[1] == '1': - vals.append([]) - vals[int(idx[2])-1].append(res) - if idx[1] == '2': - vals[int(idx[2])-1].append(res) - if idx[1] == '3': - if request == "volt": - res = float(res)/1000 - vals[int(idx[2])-1].append(res) - - return vals - -def snmpwalk(root): - - # Create SNMP manager object - client = role.manager((host, port)) - - # Create a SNMP request&response objects from protocol version - # specific module. - try: - req = eval('v' + version).GETREQUEST() - nextReq = eval('v' + version).GETNEXTREQUEST() - rsp = eval('v' + version).GETRESPONSE() - - except (NameError, AttributeError): - print '# Unsupported SNMP protocol version: %s\n%s' % (version, usage) - sys.exit(-1) - - # Store tables headers - head_oids = [root] - - encoded_oids = map(asn1.OBJECTID().encode, head_oids) - - result = []; - - while 1: - - # Encode OIDs, encode SNMP request message and try to send - # it to SNMP agent and receive a response - (answer, src) = client.send_and_receive(req.encode(community=community, encoded_oids=encoded_oids)) - - # Decode SNMP response - rsp.decode(answer) - - # Make sure response matches request (request IDs, communities, etc) - if req != rsp: - raise 'Unmatched response: %s vs %s' % (str(req), str(rsp)) - - # Decode BER encoded Object IDs. - oids = map(lambda x: x[0], map(asn1.OBJECTID().decode, rsp['encoded_oids'])) - - # Decode BER encoded values associated with Object IDs. - vals = map(lambda x: x[0](), map(asn1.decode, rsp['encoded_vals'])) - - # Check for remote SNMP agent failure - if rsp['error_status']: - # SNMP agent reports 'no such name' when walk is over - if rsp['error_status'] == 2: - # Switch over to GETNEXT req on error - # XXX what if one of multiple vars fails? - if not (req is nextReq): - req = nextReq - continue - # One of the tables exceeded - for l in oids, vals, head_oids: - del l[rsp['error_index']-1] - else: - raise 'SNMP error #' + str(rsp['error_status']) + ' for OID #' + str(rsp['error_index']) - - # Exclude completed OIDs - while 1: - for idx in range(len(head_oids)): - if not asn1.OBJECTID(head_oids[idx]).isaprefix(oids[idx]): - # One of the tables exceeded - for l in oids, vals, head_oids: - del l[idx] - break - else: - break - - if not head_oids: - return result - - # Print out results - for (oid, val) in map(None, oids, vals): - result.append((oid, str(val))) - # print oid + ' ---> ' + str(val) - - # BER encode next SNMP Object IDs to query - encoded_oids = map(asn1.OBJECTID().encode, oids) - - # Update request object - req['request_id'] = req['request_id'] + 1 - - # Switch over GETNEXT PDU for if not done - if not (req is nextReq): - req = nextReq - - raise "error" - - -def print_config(): - print "graph_title " + request_conf[request]["label"] - print "graph_vlabel " + request_conf[request]["vlabel"] - print "graph_args " + request_conf[request]["graph"] - print "graph_category sensors" - print "host_name", host - for dataset in get_data(): - if request == "volt": - if dataset[1] == "Battery Status": - continue - else: - print request + dataset[0] + ".label", dataset[1] - ref_val = float(dataset[1].split()[-1][:-1]) - print request + dataset[0] + ".warning", str(ref_val * 0.95) + ":" + str(ref_val * 1.05) - print request + dataset[0] + ".critical", str(ref_val * 0.80) + ":" + str(ref_val * 1.20) - if request == "temp": - print request + dataset[0] + ".label", dataset[1] - if dataset[1].startswith("CPU"): - print request + dataset[0] + ".warning", 55 - print request + dataset[0] + ".critical", 60 - if dataset[1].startswith("System"): - print request + dataset[0] + ".warning", 40 - print request + dataset[0] + ".critical", 45 - if request == "fan": - print request + dataset[0] + ".label", dataset[1] - print request + dataset[0] + ".warning", 2400 - print request + dataset[0] + ".critical", 2000 - - sys.exit(0) - - -if "config" in sys.argv[1:]: - print_config() -elif "snmpconf" in sys.argv[1:]: - print "require 1.3.6.1.4.1.18928.1.2.2.1.8.1.1" - sys.exit(0) -else: - for dataset in get_data(): - # Filter Battery Status (255 == Not installed) - if request == "volt" and dataset[1] == "Battery Status": - continue - print request + dataset[0] + ".value", dataset[2] - sys.exit(0) Index: /cula_sd =================================================================== --- /bacula_sd (revision 2) +++ (revision ) @@ -1,140 +1,0 @@ -#!/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. -# - -# -# Munin Plugin to get storage device throughput for Bacula by parsing the bconsole -# output. -# -# Parameters: -# -# config (required) -# autoconf (optional - only used by munin-config) -# - -# Magic markers (optional - only used by munin-config and some -# installation scripts): -# -#%# family=contrib -#%# capabilities=autoconf - -import subprocess -import time -import sys -import re -import os - -def parse_devices(): - """ Parse the bconsole output once to get the device names """ - - bconsole = subprocess.Popen("bconsole", stdin=subprocess.PIPE, stdout=subprocess.PIPE) - stdout, stderr = bconsole.communicate("status\n2") - - devs = [] - - # Hold the line numbers for devices - dev_line = [] - input = stdout.split("\n") - - for line, i in zip(input, range(0, len(input))): - if line.startswith("Connecting to Storage daemon "): - hostname = line.split()[-1].split(":")[0] - if line.startswith("Device \""): - dev_line.append(i) - - for pos in dev_line: - # Get the device name - dev_name = input[pos].split()[1][1:-1] - dev_dev = input[pos].split()[2][1:-1] - dev_dev_clean = re.sub("^[^A-Za-z_]", "_", dev_dev, 1) - dev_dev_clean = re.sub("[^A-Za-z0-9_]", "_", dev_dev_clean, 0) - devs.append([dev_name, dev_dev, dev_dev_clean]) - - return hostname, devs - - -def parse(): - """ Parse the bconsole output """ - - bconsole = subprocess.Popen("bconsole", stdin=subprocess.PIPE, stdout=subprocess.PIPE) - stdout, stderr = bconsole.communicate("status\n2") - - devstats = [] - - # Hold the line numbers for devices - dev_line = [] - input = stdout.split("\n") - - for line, i in zip(input, range(0, len(input))): - if line.startswith("Device \""): - dev_line.append(i) - - for pos in dev_line: - # Get the device name - dev_dev = input[pos].split()[2][1:-1] - dev_dev_clean = re.sub("^[^A-Za-z_]", "_", dev_dev, 1) - dev_dev_clean = re.sub("[^A-Za-z0-9_]", "_", dev_dev_clean, 0) - - # Get the current bytes - if input[pos].endswith("is mounted with:"): - bytes = long(input[pos+5].split()[1].split("=")[1].replace(",", "")) - devstats.append([dev_dev, dev_dev_clean, bytes]) - else: - devstats.append([dev_dev, dev_dev_clean, 0]) - - return devstats - - -def print_config(): - hostname, devstats = parse_devices() - print "graph_title Bacula Storage Daemon throughput" - print "graph_vlabel bytes per ${graph_period}" - print "graph_args --base 1024 -l 0" - print "graph_scale yes" - print "graph_info Bacula Storage Daemon througput measurement based on written bytes. This may be somewhat inacurate whenever a tape is changed." - print "graph_category Bacula" - print "graph_order", - for dev in devstats: - print dev[2], - print - if os.getenv("report_hostname") is not None and \ - os.getenv("report_hostname").upper() in ["YES", "TRUE", "1", "Y"]: - print "host_name", hostname - for dev in devstats: - print "%s.label %s" % (dev[2], dev[1]) - print "%s.type DERIVE" % (dev[2]) - print "%s.min 0" % (dev[2]) -# print "%s.max %s" % (dev[2], str(1024*1024*1024*16)) -# print "%s.cdef up,8,*" (dev[2]) - sys.exit(0) - - -if "config" in sys.argv[1:]: - print_config() -elif "autoconf" in sys.argv[1:]: - for dir in os.getenv("PATH").split(":"): - for root, dirs, files in os.walk(dir): - if "bconsole" in files: - print "yes" - sys.exit(0) - print "no" - sys.exit(1) -elif "suggest" in sys.argv[1:]: - sys.exit(1) -else: - for dev in parse(): - print "%s.value %s" % (dev[1], dev[2]) Index: /mp__cyclades_pm_ =================================================================== --- /snmp__cyclades_pm_ (revision 19) +++ (revision ) @@ -1,157 +1,0 @@ -#!/usr/bin/perl -w -# -*- cperl -*- -# -# Copyright (C) 2012 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. -# - -=head1 NAME - -snmp__cyclades_pm_ - Munin plugin to retrive readings from a Cyclades -Power Managemen Distribution Unit connected to a Cyclades console server. - -=head1 APPLICABLE SYSTEMS - -Avocent/Cyclades PMXX connected to a SNMP enabled Cyclades ACS/TS. - -=head1 CONFIGURATION - -As a rule SNMP plugins need site specific configuration. The default -configuration (shown here) will only work on insecure sites/devices. - - [snmp_*] - env.version 2 - env.community public - -In general SNMP is not very secure at all unless you use SNMP version -3 which supports authentication and privacy (encryption). But in any -case the community string for your devices should not be "public". - -Please see 'perldoc Munin::Plugin::SNMP' for further configuration -information. - -=head1 INTERPRETATION - -The plugin reports the current fan speed readings as reported by the thecusIO -module. - -=head1 MIB INFORMATION - -Private MIB - -=head1 MAGIC MARKERS - - #%# family=snmpauto - #%# capabilities=snmpconf - -=head1 VERSION - - 0.0.20120307 - -=head1 BUGS - -None known. - -=head1 AUTHOR - -Copyright (C) 2012 Andreas Thienemann - -=head1 LICENSE - -GPLv2 or (at your option) any later version. - -=cut - -use strict; -use Munin::Plugin; -use Munin::Plugin::SNMP; - -my $DEBUG = $ENV{'MUNIN_DEBUG'}; - -my ($session, $type, $title, $vlabel, $info, $oid, $format); - -sub get_pdu_ports { - my $result = $session->get_entries( - -columns => ['1.3.6.1.4.1.2925.4.5.5.1.1'] - ); - - return sort(values %$result); -} - -sub get_pdu_id { - my ($port) = @_; - my $result = $session->get_single("1.3.6.1.4.1.2925.4.5.3.1.11.$port.1"); - return $result; -} - -if (defined $ARGV[0] and $ARGV[0] eq "snmpconf") { - print "number 1.3.6.1.4.1.2925.4.5.1\n"; - exit 0; -} - -$session = Munin::Plugin::SNMP->session(); - -my ($host,undef,$version,$tail) = Munin::Plugin::SNMP->config_session(); - -($type) = ($tail =~ /cyclades_pm_(.*)$/); - -if ($type =~ "volt") { - $title = "Voltage"; - $vlabel = "Volt"; - $info = "actual value of voltage in the element (V). When element does not have voltage sensor, it returns 0."; - $oid = "1.3.6.1.4.1.2925.4.5.5.1.7"; - $format = "%i"; -} elsif ($type =~ "current") { - $title = "Current"; - $vlabel = "Ampere"; - $info = "actual value of current in the element (A)."; - $oid = "1.3.6.1.4.1.2925.4.5.5.1.3"; - $format = "%.2f"; -} elsif ($type =~ "power") { - $title = "Power"; - $vlabel = "Watt"; - $info = "actual value of power in the element (W)."; - $oid = "1.3.6.1.4.1.2925.4.5.5.1.5"; - $format = "%i"; -} else { - print "Couldn't get type from $tail\n"; - exit 1; -} - - -if ($ARGV[0] and $ARGV[0] eq "config") { - my ($host,undef,$version,$tail) = Munin::Plugin::SNMP->config_session(); - - print "host_name $host\n" unless $host eq 'localhost'; - - print "graph_title Cyclades PM $title\n"; - print "graph_args --base 1000 -l 0\n"; - print "graph_vlabel $vlabel\n"; - print "graph_info This graph shows the $info\n"; - print "graph_category Sensors\n"; - - foreach my $port (get_pdu_ports()) { - my $id = get_pdu_id($port); - print lc($id) . ".label $id\n"; - } - - exit(0); -} - -foreach my $port (get_pdu_ports()) { - my $id = get_pdu_id($port); - my $val = $session->get_single("$oid.$port.1") || "U"; - printf ("%s.value $format\n", lc($id), ($val / 10)); -}