mirror of
https://github.com/munin-monitoring/contrib.git
synced 2018-11-08 00:59:34 +01:00
commit
8f3f79c81c
@ -1,8 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# $Id: cyrus-imapd 18 2011-07-15 09:14:04Z ixs $
|
# Copyright (C) 2009 - 2012 Andreas Thienemann <andreas@bawue.net>
|
||||||
#
|
|
||||||
# Copyright (C) 2009-2011 Andreas Thienemann <andreas@bawue.net>
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU Library General Public License as published by
|
||||||
@ -51,7 +49,7 @@ It displays the following three datapoints:
|
|||||||
|
|
||||||
=head1 VERSION
|
=head1 VERSION
|
||||||
|
|
||||||
$Revision: 18 $
|
0.0.20120307
|
||||||
|
|
||||||
=head1 BUGS
|
=head1 BUGS
|
||||||
|
|
||||||
@ -71,7 +69,7 @@ GPLv2
|
|||||||
CONFIGDIR=$(awk -F : '/^configdirectory:/ { gsub(/ /, "", $2); print $2 }' /etc/imapd.conf 2> /dev/null)
|
CONFIGDIR=$(awk -F : '/^configdirectory:/ { gsub(/ /, "", $2); print $2 }' /etc/imapd.conf 2> /dev/null)
|
||||||
PROCDIR="${CONFIGDIR}/proc"
|
PROCDIR="${CONFIGDIR}/proc"
|
||||||
|
|
||||||
if [ "$1" = "autoconf" ]; then
|
if [ "$1" == "autoconf" ]; then
|
||||||
if [ "x${CONFIGDIR}x" != "xx" ] && [ -d ${PROCDIR} ]; then
|
if [ "x${CONFIGDIR}x" != "xx" ] && [ -d ${PROCDIR} ]; then
|
||||||
echo yes
|
echo yes
|
||||||
else
|
else
|
||||||
@ -81,14 +79,14 @@ if [ "$1" = "autoconf" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if we actually got some sensible data
|
# Check if we actually got some sensible data
|
||||||
if [ "x${CONFIGDIR}x" = "xx" ]; then
|
if [ "x${CONFIGDIR}x" == "xx" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If run with the "config"-parameter, give out information on how the
|
# If run with the "config"-parameter, give out information on how the
|
||||||
# graphs should look.
|
# graphs should look.
|
||||||
|
|
||||||
if [ "$1" = "config" ]; then
|
if [ "$1" == "config" ]; then
|
||||||
echo 'graph_title Cyrus IMAPd Load'
|
echo 'graph_title Cyrus IMAPd Load'
|
||||||
echo 'graph_args --base 1000 -l 0'
|
echo 'graph_args --base 1000 -l 0'
|
||||||
echo 'graph_vlabel connections'
|
echo 'graph_vlabel connections'
|
||||||
|
145
plugins/disk/smart_raw__
Executable file
145
plugins/disk/smart_raw__
Executable file
@ -0,0 +1,145 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Copyright (C) 2011 Andreas Thienemann <andreas@bawue.net>
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
smart_raw__ - Munin plugin to retreive raw SMART values from a disk.
|
||||||
|
|
||||||
|
=head1 APPLICABLE SYSTEMS
|
||||||
|
|
||||||
|
All machines with a SMART capable disk and smartmontools installed.
|
||||||
|
|
||||||
|
This plugin is very useful if you want to need to monitor a single raw S.M.A.R.T.
|
||||||
|
value reported by a disk. Load Cycle Counts or Pending Sectors come to mind as
|
||||||
|
these are a good indicator of problems with a disk.
|
||||||
|
|
||||||
|
=head1 CONFIGURATION
|
||||||
|
|
||||||
|
The plugin should be installed as smart_raw_sda_193 which means that the smart value
|
||||||
|
numbered 193 will be read from the disk sda.
|
||||||
|
|
||||||
|
|
||||||
|
Basic configuration for every system is that the plugin needs to be called as root
|
||||||
|
in order to execute smartmontools.
|
||||||
|
|
||||||
|
Add the following to your /etc/munin/plugin-conf.d/smart_raw:
|
||||||
|
|
||||||
|
[smart_raw_sda_193]
|
||||||
|
user root
|
||||||
|
|
||||||
|
=head1 INTERPRETATION
|
||||||
|
|
||||||
|
Smart RAW values are provided as is. You need to undertand what you are monitoring...
|
||||||
|
|
||||||
|
=head1 MAGIC MARKERS
|
||||||
|
|
||||||
|
#%# family=contrib
|
||||||
|
#%# capabilities=
|
||||||
|
|
||||||
|
=head1 VERSION
|
||||||
|
|
||||||
|
0.0.1
|
||||||
|
|
||||||
|
=head1 BUGS
|
||||||
|
|
||||||
|
None known.
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Andreas Thienemann <andreas@bawue.net>
|
||||||
|
|
||||||
|
=head1 LICENSE
|
||||||
|
|
||||||
|
GPLv3+
|
||||||
|
|
||||||
|
=cut
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
# We are a wildcard plugin, figure out what we are being called for
|
||||||
|
try:
|
||||||
|
disk = sys.argv[0].split('_')[2]
|
||||||
|
value = sys.argv[0].split('_')[3]
|
||||||
|
except IndexError:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def normalize_name(name):
|
||||||
|
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 read_smart():
|
||||||
|
"""Read SMART attributes"""
|
||||||
|
out = timeout_command("/usr/sbin/smartctl -A -d ata /dev/%s" % (disk), 2)
|
||||||
|
smart_attribs = dict()
|
||||||
|
for line in out.split('\n')[7:-2]: # Cut away the header and the footer
|
||||||
|
line = line.split()
|
||||||
|
smart_attribs[line[0]] = {
|
||||||
|
'name' : line[1],
|
||||||
|
'label' : normalize_name(line[1]),
|
||||||
|
'raw' : line [-1],
|
||||||
|
}
|
||||||
|
return smart_attribs
|
||||||
|
|
||||||
|
def print_config():
|
||||||
|
"""Return configuration arguments for munin"""
|
||||||
|
attribs = read_smart()
|
||||||
|
print "graph_title S.M.A.R.T raw value %s for drive %s" % (attribs[value]['name'], disk)
|
||||||
|
print "graph_vlabel Raw value"
|
||||||
|
print "graph_info RAW smartctl value"
|
||||||
|
print "graph_category disk"
|
||||||
|
print "graph_args --base 1000 -l 0"
|
||||||
|
|
||||||
|
print "%s.label %s" % (value, attribs[value]['label'])
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def fetch():
|
||||||
|
attribs = read_smart()
|
||||||
|
print "%s.value %s" % (value, attribs[value]['raw'])
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if "config" in sys.argv[1:]:
|
||||||
|
print_config()
|
||||||
|
elif "autoconf" in sys.argv[1:]:
|
||||||
|
pass
|
||||||
|
elif "suggest" in sys.argv[1:]:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
fetch()
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
#
|
#
|
||||||
# Copyright (C) 2011 Andreas Thienemann <andreas@bawue.net>
|
# Copyright (C) 2011,2012 Andreas Thienemann <andreas@bawue.net>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
@ -40,11 +40,13 @@ likely no bmc to query.
|
|||||||
|
|
||||||
In certain cases however bmc-info will just seem to hang for quite some time.
|
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
|
In this case, autodetection does not work because the smbios table has
|
||||||
incorrect information. One system know to experience this problem is the
|
incorrect information. One system known to experience this problem is the
|
||||||
HP Proliant Microserver.
|
HP Proliant Microserver.
|
||||||
|
|
||||||
Adding env.freeipmi_args "--no-probing --driver-type=KCS --driver-address=0xca2 --register-spacing=1"
|
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.
|
to the munin plugin configuration will make the plugin work. This is the
|
||||||
|
specific line for the HP Proliant Microserver mentioned above. Your mileage
|
||||||
|
may vary.
|
||||||
|
|
||||||
Basic configuration for every system is that the plugin needs to be called as root.
|
Basic configuration for every system is that the plugin needs to be called as root.
|
||||||
|
|
||||||
|
292
plugins/sensors/snmp__areca_
Executable file
292
plugins/sensors/snmp__areca_
Executable file
@ -0,0 +1,292 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (C) 2009 - 2012 Andreas Thienemann <andreas@bawue.net>
|
||||||
|
#
|
||||||
|
# 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__areca_ - Munin plugin to get temperature, voltage or fan speed values
|
||||||
|
from Areca network enabled RAID controllers via SNMP.
|
||||||
|
|
||||||
|
=head1 APPLICABLE SYSTEMS
|
||||||
|
|
||||||
|
All machines with a SNMP capable ARECA raid controller.
|
||||||
|
|
||||||
|
=head1 CONFIGURATION
|
||||||
|
|
||||||
|
Make sure your Areca controller is accessible via SNMP from the munin host:
|
||||||
|
snmpwalk -v 1 -c snmp_community ip.add.re.ss
|
||||||
|
|
||||||
|
The plugin is a wildcard plugin and can thus be used to retrieve different
|
||||||
|
values depending on the name of the file.
|
||||||
|
|
||||||
|
Linking it as snmp_10.8.1.230_areca_fan would retrieve the fan speed values from
|
||||||
|
the Areca controller at 10.8.1.230.
|
||||||
|
|
||||||
|
Valid values are fan, temp and volt.
|
||||||
|
|
||||||
|
Add the following to your /etc/munin/plugin-conf.d/snmp__areca file:
|
||||||
|
|
||||||
|
[snmp_ip.add.re.ss_*]
|
||||||
|
community private
|
||||||
|
version 1
|
||||||
|
|
||||||
|
Then test the plugin by calling the following commands:
|
||||||
|
|
||||||
|
munin-run snmp_10.8.1.230_areca_temp config
|
||||||
|
munin-run snmp_10.8.1.230_areca_temp
|
||||||
|
|
||||||
|
Both commands should output sensible data without failing.
|
||||||
|
|
||||||
|
=head1 INTERPRETATION
|
||||||
|
|
||||||
|
The plugin shows the temperature in Celsius or the fanspeed in rotations per minute.
|
||||||
|
|
||||||
|
=head1 MAGIC MARKERS
|
||||||
|
|
||||||
|
#%# family=contrib
|
||||||
|
#%# capabilities=
|
||||||
|
|
||||||
|
=head1 VERSION
|
||||||
|
|
||||||
|
0.0.1
|
||||||
|
|
||||||
|
=head1 BUGS
|
||||||
|
|
||||||
|
None known. If you know of any, please raise a ticket at https://trac.bawue.org/munin/wiki/areca__snmp_
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Andreas Thienemann <andreas@bawue.net>
|
||||||
|
|
||||||
|
=head1 LICENSE
|
||||||
|
|
||||||
|
GPLv2
|
||||||
|
|
||||||
|
=cut
|
||||||
|
"""
|
||||||
|
|
||||||
|
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)
|
104
plugins/sensors/snmp__thecus_fans
Executable file
104
plugins/sensors/snmp__thecus_fans
Executable file
@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
# -*- cperl -*-
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
snmp__thecus_fans - Munin plugin to retrive fanspeed readings from a Thecus
|
||||||
|
NAS device running SNMP.
|
||||||
|
|
||||||
|
=head1 APPLICABLE SYSTEMS
|
||||||
|
|
||||||
|
All Thecus NAS devices which have the third party NETSNMPD module installed.
|
||||||
|
This is available at http://www.fajo.de/main/thecus/modules/netsnmpd
|
||||||
|
|
||||||
|
=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) 2011 - 2012 Andreas Thienemann <andreas@bawue.net>
|
||||||
|
|
||||||
|
Based on the snmp__uptime plugin as a template.
|
||||||
|
|
||||||
|
=head1 LICENSE
|
||||||
|
|
||||||
|
GPLv2 or (at your option) any later version.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Munin::Plugin::SNMP;
|
||||||
|
use vars qw($DEBUG);
|
||||||
|
|
||||||
|
$DEBUG = $ENV{'MUNIN_DEBUG'};
|
||||||
|
|
||||||
|
my $response;
|
||||||
|
|
||||||
|
if (defined $ARGV[0] and $ARGV[0] eq "snmpconf") {
|
||||||
|
print "index 1.3.6.1.4.1.14822.101.21.\n";
|
||||||
|
print "require 1.3.6.1.4.1.14822.101.21.5200.1.1.0 [0-9]\n";
|
||||||
|
print "require 1.3.6.1.4.1.14822.101.21.5200.1.2.0 [0-9]\n";
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined $ARGV[0] and $ARGV[0] eq "config") {
|
||||||
|
my ($host) = Munin::Plugin::SNMP->config_session();
|
||||||
|
print "host_name $host\n" unless $host eq 'localhost';
|
||||||
|
print "graph_title Thecus Fans
|
||||||
|
graph_args --base 1000 -l 0
|
||||||
|
graph_vlabel RPM
|
||||||
|
graph_info This graph shows the RPMs of the fans as reported by the ThecusIO module.
|
||||||
|
graph_category sensors
|
||||||
|
fan1.label Fan 1
|
||||||
|
fan1.info Thecus CPU Fan
|
||||||
|
fan2.label Fan 2
|
||||||
|
fan2.info Thecus System Fan
|
||||||
|
";
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $session = Munin::Plugin::SNMP->session(-translate =>
|
||||||
|
[ -timeticks => 0x0 ]);
|
||||||
|
|
||||||
|
my $fan1 = $session->get_single ("1.3.6.1.4.1.14822.101.21.5200.1.1.0") || 'U';
|
||||||
|
my $fan2 = $session->get_single ("1.3.6.1.4.1.14822.101.21.5200.1.2.0") || 'U';
|
||||||
|
|
||||||
|
#print "Retrived uptime is '$uptime'\n" if $DEBUG;
|
||||||
|
|
||||||
|
print "fan1.value ", $fan1, "\n";
|
||||||
|
print "fan2.value ", $fan2, "\n";
|
187
tools/nagios/check_munin
Normal file
187
tools/nagios/check_munin
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Copyright (C) 2009 Andreas Thienemann <andreas@bawue.net>
|
||||||
|
#
|
||||||
|
# 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 <Host> -M <Module> [-P <Port>] -D [<warn>] [<crit>]")
|
||||||
|
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)
|
Loading…
Reference in New Issue
Block a user