From 78554e55160f2b472cd665a3f8677278794b10b4 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Sat, 13 Apr 2013 19:07:44 +0100 Subject: [PATCH] refactor snmp_connect to handle versions and device classes --- .../lib/App/Netdisco/Util/DiscoverAndStore.pm | 2 +- Netdisco/lib/App/Netdisco/Util/SNMP.pm | 97 ++++++++++++++----- 2 files changed, 74 insertions(+), 25 deletions(-) diff --git a/Netdisco/lib/App/Netdisco/Util/DiscoverAndStore.pm b/Netdisco/lib/App/Netdisco/Util/DiscoverAndStore.pm index c7693d5d..60b80ca8 100644 --- a/Netdisco/lib/App/Netdisco/Util/DiscoverAndStore.pm +++ b/Netdisco/lib/App/Netdisco/Util/DiscoverAndStore.pm @@ -95,7 +95,7 @@ sub store_device { $device->$property( $snmp->$property ); } - $device->snmp_class( $snmp->class ); + $device->snmp_class( $snmp->device_type ); $device->last_discover(\'now()'); schema('netdisco')->txn_do(sub { diff --git a/Netdisco/lib/App/Netdisco/Util/SNMP.pm b/Netdisco/lib/App/Netdisco/Util/SNMP.pm index d233ac2c..6e62c85a 100644 --- a/Netdisco/lib/App/Netdisco/Util/SNMP.pm +++ b/Netdisco/lib/App/Netdisco/Util/SNMP.pm @@ -60,6 +60,30 @@ sub _snmp_connect_generic { # get device details from db my $device = get_device($ip); + # TODO: only supporing v2c at the moment + my %snmp_args = ( + DestHost => $device->ip, + Retries => (setting('snmpretries') || 2), + Timeout => (setting('snmptimeout') || 1000000), + MibDirs => [ _build_mibdirs() ], + IgnoreNetSNMPConf => 1, + Debug => ($ENV{INFO_TRACE} || 0), + ); + + # TODO: add version force support + # use existing SNMP version or try 2, 1 + my @versions = (($device->snmp_ver || setting('snmpver') || 2)); + push @versions, 1; + + # use existing or new device class + my @classes = ('SNMP::Info'); + if ($device->snmp_class) { + unshift @classes, $device->snmp_class; + } + else { + $snmp_args{AutoSpecity} = 1; + } + # get the community string(s) my $comm_type = pop; my @communities = @{ setting($comm_type) || []}; @@ -67,36 +91,61 @@ sub _snmp_connect_generic { if length $device->snmp_comm and length $comm_type and $comm_type eq 'community'; - # TODO: only supporing v2c at the moment - my %snmp_args = ( - DestHost => $device->ip, - Version => ($device->snmp_ver || setting('snmpver') || 2), - Retries => (setting('snmpretries') || 2), - Timeout => (setting('snmptimeout') || 1000000), - MibDirs => [ _build_mibdirs() ], - AutoSpecify => 1, - IgnoreNetSNMPConf => 1, - Debug => ($ENV{INFO_TRACE} || 0), - ); - my $info = undef; - my $last_comm = 0; - COMMUNITY: foreach my $c (@communities) { - next unless defined $c and length $c; - try { - $info = SNMP::Info->new(%snmp_args, Community => $c); - ++$last_comm if ( - $info - and (not defined $info->error) - and length $info->uptime - ); - }; - last COMMUNITY if $last_comm; + VERSION: foreach my $ver (@versions) { + next unless length $ver; + + CLASS: foreach my $class (@classes) { + next unless length $class; + + COMMUNITY: foreach my $comm (@communities) { + next unless length $comm; + + $info = _try_connect($ver, $class, $comm, \%snmp_args) + and last VERSION; + } + } } return $info; } +sub _try_connect { + my ($ver, $class, $comm, $snmp_args) = @_; + my $info = undef; + + try { + debug + sprintf '[%s] try_connect with ver: %s, class: %s, comm: %s', + $snmp_args->{DestHost}, $ver, $class, $comm; + eval "require $class"; + + $info = $class->new(%$snmp_args, Version => $ver, Community => $comm); + undef $info unless ( + (not defined $info->error) + and length $info->uptime + and ($info->layers or $info->description) + and $info->class + ); + + # first time a device is discovered, re-instantiate into specific class + if ($info and $info->device_type ne $class) { + $class = $info->device_type; + debug + sprintf '[%s] try_connect with ver: %s, new class: %s, comm: %s', + $snmp_args->{DestHost}, $ver, $class, $comm; + + eval "require $class"; + $info = $class->new(%$snmp_args, Version => $ver, Community => $comm); + } + } + catch { + debug $_; + }; + + return $info; +} + sub _build_mibdirs { return map { dir(setting('mibhome'), $_) } @{ setting('mibdirs') || [] };