diff --git a/Netdisco/Changes b/Netdisco/Changes index 80e8c60b..45edf259 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -5,6 +5,7 @@ * Add IP Phones discovered through LLDP/CDP report * Add device/node/vlan/port specific search from Navbar * [#3] [#47] Device Neighbor Map can have max depth and VLAN filter + * [#31] get_community now supported [ENHANCEMENTS] diff --git a/Netdisco/lib/App/Netdisco/Manual/Configuration.pod b/Netdisco/lib/App/Netdisco/Manual/Configuration.pod index 9a3c1a63..1bff8bbf 100644 --- a/Netdisco/lib/App/Netdisco/Manual/Configuration.pod +++ b/Netdisco/lib/App/Netdisco/Manual/Configuration.pod @@ -344,6 +344,30 @@ this you usually configure a common context prefix, with Netdisco's default being "C" (i.e. C, C, etc). Add the C key to a stanza to override this. +=head3 C + +Value: String. Default none. + +An external program to run to get the community string for a given device. +This is useful if, for example, you have you devices already configured in +another NMS and you want to use that information instead of configuring +C. + +The strings "C<%IP%>" and "C<%HOST%>" are replaced by the IP address and the +hostname (or IP address if no hostname is known) of the system being +contacted. For example: + + get_community: '/path/to/my/program %IP%' + +The command must return output in the following form: + + community= + setCommunity= + +If the community string is not known for the given system, the command should +return no output and the community strings configured in C, +C, and C will be used instead. + =head3 C Value: Boolean. Default C. @@ -805,10 +829,6 @@ C =item * -C - -=item * - C =item * diff --git a/Netdisco/lib/App/Netdisco/Util/SNMP.pm b/Netdisco/lib/App/Netdisco/Util/SNMP.pm index 99d9c541..4dfc9dfc 100644 --- a/Netdisco/lib/App/Netdisco/Util/SNMP.pm +++ b/Netdisco/lib/App/Netdisco/Util/SNMP.pm @@ -241,11 +241,11 @@ sub _build_communities { my $snmp_comm_rw = eval { $device->community->snmp_comm_rw }; my @communities = (); - # first try last-known-good + # try last-known-good read push @communities, {read => 1, community => $device->snmp_comm} if defined $device->snmp_comm and $mode eq 'read'; - # first try last-known-good + # try last-known-good write push @communities, {write => 1, community => $snmp_comm_rw} if $snmp_comm_rw and $mode eq 'write'; @@ -299,9 +299,51 @@ sub _build_communities { }} @{setting('community_rw') || []}; } + # but first of all, use external command if configured + unshift @communities, _get_external_community($device, $mode) + if setting('get_community') and length setting('get_community'); + return @communities; } +sub _get_external_community { + my ($device, $mode) = @_; + my $cmd = setting('get_community'); + my $ip = $device->ip; + my $host = $device->dns || $ip; + + if (defined $cmd and length $cmd) { + # replace variables + $cmd =~ s/\%HOST\%/$host/egi; + $cmd =~ s/\%IP\%/$ip/egi; + + my $result = `$cmd`; + return () unless defined $result and length $result; + + my @lines = split (m/\n/, $result); + foreach my $line (@lines) { + if ($line =~ m/^community\s*=\s*(.*)\s*$/i) { + if (length $1 and $mode eq 'read') { + return map {{ + read => 1, + community => $_, + }} split(m/\s*,\s*/,$1); + } + } + elsif ($line =~ m/^setCommunity\s*=\s*(.*)\s*$/i) { + if (length $1 and $mode eq 'write') { + return map {{ + write => 1, + community => $_, + }} split(m/\s*,\s*/,$1); + } + } + } + } + + return (); +} + =head2 snmp_comm_reindex( $snmp, $device, $vlan ) Takes an established L instance and makes a fresh connection using