diff --git a/plugins/snmp/snmp__rms2_ b/plugins/snmp/snmp__rms2_ new file mode 100755 index 00000000..db369752 --- /dev/null +++ b/plugins/snmp/snmp__rms2_ @@ -0,0 +1,222 @@ +#!/usr/bin/perl -w +# +# This plugin is for querying Knuerr RMS Compact II Rack Monitoring Units +# by SNMP. +# +# Michael Meier +# +# 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; version 2 dated June, +# 1991. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# +# Usage: +# ln -s /usr/share/munin/node/plugins-auto/snmp__rms2_ /etc/munin/node.d/snmp_HOSTNAME_rms2_MODE +# available MODEs: +# temp for temperature sensors +# humidity for humidity sensors (untested!) +# contact for contact sensors +# +# Note: Due to shortcomings of munin-node-configure, it is not currently +# possible to make this plugin properly autodetect/autoconfigure. That is +# because for SNMP plugins that need more than just a hostname, only numbers +# that come from an SNMP tree can be the second parameter. Parameters like +# "temp" do not exist in the short-sighted world of munin-node-configure. +# Combining SNMP with the "suggest" plugin-feature is currently not possible. + +#%# family=snmpauto +#%# capabilities=snmpconf + +use strict; +use Net::SNMP; + +my $DEBUG = 0; + +my $host = $ENV{host} || undef; +my $port = $ENV{port} || 161; +my $community = $ENV{community} || "public"; +my $mode = $ENV{mode} || undef; + +my $response; + +my $graphs = { + 'temp' => { 'title' => 'Temperatures', + 'unit' => 'degC', # This can actually be overwritten later with retard-units (F) + 'scale' => 0.1, + 'thatype' => 2, + 'list' => '.1.3.6.1.4.1.3711.24.1.1.1.2.2.1.1' }, + 'humidity' => { 'title' => 'Humidity', + 'unit' => '%', + 'scale' => 0.1, # FIXME? + 'thatype' => 3, + 'list' => '.1.3.6.1.4.1.3711.24.1.1.1.2.2.1.1' }, + 'contact' => { 'title' => 'Contact sensors', + 'unit' => 'n', + 'list' => '.1.3.6.1.4.1.3711.24.1.1.1.3.1.1.1' }, +}; + +if (defined($ARGV[0]) && ($ARGV[0] eq "snmpconf")) { + print "require .1.3.6.1.4.1.3711.24.1.1.99.1.0\n"; # The inventory tree + exit(0); +} + +if ($0 =~ /^(?:|.*\/)snmp_([^_]+)_rms2_(.+)$/) { + $host = $1; + $mode = $2; + if ($host =~ /^([^:]+):(\d+)$/) { + $host = $1; + $port = $2; + } +} elsif (!defined($host)) { + print "# Debug: $0 -- $1 -- $2\n" if $DEBUG; + print("# Error: couldn't understand what I'm supposed to monitor.\n"); + print("# You need to either name this plugin properly in the scheme\n"); + print("# snmp_HOSTNAME_rms2_MODE\n"); + print("# or alternatively set the environment variables 'host' and 'mode'\n"); + exit(1); +} + +my ($session, $error) = Net::SNMP->session( + -hostname => $host, + -community => $community, + -port => $port, + -version => 'snmpv2c', + -timeout => 1.0 +); + +if (!defined ($session)) { + print("# Failed to open SNMP session: $error"); + exit(1); +} + +unless (defined($graphs->{$mode}->{'title'})) { + print("# Unknown mode '$mode'! Available modes are:\n"); + foreach my $m (keys(%{$graphs})) { + if (defined($graphs->{$m}->{'title'})) { + printf("# %-18s %s\n", $m, $graphs->{$m}->{'title'}); + } + } + exit(1); +} + +# This is mostly copy&paste from the snmpwalk.pl-example in the Net::SNMP sourcecode. +# I'm not really sure this is the simplest way to do this, but could not find a +# better WORKING example. +my $last_oid = $graphs->{$mode}->{'list'}; +my @indexes = ( ); +my @args = ( -varbindlist => [ $last_oid ] ); +push(@args, -maxrepetitions => 2); +GET_BULK: while (defined $session->get_bulk_request(@args)) { + my @oids = $session->var_bind_names(); + if (!scalar @oids) { + print("# ERROR: Empty SNMP tree\n"); + exit(1); + } + foreach my $oid (@oids) { + # Make sure we have not hit the end of the MIB. + if ($session->var_bind_types()->{$oid} == ENDOFMIBVIEW) { + $oid =~ s/.*\.//g; + push(@indexes, $oid); + last GET_BULK; + } + if (substr($oid, 0, length($graphs->{$mode}->{'list'})) ne $graphs->{$mode}->{'list'}) { + last GET_BULK; + } + $last_oid = $oid; + $oid =~ s/.*\.//g; + push(@indexes, $oid); + } + @args = (-maxrepetitions => 2, -varbindlist => [ $last_oid ]); +} + +if (defined($graphs->{$mode}->{'thatype'})) { # Analogue sensor requested + if ($graphs->{$mode}->{'thatype'} == 2) { # Temperature-Sensor + if (defined($response = $session->get_request(".1.3.6.1.4.1.3711.24.1.1.1.2.1"))) { + my $tempscale = $response->{".1.3.6.1.4.1.3711.24.1.1.1.2.1"} eq '2'; + if ($tempscale == 2) { $graphs->{$mode}->{'unit'} = 'degF'; } + if ($tempscale == 3) { $graphs->{$mode}->{'unit'} = 'K'; } + } + } +} + +# Now this is a little cheating: We "calculate" various other start OIDs from +# the list OID. +my $nameoid = my $stateoid = my $valueoid = $graphs->{$mode}->{'list'}; +# The start OID for names just ends with .3 instead of .1 +$nameoid =~ s/1$/3/; +# the one for input status ends with .2 instead of .1 +$stateoid =~ s/1$/2/; +# the start OID for the value ends with .7 instead of .1 +$valueoid =~ s/1$/7/; + +# Now check which of the inputs we detected are valid +my @validindexes = ( ); +foreach my $i (@indexes) { + unless (defined($response = $session->get_request($stateoid . "." . $i))) { + next; + } + if ($response->{$stateoid . "." . $i} ne '1') { # 1 means active and valid. + next; + } + if (defined($graphs->{$mode}->{'thatype'})) { # Analogue sensor requested + my $typeoid = $graphs->{$mode}->{'list'}; + $typeoid =~ s/1$/6/; + unless (defined($response = $session->get_request($typeoid . "." . $i))) { + next; + } + if ($response->{$typeoid . "." . $i} ne $graphs->{$mode}->{'thatype'}) { + next; # Not the correct type (humidity vs. temperature) + } + } + push(@validindexes, $i); +} + +if ($ARGV[0] and $ARGV[0] eq "config") { + print("host_name $host\n"); + printf("graph_title %s\n", $graphs->{$mode}->{'title'}); + # print "graph_args --base 1000\n"; + print("graph_category envsensor\n"); + printf("graph_vlabel %s\n", $graphs->{$mode}->{'unit'}); + unless (defined($graphs->{$mode}->{'thatype'})) { + print("graph_info For contact sensors, the values mean: 1 = open, 2 = closed, 3 = armed, 4 = triggered\n"); + } + + foreach my $i (@validindexes) { + if (defined($response = $session->get_request($nameoid . "." . $i))) { + printf("%s%u.label %s\n", $mode, $i, $response->{$nameoid . "." . $i}); + } else { + printf("%s%u.label Port %u\n", $mode, $i, $i); + } + if (defined($response = $session->get_request($graphs->{$mode}->{'list'} . "." . $i))) { + printf("%s%u.info Port %s\n", $mode, $i, $response->{$graphs->{$mode}->{'list'} . "." . $i}); + } + printf("%s%u.type GAUGE\n", $mode, $i); + if (defined($ENV{"${mode}${i}.warning"})) { printf("%s%s.warning %s\n", $mode, $i, $ENV{"${mode}${i}.warning"}); } + if (defined($ENV{"${mode}${i}.critical"})) { printf("%s%s.critical %s\n", $mode, $i, $ENV{"${mode}${i}.critical"}); } + } + exit(0); +} + +foreach my $i (@validindexes) { + if (defined($response = $session->get_request($valueoid . "." . $i))) { + my $v = $response->{$valueoid . "." . $i}; + if (defined($graphs->{$mode}->{'scale'})) { + $v = $v * $graphs->{$mode}->{'scale'}; + printf("%s%u.value %.1f\n", $mode, $i, $v); + } else { + printf("%s%u.value %u\n", $mode, $i, $v); + } + } else { + printf("%s%u.value U\n", $mode, $i); + } +}