mirror of
https://github.com/munin-monitoring/contrib.git
synced 2018-11-08 00:59:34 +01:00
17f784270a
* remove trailing whitespace * remove empty lines at the end of files
293 lines
7.6 KiB
Python
Executable File
293 lines
7.6 KiB
Python
Executable File
#!/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)
|