From 08b6b8811a24f71ae6655cb53a0c3e89a6d0f90b Mon Sep 17 00:00:00 2001 From: Gunnar Wolf Date: Sat, 9 Feb 2008 03:51:32 +0100 Subject: [PATCH] Initial version --- plugins/other/multi_snmp_querier | 241 +++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100755 plugins/other/multi_snmp_querier diff --git a/plugins/other/multi_snmp_querier b/plugins/other/multi_snmp_querier new file mode 100755 index 00000000..43d751ce --- /dev/null +++ b/plugins/other/multi_snmp_querier @@ -0,0 +1,241 @@ +#!/usr/bin/perl -w + +=head1 NAME + +multi_snmp_querier - Munin plugin to query several SNMP hosts + +=head1 SYNOPSIS + +This plugin is meant to be called from Munin. You should at least set the +'hosts' environment variable from Munin's configuration (i.e. +/etc/munin/munin.conf) to specify which hosts and how to query. + +=head1 DESCRIPTION + + This plugin expects to receive the following environment variables: + +=over 4 + +=item snmp_oid + +Which SNMP OID should we query on; it defaults to +1.3.6.1.2.1.43.10.2.1.4.1.1 (total printed pages - of course, it only +makes sense to query a printer on this ;-) ). + +Other known and useful OIDs for printers are +1.3.6.1.2.1.43.11.1.1.9.1.1 (total number of pages printed with this +toner cartridge), 1.3.6.1.2.1.43.11.1.1.9.1.1 (total projected +capacity of this toner cartridge - Note that for many makers, the +literal '-2' is returning, meaning more or less "I don't know"), You +might also be interested in 1.3.6.1.2.1.43.11.1.1.6.1.1 (toner type +this printer uses), although as it is a constant string and not +indicative of any kind of value, there's no use in putting it into +Munin (at least, not via this plugin). + +Appropriate labels will be given when Munin requests for configuration +on the above mentioned OIDs - Of course, other OIDs will get far more +generic labels. + +=item hosts (REQUIRED!) + +Comma-separated list of hosts to send SNMP queries to. You can specify +SNMP port and community to each of the hosts by listing them as +community@host:port - Community defaults to public, port defaults to +161. The following is a valid hosts declaration: + + hosts='192.168.0.15, 192.168.0.18:162, private@192.168.0.20' + +It will query host 192.168.0.15 on port 161 with the 'private' +community, host 192.168.0.18 on port 162 with the 'private' community +and host 192.168.0.20 on port 161 with the 'public' community. + +=back + +=head1 DEPENDS ON + +L, L + +=head1 SEE ALSO + +L, L + +=head1 TO DO + +Add a mechanism to specify the labels for unknown OIDs + +=head1 AUTHOR + +Gunnar Wolf + +=head1 COPYRIGHT + +Copyright 2008 Gunnar Wolf, Instituto de Investigaciones +Economicas, UNAM. This plugin 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, or any later version (at your choice). + +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. + +=cut + +use strict; +use Net::SNMP; +use Net::Ping; + +my (%defaults, @hosts, $oid, %known_oids, $VERSION, $cmd_arg); + +$VERSION = '1.0'; # No, not a module, not used in any way - but where else? :) + +%defaults = (community => 'public', + timeout => 1, + port => 161, + oid => '1.3.6.1.2.1.43.10.2.1.4.1.1'); + +@hosts = get_hosts($ENV{hosts}); +$oid = $ENV{snmp_oid} || $defaults{oid}; + +%known_oids = ('1.3.6.1.2.1.43.10.2.1.4.1.1' => + { title => 'Pages', + vlabel => 'Printed pages', + category => 'Printer', + info => 'Returns the total number of printed pages per defined printer', + total => 'Total', + units => 'pages' + }, + '1.3.6.1.2.1.43.11.1.1.8.1.1' => + { title => 'Total projected capacity of this cartridge', + vlabel => 'Total capacity', + category => 'Printer', + info => 'Returns the total projected capacity (in pages) of '. + 'the currently installed cartridge', + total => 'Total', + units => 'pages' + }, + '1.3.6.1.2.1.43.11.1.1.9.1.1' => + { title => 'Pages printed with this cartridge', + vlabel => 'Printed pages', + category => 'Printer', + info => 'Returns the total number of printed pages per ' . + 'defined printer with the current cartridge', + total => 'Total', + units => 'pages' + }, + 'default' => + { title => "Results for SNMP OID $oid", + vlabel => 'units', + category => 'Other', + info => "Results for SNMP OID $oid", + total => 'Total', + units => 'units' + } + ); + +die "Hosts not set - cannot continue" unless @hosts; + +$cmd_arg = $ARGV[0] || ''; +if($cmd_arg eq "config") { + my $labels = $known_oids{$oid} || $known_oids{default}; + # See http://munin.projects.linpro.no/wiki/HowToWritePlugins for + # explanation on the following fields + print "graph_title $labels->{title}\n"; + print "graph_args --base 1000 -l 0\n"; + print "graph_vlabel $labels->{vlabel}\n"; + print "graph_scale no\n"; + print "graph_category $labels->{category}\n"; + print "graph_info $labels->{info}\n"; + print "graph_total $labels->{total}\n"; + for my $host (@hosts) { + my $addr = host_label_for($host->{addr}); + print "${addr}_pages.label $addr\n"; + print "${addr}_pages.draw AREA\n"; + print "${addr}_pages.type DERIVE\n"; + print "${addr}_pages.info $labels->{units} per minute\n"; + } + + exit 0; +} elsif ($cmd_arg eq 'autoconf') { + print "yes\n"; + exit 0; +} + +for my $host (@hosts) { + my ($data, $addr); + $data = get_value_for($host); + $addr = host_label_for($host->{addr}); + # We only use N/A as an internal marker - It would just confuse RRD. + next if $data eq 'N/A'; + print "${addr}_pages.value $data\n"; +} + +exit 0; + +sub ck_alive{ + my ($host, $ping); + $host = shift; + $ping = Net::Ping->new("tcp", 1); + $ping->ping($host); +} + +sub get_hosts { + # Hosts are defined in the 'hosts' environment variable. It's a list of + # hosts (and optionally ports) - We parse the list and arrange it neatly + # to be easily consumed. + my ($hostsdef, @hosts); + $hostsdef = shift; + + for my $host (split(/,/, $hostsdef)) { + $host =~ s/\s//g; + + $host =~ /^(?:(.*)@)? + ([^:]+) + (?::(\d+))?$/x; + + push @hosts, {community => $1 || $defaults{community}, + addr => $2, + port => $3 || $defaults{port} }; + + } + + return @hosts; +} + +sub get_value_for { + my ($host, $snmp, $data); + $host = shift; + + ck_alive($host->{addr}) or return 'N/A'; + + $snmp = setup_snmp($host); + $data = $snmp->get_request($oid); + + return 'N/A' unless $data->{$oid}; + return $data->{$oid}; +} + +sub setup_snmp { + my ($host, $session, $error); + $host = shift; + ($session, $error) = Net::SNMP->session( -hostname => $host->{addr}, + -port => $host->{port}, + -community => $host->{community}, + -timeout => $defaults{timeout} ); + + $session or die "Error before query $host->{addr}:$host->{port}: $error"; + return $session; +} + +sub host_label_for { + my ($addr); + $addr = 'src_' . shift; + $addr =~ s/\./_/g; # Periods not allowed in variable names + return $addr; +}