#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Carp;
use Parse::CSV;
use SNMP;
use SNMP::Query::AsynchMulti;
#---------------------------------------------------------
my $csv_file = shift || die "Please specify a CSV file with SNMP host info!";
my @reqired_fields = qw(HOSTIP COMMUNITY SNMPVER SNMPPORT);
my @hosts = read_hosts_csv($csv_file, @reqired_fields);
# This object encapsulates the desired queries to run.
my $query = SNMP::Query::AsynchMulti->new();
foreach my $host (@hosts) {
my $sess = SNMP::Session->new(
DestHost => $host->{HOSTIP},
Community => $host->{COMMUNITY},
Version => $host->{SNMPVER},
RemotePort => $host->{SNMPPORT},
#Timeout => $host->{SNMP_TIMEOUT},
#Retries => $host->{SNMP_RETRIES},
);
my @varbinds = qw(
ifDescr ifInOctets ifOutOctets ifAlias ifType
ifName ifInErrors ifOutErrors ifSpeed
ifAdminStatus ifOperStatus
);
my $varlist = SNMP::VarList->new( map { [$_] } @varbinds );
$query->add({
Session => $sess,
VarBinds => $varlist,
QueryType => 'getbulk', # See POD for explanation...
MaxRepeaters => 20, # Additional options depend on
NonRepeaters => 0, # the QueryType...
});
}
$query->shuffle(); # Randomize order of queries...(not yet implemented)
# Run all the added queries with up to X
# asynchronous operations in-flight at any time.
foreach my $iter (1..10) {
sleep 30 unless $iter == 1;
my $results = $query->execute({ InFlight => 30 });
print Dumper $results;
}
exit;
#---------------------------------------------------------
# Read in the CSV file.
sub read_hosts_csv {
my $file = shift;
my @required_fields = @_;
# Parse entries from a CSV file into hashes hash
my $csv_parser = Parse::CSV->new(
file => $file,
fields => 'auto', # Use the first line as column headers,
# which become the hash keys.
);
my @node_cfg; # Return a reference to this
my $line_num = 0;
while ( my $line = $csv_parser->fetch() ) {
$line_num++;
my $error_flag = 0;
foreach my $field (@required_fields) {
if ( ! exists $line->{$field} ) {
$error_flag = 1;
carp "Missing field [$field] on line [$line_num] in CSV file [$file]";
}
}
croak "Terminating due to errors on line [$line_num] in CSV file [$file]"
if $error_flag;
push @node_cfg, $line;
}
if ( $csv_parser->errstr() ) {
croak "Fatal error parsing [$file]: " . $csv_parser->errstr();
}
return @node_cfg;
}
1;
__END__
####
NODE_NAME,NODE_TYPE,COMMUNITY,HOSTIP,SNMPPORT,SNMPVER
camel.mystuff.com,CPE-3810,foobar,10.1.15.62,161,2
somename.mystuff.com,CPE-2420,wheebaz,10.2.7.45,161,2
buhziuhuh.mystuff.com,CPE-2420,nipnop,10.2.7.40,161,2
salma-hayek.mystuff.com,CPE-2420,hummahumma,10.1.14.16,161,2
zippy.mystuff.com,CPE-2420,woo!woo,10.2.6.41,161,2
napoleon.mystuff.com,CPE-2420,vote4pedro,10.2.7.35,161,2
wjul.mystuff.com,CPE-3810,hoosurdaddy,10.1.15.72,161,2
telephone.mystuff.com,CPE-3660,yipyipyip,10.1.15.42,161,2
brrrrrring.mystuff.com,CPE-3660,uuuuuh-huh,10.1.15.73,161,2
##
##
#!/usr/bin/perl
package SNMP::Query::AsynchMulti;
use strict;
use warnings;
use Carp;
use SNMP;
sub new {
my $class = shift;
my $self = bless {}, $class;
$self->{query_stack} = [];
$self->{results} = [];
$self->{max_in_flight} = 10;
$self->{current_in_flight} = 0;
$self->{total_query_count} = 0;
return $self;
}
sub add {
my $self = shift;
my $params = shift;
my $query_stack = $self->{query_stack};
my $sess = $params->{Session} || croak "Session parameter must be specified";
my $varbinds = $params->{VarBinds} || croak "VarBinds parameter must be specified";
my $query_type = $params->{QueryType} || 'getbulk';
if ($query_type eq 'getbulk') {
my $non_repeaters = $params->{NonRepeaters} || 0;
my $max_repeaters = $params->{MaxRepeaters} || 10;
my $query = $self->_make_getbulk_query($sess, $varbinds, $non_repeaters, $max_repeaters);
push @$query_stack, $query;
}
else {
croak "Attempt to add using unknown query type: $query_type\n";
}
return 1;
}
sub _make_getbulk_query {
my $self = shift;
my ($sess,$varbinds,$non_repeaters,$max_repeaters) = @_;
return sub {
my $callback = sub {
my $bulkwalk_results = shift;
push @{$self->{results}}, "Query Complete", $bulkwalk_results;
$self->{current_in_flight}--;
warn "Finished Query\n";
if (scalar @{$self->{query_stack}}) {
my $next_query = pop @{$self->{query_stack}};
return $next_query->();
}
return SNMP::finish() if $self->{current_in_flight} <= 0;
};
$self->{current_in_flight}++;
$self->{total_query_count}++;
warn "Started query $self->{total_query_count}\n";
return $sess->bulkwalk($non_repeaters, $max_repeaters, $varbinds, [$callback]);
};
}
sub shuffle {} # TODO implement shuffle with List::Util or something
sub execute {
my $self = shift;
my $params = shift;
@{$self->{results}} = ();
$self->{current_in_flight} = 0;
my $max_in_flight = $params->{InFlight} || $self->{max_in_flight};
my $query_stack_ref = $self->{query_stack};
my @query_stack_copy = @{$self->{query_stack}};
while (scalar @$query_stack_ref) {
my $query = pop @$query_stack_ref;
$query->();
last if $self->{current_in_flight} >= $max_in_flight;
}
SNMP::MainLoop();
#use Data::Dumper; warn Dumper $self->{query_stack}, \@query_stack_copy; exit;
$self->{query_stack} = \@query_stack_copy;
return \@{$self->{results}};
}
1;
__END__