|
Server : Apache/2.2.2 (Fedora) System : Linux App1.pathumtani.go.th 2.6.20-1.2320.fc5smp #1 SMP Tue Jun 12 19:40:16 EDT 2007 i686 User : apache ( 48) PHP Version : 5.2.9 Disable Function : NONE Directory : /usr/sbin/ |
Upload File : |
#!/usr/bin/perl -w
#
# Copyright (C) 2004 Jimmy Olsen
#
# 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.
#
#
# $Log$
# Revision 1.8.2.1 2005/02/16 20:13:10 jimmyo
# Added man page for munin-node-configure-snmp.
#
# Revision 1.8 2004/11/16 20:00:42 jimmyo
# License cleanups.
#
use strict;
use Net::SNMP;
use Socket;
use Getopt::Long;
my $debug = 0;
my $version = "1.2.5";
my $config = "/etc/munin/munin-node.conf";
my $servicedir = "/etc/munin/plugins";
my $libdir = "/usr/share/munin/plugins";
my $bindir = "/usr/sbin";
my $sysName = "1.3.6.1.2.1.1.5.0";
my $name;
my $session;
my $error;
my $response;
my $community = "public";
my $snmpver = "2c";
my $snmpport = "161";
my $do_usage = 0;
my $do_version = 0;
my $do_error = 0;
my $newer = undef;
my @plugins = ();
my %plugconf = ();
my %hostconf = ();
$do_error = 1 unless GetOptions (
"help" => \$do_usage,
"debug!" => \$debug,
"config=s" => \$config,
"servicedir=s" => \$servicedir,
"plugins=s" => \@plugins,
"libdir=s" => \$libdir,
"version!" => \$do_version,
"snmpversion=s" => \$snmpver,
"community=s" => \$community,
"newer=s" => \$newer
);
if (! @plugins)
{
@plugins = &get_plugins ($libdir);
}
@plugins = split (/,/, join (',', @plugins));
print "# DEBUG: Checking plugins: ", join (',', @plugins), "\n" if $debug;
if ($do_error or $do_usage or !@ARGV)
{
print "Usage: $0 [options] <host/cidr> [host/cidr] [...]
Options:
--help View this help page
--version Show version information
--debug View debug information (very verbose)
--config <file> Override configuration file
[$config]
--servicedir <dir> Override plugin dir [$servicedir]
--libdir <dir> Override plugin lib [$libdir]
";
exit (!$do_usage); # 1 if error, 0 if --help
}
if ($do_version)
{
print "munin-node-configure-snmp (munin-node) version $version.\n";
print "Written by Jimmy Olsen\n";
print "\n";
print "Copyright (C) 2004 Jimmy Olsen\n";
print "This is free software released under the GNU Public License. There is NO\n";
print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
exit 0;
}
foreach my $plugin (@plugins)
{
&fetch_plugin_config ($plugin, \%plugconf);
}
while (my $addr = shift)
{
my $num = 32;
if ($addr =~ /([^\/]+)\/(\d+)/)
{
$num = $2;
$addr = $1;
}
$num = 32 - $num;
$num = 2 ** $num;
print "# Doing $addr / $num\n" if $debug;
for (my $i = 0; $i < $num; $i++)
{
print "# Doing $addr -> $i...\n" if $debug;
my $tmpaddr = $addr;
if ($tmpaddr =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/)
{
my @tmpaddr = split (/\./, $tmpaddr);
$tmpaddr[3] += $i;
$tmpaddr = gethostbyaddr (inet_aton (join ('.', @tmpaddr)), AF_INET);
$tmpaddr ||= join ('.', @tmpaddr);
}
print "# ($tmpaddr)\n" if $debug;
&do_host ("$tmpaddr", $community, $snmpver, $snmpport);
}
}
#interfaces ($name);
sub do_host
{
my $host = shift;
my $comm = shift;
my $ver = shift;
my $port = shift;
if ($host =~ /([^:]+):(\d+)/)
{
$host = $1;
$port = $2;
}
($session, $error) = Net::SNMP->session(
-hostname => $host,
-community => $comm,
-port => $port,
-version => $ver,
);
$session->translate (0);
die $error if $error;
if (!defined ($session))
{
print "# Dropping host \"$host\": $error" . "\n";
return 0;
}
if (!defined ($response = $session->get_request($sysName)))
{
print "# Dropping host \"$host\": " . $session->error() . "\n";
return 0;
}
$name = $response->{$sysName};
foreach my $plugin (@plugins)
{
my $auto = snmp_autoconf_plugin ($plugin, \%plugconf, \%hostconf, $host);
if (defined $auto)
{
if ($plugconf{$plugin}->{wild})
{
foreach my $id (@{$auto})
{
if (! -e "$servicedir/snmp_$host"."_$plugin"."_$id")
{
print "ln -s $libdir/snmp__$plugin", "_ $servicedir/snmp_$host", "_$plugin", "_$id\n";
}
}
}
else
{
if (! -e "$servicedir/snmp_$host"."_$plugin")
{
print "ln -s $libdir/snmp__$plugin", " $servicedir/snmp_$host", "_$plugin\n";
}
}
}
}
}
sub snmp_autoconf_plugin
{
my $plugname = shift;
my $plugconf = shift;
my $hostconf = shift;
my $host = shift;
print "# Running autoconf on $plugname for $host...\n" if $debug;
# First round of requirements
if (defined $plugconf->{$plugname}->{req})
{
print "# Checking requirements...\n" if $debug;
foreach my $req (@{$plugconf->{$plugname}->{req}})
{
if ($req->[0] =~ /\.$/)
{
print "# Delaying testing of $req->[0], as we need the indexes first.\n" if $debug;
next;
}
my $snmp_val = snmp_get_single ($session, $req->[0]);
if (!defined $snmp_val or $snmp_val !~ /$req->[1]/)
{
print "# Nope. Duh.\n" if $debug;
return undef;
}
}
}
# We need the number of "things" to autoconf
my $num = 1;
if (defined $plugconf->{$plugname}->{num})
{
$num = snmp_get_single ($session, $plugconf->{$plugname}->{num});
return undef if !defined $num;
}
print "# Number of items to autoconf is $num...\n" if $debug;
# Then the index base
my $indexes;
if (defined $plugconf->{$plugname}->{ind})
{
$indexes = snmp_get_index ($plugconf->{$plugname}->{ind}, $num);
return undef if !defined $indexes;
}
else
{
$indexes->{0} = 1;
}
print "# Got indexes: ", join (',', keys (%{$indexes})), "\n" if $debug;
return undef unless scalar keys %{$indexes};
# Second round of requirements (now that we have the indexes)
if (defined $plugconf->{$plugname}->{req})
{
print "# Checking requirements...\n" if $debug;
foreach my $req (@{$plugconf->{$plugname}->{req}})
{
if ($req->[0] !~ /\.$/)
{
print "# Already tested of $req->[0], before we got hold of the indexes.\n" if $debug;
next;
}
foreach my $key (keys %$indexes)
{
my $snmp_val = snmp_get_single ($session, $req->[0] . $key);
if (!defined $snmp_val or $snmp_val !~ /$req->[1]/)
{
print "# Nope. Deleting $key from possible solutions.\n" if $debug;
delete $indexes->{$key}; # Disable
}
}
}
}
my @tmparr = sort keys %$indexes;
return \@tmparr;
}
sub fetch_plugin_config
{
my $plugname = shift;
my $plugconf = shift;
my $plugin = "snmp__" . $plugname;
if (-x "$libdir/$plugin" . "_")
{
$plugin .= "_";
$plugconf->{$plugname}->{wild} = 1;
}
elsif (-x "$libdir/$plugin")
{
$plugconf->{$plugname}->{wild} = 0;
}
else
{
print "# Skipping $plugname: Couldn't find plugin \"$libdir/$plugin\".\n" if $debug;
return 0;
}
print "# SNMPconfing plugin \"$plugname\" ( $libdir/$plugin )\n" if $debug;
my $fork = open (PLUG, "-|");
if ($fork == -1)
{
die "# ERROR: Unable to fork: $!";
}
elsif ($fork == 0) # Child
{
close (STDERR);
open (STDERR, ">&STDOUT");
exec ("$bindir/munin-run", "--config", $config, "--servicedir", $libdir, $plugin, "snmpconf");
}
else
{
while (<PLUG>)
{
chomp;
s/^\s+//;
s/\s+$//;
my ($a, $b) = split (/\s+/, $_, 2);
next unless defined $a;
if ($a =~ /^require$/i and defined $b)
{
my ($oid, $val) = split (/\s+/, $b);
if (! defined $val)
{
$val = ".*";
}
push (@{$plugconf->{$plugname}->{req}}, [$oid, $val]);
print "# Registered $plugname requirement: $oid =~ /$val/\n" if $debug;
}
elsif ($a =~ /^index$/i and defined $b)
{
$plugconf->{$plugname}->{ind} = $b;
print "# Registered $plugname index : $b\n" if $debug;
}
elsif ($a =~ /^number$/i and defined $b)
{
$plugconf->{$plugname}->{num} = $b;
print "# Registered $plugname number : $b\n" if $debug;
}
elsif ($a =~ /^env\.(\S+)$/)
{
$plugconf->{$plugname}->{env}->{$1} = $b;
print "# Registered $plugname env : $b\n" if $debug;
}
else
{
print "# Couldn't parse line line $_\n";
}
}
}
return 0;
}
sub snmp_get_single
{
my $session = shift;
my $oid = shift;
if ((!defined ($response = $session->get_request($oid))) or
$session->error_status)
{
return undef;
}
print "# Fetched value \"$response->{$oid}\"\n" if $debug;
return $response->{$oid};
}
sub snmp_get_index
{
my $oid = shift;
my $num = shift;
my $ret = $oid . "0";
my $rhash = {};
$num++; # Avaya switch b0rkenness...
for (my $i = 0; $i < $num; $i++)
{
if ($i == 0)
{
print "# Checking for $ret\n" if $debug;
$response = $session->get_request($ret);
}
if ($i or !defined $response or $session->error_status)
{
print "# Checking for sibling of $ret\n" if $debug;
$response = $session->get_next_request($ret);
}
if (!$response or $session->error_status)
{
return undef;
}
my @keys = keys %$response;
$ret = $keys[0];
last unless ($ret =~ /^$oid\d+$/);
print "# Index $i: ", join ('|', @keys), "\n" if $debug;
$rhash->{$response->{$ret}} = 1;
}
return $rhash;
}
sub interfaces
{
my $name = shift;
my %interfaces = ();
my $num;
my $ifNumber = "1.3.6.1.2.1.2.1.0";
my $ifEntryIndex = "1.3.6.1.2.1.2.2.1.1"; # dot something
my $ifEntryType = "1.3.6.1.2.1.2.2.1.3"; # dot something
my $ifEntrySpeed = "1.3.6.1.2.1.2.2.1.5"; # dot something
print "# System name: ", $name, "\n" if $debug;
if (!defined ($response = $session->get_request($ifNumber)) or
$session->error_status)
{
die "Croaking: " . $session->error();
}
$num = $response->{$ifNumber} +1; # Add one because of bogus switch entries
print "# Number of interfaces: ", $num, "\n" if $debug;
my $ret = $ifEntryIndex . ".0";
for (my $i = 0; $i < $num;)
{
if ($i == 0)
{
$response = $session->get_request($ret);
}
if ($i or !defined $response or $session->error_status)
{
$response = $session->get_next_request($ret);
}
if (!$response or $session->error_status)
{
die "Croaking: ", $session->error();
}
my @keys = keys %$response;
$ret = $keys[0];
last unless ($ret =~ /^$ifEntryIndex\.\d+$/);
print "# Index $i: ", join ('|', @keys), "\n" if $debug;
$interfaces{$response->{$ret}} = 1;
$i++;
}
foreach my $key (keys %interfaces)
{
$response = $session->get_request($ifEntrySpeed . "." . $key);
if (!$response or $session->error_status)
{
die "Croaking: ", $session->error();
}
my @keys = keys %$response;
print "# Speed $key: ", join ('|', @keys), ": ", $response->{$keys[0]}, "\n" if $debug;
if ($response->{$keys[0]} == 0)
{
delete $interfaces{$key};
}
}
foreach my $key (keys %interfaces)
{
$response = $session->get_request($ifEntryType . "." . $key);
if (!$response or $session->error_status)
{
die "Croaking: ", $session->error();
}
my @keys = keys %$response;
print "# Type $key: ", join ('|', @keys), ": ", $response->{$keys[0]}, "\n" if $debug;
if ($response->{$keys[0]} != 6)
{
delete $interfaces{$key};
}
}
foreach my $key (sort keys %interfaces)
{
print "snmp_${name}_if_$key\n";
}
}
sub get_plugins
{
my $dir = shift;
my @plugs = ();
my @plugins = ();
print "DEBUG: Opening \"$dir\" for reading...\n" if $debug;
opendir (DIR, $dir) or die "Could not open \"$dir\" for reading: $!";
@plugs = readdir (DIR);
closedir (DIR);
foreach my $plug (@plugs)
{
my $p = undef;
my $path = "$dir/$plug";
$path = readlink($path) and $path = $path =~ /^\// ? $path : "$dir/$path" while -l $path;
next unless -f $path;
next unless -x _;
next if $plug =~ /^\./;
$p->{'family'} = "contrib"; # Set default family...
print "DEBUG: Checking plugin: $plug..." if $debug;
if (! open (FILE, "$dir/$plug"))
{
warn "WARNING: Could not open file \"$dir/$plug\" for reading ($!). Skipping.";
next;
}
while (<FILE>)
{
chomp;
if (/#%#\s+family\s*=\s*(\S+)\s*$/)
{
$p->{'family'} = $1;
print "$1..." if $debug;
}
elsif (/#%#\s+capabilities\s*=\s*(.+)$/)
{
foreach my $cap (split (/\s+/, $1))
{
$p->{'capability'}->{$cap} = 1;
print "$cap..." if $debug;
}
}
}
close (FILE);
print "\n" if $debug;
if (defined $p->{'capability'}->{'snmpconf'})
{
$plug =~ s/^snmp__//;
$plug =~ s/_$//;
push (@plugins, $plug);
}
}
return @plugins;
}
1;
=head1 NAME
munin-node-configure-snmp - A sub-program used by munin-node-configure to
do the actual SNMP probing.
=head1 SYNOPSIS
munin-node-configure-snmp [options] <host/cidr> [host/cidr] [...]
=head1 DESCRIPTION
Munin's node is a daemon that Munin connects to fetch data. This data is
stored in .rrd-files, and later graphed and htmlified. It's designed to
let it be very easy to graph new datasources.
Munin-node-configure-snmp is a program that is used by another program in
the Munin package, munin-node-configure, to do SNMP probing of hosts or
networks.
This program is only meant to be run by other programs in the Munin
package, not by hand.
=head1 VERSION
This is munin-node v1.2.5
=head1 AUTHORS
Jimmy Olsen.
=head1 BUGS
munin-node-configure-snmp does not have any known bugs.
Please report other bugs in the bug tracker at L<http://munin.sf.net/>.
=head1 COPYRIGHT
Copyright © 2004 Jimmy Olsen.
This is free software; see the source for copying conditions. There is
NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
This program is released under the GNU General Public License
=cut