diff --git a/t/test_class.pl b/t/test_class.pl index 31ca720d..a1f873b7 100755 --- a/t/test_class.pl +++ b/t/test_class.pl @@ -1,208 +1,328 @@ -#!/usr/bin/perl -w +#!/usr/bin/perl # # test_class.pl # -# Test a device class in SNMP::Info against a device. +# Copyright (c) 2013 Eric Miller +# All rights reserved. # -# Max Baker +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: # -# $Id$ +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the University of California, Santa Cruz nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. # +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. -use FindBin; -use lib "$FindBin::Bin/../.."; -#use lib '/usr/local/netdisco'; - -use SNMP::Info; -use Getopt::Long; use strict; -use vars qw/$Class $Dev $Comm $Ver @Dump %Dumped $Debug %args $NoBulk $MibDirs/; +use warnings; +use Carp; +use Getopt::Long; +use Pod::Usage; +use SNMP::Info; + +my $EMPTY = q{}; # Default Values -$Class = ''; -$Dev = ''; -$Comm = ''; -$Ver = 2; -@Dump = (); -$Debug = 0; -$NoBulk = 0; +my $class = $EMPTY; +my @dump = (); +my $debug = 0; +my $device = ''; +my $comm = ''; +my $ver = 2; +my $ignore = 0; +my $help = 0; +my $nobulk = 0; +my $mibdirs; +my %dumped; -GetOptions ('c|class=s' => \$Class, - 'd|dev=s' => \$Dev, - 's|comm=s' => \$Comm, - 'v|ver=i' => \$Ver, - 'h|help' => \&usage, - 'p|print=s' => \@Dump, - 'x|debug+' => \$Debug, - 'n|nobulk' => \$NoBulk, - 'm|mibdir=s@' => \$MibDirs, - ); +GetOptions( + 'c|class=s' => \$class, + 'd|dev=s' => \$device, + 's|comm=s' => \$comm, + 'v|ver=i' => \$ver, + 'i|ignore' => \$ignore, + 'p|print=s' => \@dump, + 'x|debug+' => \$debug, + 'm|mibdir=s' => \$mibdirs, + 'n|nobulk' => \$nobulk, + 'h|?|help' => sub { pod2usage(1); }, +); -&usage unless ($Dev and $Comm); - -# Default MIB directories -my $n = '/usr/local/netdisco'; -unless (defined $MibDirs) { - $MibDirs = ["$n/mibs/allied", "$n/mibs/asante", "$n/mibs/cisco", "$n/mibs/foundry", - "$n/mibs/hp", "$n/mibs/nortel", "$n/mibs/extreme", "$n/mibs/rfc", - "$n/mibs/net-snmp"]; +unless ( $device and $comm ) { + pod2usage(2); } -$Class = $Class ? "SNMP::Info::$Class" : 'SNMP::Info'; -eval "require $Class;"; -if ($@) { - die "Can't load Class specified : $Class.\n\n$@\n"; +if ( $ignore && !defined $mibdirs ) { + print "mibdirs must be provided if ignoring snmp.conf \n\n"; + pod2usage(1); } -my $class_ver = 'undef'; -{ no strict 'refs'; - $class_ver = ${"${Class}::VERSION"}; -} -print "Class $Class ($class_ver) loaded from SNMP::Info $SNMP::Info::VERSION.\n"; -#print "MIB Dirs : ",join(', ',@$MibDirs),"\n"; -print "Dumping : ",join(',',@Dump),"\n" if scalar @Dump; +if ($ignore) { local $ENV{'SNMPCONFPATH'} = $EMPTY } +if ($ignore) { local $ENV{'MIBDIRS'} = "$mibdirs" } -%args = (); -if ($NoBulk) { - $args{BulkWalk} = 0; +if ( defined $mibdirs ) { + SNMP::addMibDirs($mibdirs); } -my $dev = new $Class( 'AutoSpecify' => 0, - 'AutoVerBack' => 0, - 'Version' => $Ver, - 'Debug' => $Debug, - 'DestHost' => $Dev, - 'Community' => $Comm, - 'MibDirs' => $MibDirs, - %args - ) or die "\n"; +$class = $class ? "SNMP::Info::$class" : 'SNMP::Info'; + +( my $mod = "$class.pm" ) + =~ s{::}{/}xg; # SNMP::Info::Layer3 => SNMP/Info/Layer3.pm +if ( !eval { require $mod; 1; } ) { + croak "Could not load $class. Error Message: $@\n"; +} + +my $class_ver = $class->VERSION(); + +print + "Class $class ($class_ver) loaded from SNMP::Info $SNMP::Info::VERSION.\n"; + +if ( scalar @dump ) { print 'Dumping : ', join( q{,}, @dump ), "\n" } + +my %args = (); +if ($nobulk) { + $args{BulkWalk} = 0; +} + +my $dev = $class->new( + 'AutoSpecify' => 0, + 'AutoVerBack' => 0, + 'Debug' => $debug, + 'MibDirs' => $mibdirs, + 'Version' => $ver, + 'DestHost' => $device, + 'Community' => $comm, + %args +) or die "\n"; + +print "Connected to $device.\n"; +print 'Detected Class: ', $dev->device_type(), "\n"; +print "Using Class: $class (-c to change)\n"; -print "Connected to $Dev.\n"; -print "Detected Class: ", $dev->device_type(), "\n"; -print "Using Class: $Class (-c to change)\n"; - my $layers = $dev->layers(); -my $descr = $dev->description(); +my $descr = $dev->description(); -unless (defined $layers or defined $descr){ - die "Are you sure you got the right community string and version?\nCan't fetch layers or description.\n"; +if ( !defined $layers || !defined $descr ) { + die + "Are you sure you got the right community string and version?\nCan't fetch layers or description.\n"; } -print "Fetching global info...\n\n"; +print "\nFetching base info...\n\n"; -my @globals = qw/description uptime contact name location layers ports mac serial - ps1_type ps2_type ps1_status ps2_status fan slots vendor os os_ver/; +my @base_fns = qw/vendor model os os_ver description contact location + layers mac serial/; -foreach my $global (@globals){ - test_global($dev,$global); +foreach my $fn (@base_fns) { + test_global( $dev, $fn ); } print "\nFetching interface info...\n\n"; my @fns = qw/interfaces i_type i_ignore i_description i_mtu i_speed i_mac i_up - i_up_admin i_name i_duplex i_duplex_admin i_stp_state - i_lastchange/; + i_up_admin i_name i_duplex i_duplex_admin i_stp_state + i_vlan i_pvid i_lastchange/; -foreach my $fn (@fns){ - test_fn($dev,$fn); +foreach my $fn (@fns) { + test_fn( $dev, $fn ); } -print "\nTesting Misc...\n\n"; -my @misc = qw/v_name v_port/; -foreach my $fn (@misc){ - test_fn($dev,$fn); +print "\nFetching VLAN info...\n\n"; + +my @vlan = qw/v_index v_name/; + +foreach my $fn (@vlan) { + test_fn( $dev, $fn ); } -foreach my $fn (@Dump) { - test_fn($dev,$fn) unless $Dumped{$fn}; +print "\nFetching topology info...\n\n"; + +my @topo = qw/c_if c_ip c_port c_id c_platform/; + +foreach my $fn (@topo) { + test_fn( $dev, $fn ); +} + +print "\nFetching module info...\n\n"; + +my @modules = qw/e_descr e_type e_parent e_name e_class e_pos e_hwver + e_fwver e_swver e_model e_serial e_fru/; + +foreach my $fn (@modules) { + test_fn( $dev, $fn ); +} + +foreach my $fn (@dump) { + if ( !$dumped{$fn} ) { test_fn( $dev, $fn ) } } #-------------------------------- + sub test_global { - my $dev = shift; + my $info = shift; my $method = shift; - my $value; - eval { - $value = $dev->$method(); - }; - - if ($@){ - my $err = $@; - $err =~ s/[[:cntrl:]]+/ /g; - printf "%-20s Blew up. $err\n",$method; - return 0; + my $value = $info->$method(); + + if ( !defined $value ) { + printf "%-20s Does not exist.\n", $method; + return 0; } - - unless (defined $value){ - printf "%-20s Does not exist.\n",$method; - return 0; + $value =~ s/[[:cntrl:]]+/ /gx; + if ( length $value > 60 ) { + $value = substr $value, 0, 60; + $value .= '...'; } - $value =~ s/[[:cntrl:]]+/ /g; - if (length $value > 60) { - $value = substr($value,0,60); - $value .= '...'; - } - printf "%-20s %s \n",$method,$value; + printf "%-20s %s \n", $method, $value; return 1; } sub test_fn { - my $dev = shift; + my $info = shift; my $method = shift; - my $results; - - eval { - $results = $dev->$method(); - }; - - if ($@){ - my $err = $@; - $err =~ s/\n/ /g; - printf "%-20s Blew up. $err\n",$method; - return 0; - } + my $results = $info->$method(); # If accidentally called on a global, pass it along nicely. - if (defined($results) and !ref($results)) { - return test_global($dev, $method); + if ( defined $results && !ref $results ) { + return test_global( $dev, $method ); } - unless (defined $results and scalar keys %$results) { - printf "%-20s Empty Results.\n",$method; - return 0; + if ( !defined $results && !scalar keys %{$results} ) { + printf "%-20s Empty Results.\n", $method; + return 0; } - printf "%-20s %d rows.\n",$method, scalar(keys %$results); - if (grep(/^$method$/,@Dump)) { - $Dumped{$method} = 1; - foreach my $iid (keys %$results){ - print " $iid : "; - if (ref($results->{$iid}) eq 'ARRAY') { - print "[ ", join(", ", @{$results->{$iid}}), " ]"; - } else { + printf "%-20s %d rows.\n", $method, scalar keys %{$results}; + if ( grep {/^$method$/x} @dump ) { + $dumped{$method} = 1; + foreach my $iid ( keys %{$results} ) { + print " $iid : "; + if ( ref( $results->{$iid} ) eq 'ARRAY' ) { + print '[ ', join( ', ', @{ $results->{$iid} } ), ' ]'; + } + else { print $results->{$iid}; } print "\n"; - } + } } return 1; } -sub usage { - print << "end_usage"; +__END__ -test_class - Test a device against an SNMP::Info class - -c --class Layer2::Catalyst - -d --dev myswitch - -s --comm public - -v --ver 2 - -p --print i_blah - -p --print i_blah2 - -x --debug debugging flag - -n --nobulk disable bulkwalk - -m --mibdirs directory (repeat as needed) +=head1 NAME -end_usage - exit; -} +test_class.pl - Test a device against an SNMP::Info class. + +=head1 AUTHOR + +Eric Miller + +=head1 SYNOPSIS + +test_class.pl [options] + +Options: + + -c|class SNMP::Info class to use, Layer2::Catalyst + -d|dev Device + -s|comm SNMP community + -v|ver SNMP version + -p|print Print values + -x|debug Debugging flag + -i|ignore Ignore Net-SNMP configuration file + -m|mibdir Directory containing MIB Files + -n|nobulk Disable bulkwalk + -h|?|help Brief help message + +=head1 OPTIONS + +=over 8 + +=item B<-class> + +Specific SNMP::Info class to use. Defaults to SNMP::Info if no specific +class provided. + +-class Layer2::Catalyst + +=item B<-dev> + +Device to test against. No default and a mandatory option. + +-dev 1.2.3.4 + +=item B<-comm> + +SNMP community string. No default and a mandatory option. + +-comm public + +=item B<-ver> + +SNMP version. Default 2. + +-ver 1 + +=item B<-print> + +Print values of a class method rather than summarizing. May be repeated +multiple times. + +-print i_description -print i_type + +=item B<-debug> + +Turns on SNMP::Info debug. + +-debug + +=item B<-ignore > + +Ignore Net-SNMP configuration file snmp.conf. If this used mibdirs must be +provided. + +-ignore + +=item B<-mibdir> + +Directory containing MIB Files. Multiple directories should be separated by a +colon ':'. + +-mibdir /usr/local/share/snmp/mibs/rfc:/usr/local/share/snmp/mibs/net-snmp + +=item B<-nobulk > + +Disable SNMP bulkwalk. Default bulkwalk is on and utilized with version 2. + +-nobulk + +=item B<-help> + +Print help message and exits. + +=back + +=head1 DESCRIPTION + +B will test a device against a specfied SNMP::Info class. +This allows debugging and testing of live devices to include validating +device support with existing classes. + +=cut