347 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			347 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/perl
 | 
						|
#
 | 
						|
# test_class.pl
 | 
						|
#
 | 
						|
# Copyright (c) 2013 Eric Miller
 | 
						|
# All rights reserved.
 | 
						|
#
 | 
						|
# Redistribution and use in source and binary forms, with or without
 | 
						|
# modification, are permitted provided that the following conditions are met:
 | 
						|
#
 | 
						|
#     * 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 strict;
 | 
						|
use warnings;
 | 
						|
use Carp;
 | 
						|
use Getopt::Long;
 | 
						|
use Pod::Usage;
 | 
						|
use SNMP::Info;
 | 
						|
 | 
						|
my $EMPTY = q{};
 | 
						|
 | 
						|
# Default Values
 | 
						|
my $class  = $EMPTY;
 | 
						|
my @dump   = ();
 | 
						|
my $debug  = 0;
 | 
						|
my $cache  = 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'    => \$device,
 | 
						|
    's|comm=s'   => \$comm,
 | 
						|
    'v|ver=i'    => \$ver,
 | 
						|
    'i|ignore'   => \$ignore,
 | 
						|
    'p|print=s'  => \@dump,
 | 
						|
    'm|mibdir=s' => \$mibdirs,
 | 
						|
    'n|nobulk'   => \$nobulk,
 | 
						|
    'x|debug+'   => \$debug,
 | 
						|
    'k|cache'    => \$cache,
 | 
						|
    'h|?|help'   => sub { pod2usage(1); },
 | 
						|
);
 | 
						|
 | 
						|
unless ( $device and $comm ) {
 | 
						|
    pod2usage(2);
 | 
						|
}
 | 
						|
 | 
						|
if ( $ignore && !defined $mibdirs ) {
 | 
						|
    print "mibdirs must be provided if ignoring snmp.conf \n\n";
 | 
						|
    pod2usage(1);
 | 
						|
}
 | 
						|
 | 
						|
local $ENV{'SNMPCONFPATH'} = $EMPTY     if $ignore;
 | 
						|
local $ENV{'MIBDIRS'}      = "$mibdirs" if $ignore;
 | 
						|
 | 
						|
if ( defined $mibdirs ) {
 | 
						|
    SNMP::addMibDirs($mibdirs);
 | 
						|
}
 | 
						|
 | 
						|
$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,
 | 
						|
    '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";
 | 
						|
 | 
						|
my $layers = $dev->layers();
 | 
						|
my $descr  = $dev->description();
 | 
						|
 | 
						|
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 "\nFetching base info...\n\n";
 | 
						|
 | 
						|
my @base_fns = qw/vendor model os os_ver description contact location
 | 
						|
    layers mac serial/;
 | 
						|
 | 
						|
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_vlan i_pvid i_lastchange/;
 | 
						|
 | 
						|
foreach my $fn (@fns) {
 | 
						|
    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 );
 | 
						|
}
 | 
						|
 | 
						|
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 ) }
 | 
						|
}
 | 
						|
 | 
						|
if ($cache) {
 | 
						|
    eval {
 | 
						|
        require Data::Printer;
 | 
						|
    } && eval {
 | 
						|
        print "\nDumping cache...\n\n";
 | 
						|
        Data::Printer::p $dev;
 | 
						|
    };
 | 
						|
}
 | 
						|
 | 
						|
#--------------------------------
 | 
						|
 | 
						|
sub test_global {
 | 
						|
    my $info   = shift;
 | 
						|
    my $method = shift;
 | 
						|
 | 
						|
    my $value = $info->$method();
 | 
						|
 | 
						|
    if ( !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 .= '...';
 | 
						|
    }
 | 
						|
    printf "%-20s %s \n", $method, $value;
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
sub test_fn {
 | 
						|
    my $info   = shift;
 | 
						|
    my $method = shift;
 | 
						|
 | 
						|
    my $results = $info->$method();
 | 
						|
 | 
						|
    # If accidentally called on a global, pass it along nicely.
 | 
						|
    if ( defined $results && !ref $results ) {
 | 
						|
	return test_global( $dev, $method );
 | 
						|
    }
 | 
						|
    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$/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;
 | 
						|
}
 | 
						|
 | 
						|
__END__
 | 
						|
 | 
						|
=head1 NAME
 | 
						|
 | 
						|
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 
 | 
						|
    -i|ignore   Ignore Net-SNMP configuration file
 | 
						|
    -m|mibdir   Directory containing MIB Files
 | 
						|
    -n|nobulk   Disable bulkwalk
 | 
						|
    -x|debug    Debugging flag
 | 
						|
    -k|cache    Dump cache (requires Data::Printer to be installed)
 | 
						|
    -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<-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<-debug>
 | 
						|
 | 
						|
Turns on SNMP::Info debug.
 | 
						|
 | 
						|
-debug
 | 
						|
 | 
						|
=item B<-cache>
 | 
						|
 | 
						|
Dumps the table and leaf cache at the end of running. Requires that the
 | 
						|
L<Data::Printer> module be installed, otherwise does nothing.
 | 
						|
 | 
						|
-cache
 | 
						|
 | 
						|
=item B<-help>
 | 
						|
 | 
						|
Print help message and exits.
 | 
						|
 | 
						|
=back
 | 
						|
 | 
						|
=head1 DESCRIPTION
 | 
						|
 | 
						|
B<test_class.pl> 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
 |