From fdafbb735e3beb018ccc80a4aeb0bf477ff3dc5e Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Mon, 11 Mar 2019 17:39:53 +0000 Subject: [PATCH 01/15] test compilation of all scripts and modules passes --- Build.PL | 1 + xt/00-compile.t | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 xt/00-compile.t diff --git a/Build.PL b/Build.PL index 3d7fdeb6..fe0e4bba 100644 --- a/Build.PL +++ b/Build.PL @@ -96,6 +96,7 @@ Module::Build->new( test_requires => { 'Test::More' => '1.302083', 'Env::Path' => '0', + 'Test::Compile' => '0', 'Test::File::ShareDir::Dist' => '0', }, script_files => [ diff --git a/xt/00-compile.t b/xt/00-compile.t new file mode 100644 index 00000000..307058af --- /dev/null +++ b/xt/00-compile.t @@ -0,0 +1,30 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +BEGIN { + use FindBin; + FindBin::again(); + + use Path::Class; + + # stuff useful locations into @INC and $PATH + unshift @INC, + dir($FindBin::RealBin)->parent->subdir('lib')->stringify, + dir($FindBin::RealBin, 'lib')->stringify; +} + +# for netdisco app config +use App::Netdisco; +use Test::Compile; + +my $test = Test::Compile->new(); + +my @plfiles = grep {$_ !~ m/(?:sshcollector|graph)/i} $test->all_pl_files(); +my @pmfiles = grep {$_ !~ m/(?:sshcollector|graph)/i} $test->all_pm_files(); + +$test->ok($test->pl_file_compiles($_), "$_ compiles") for @plfiles; +$test->ok($test->pm_file_compiles($_), "$_ compiles") for @pmfiles; + +$test->done_testing(); From 15c132a094215fe919e9d45ae3e7fea25e0dac34 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Mon, 11 Mar 2019 17:49:13 +0000 Subject: [PATCH 02/15] Revert "test compilation of all scripts and modules passes" This reverts commit fdafbb735e3beb018ccc80a4aeb0bf477ff3dc5e. --- Build.PL | 1 - xt/00-compile.t | 30 ------------------------------ 2 files changed, 31 deletions(-) delete mode 100644 xt/00-compile.t diff --git a/Build.PL b/Build.PL index fe0e4bba..3d7fdeb6 100644 --- a/Build.PL +++ b/Build.PL @@ -96,7 +96,6 @@ Module::Build->new( test_requires => { 'Test::More' => '1.302083', 'Env::Path' => '0', - 'Test::Compile' => '0', 'Test::File::ShareDir::Dist' => '0', }, script_files => [ diff --git a/xt/00-compile.t b/xt/00-compile.t deleted file mode 100644 index 307058af..00000000 --- a/xt/00-compile.t +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env perl - -use strict; -use warnings; - -BEGIN { - use FindBin; - FindBin::again(); - - use Path::Class; - - # stuff useful locations into @INC and $PATH - unshift @INC, - dir($FindBin::RealBin)->parent->subdir('lib')->stringify, - dir($FindBin::RealBin, 'lib')->stringify; -} - -# for netdisco app config -use App::Netdisco; -use Test::Compile; - -my $test = Test::Compile->new(); - -my @plfiles = grep {$_ !~ m/(?:sshcollector|graph)/i} $test->all_pl_files(); -my @pmfiles = grep {$_ !~ m/(?:sshcollector|graph)/i} $test->all_pm_files(); - -$test->ok($test->pl_file_compiles($_), "$_ compiles") for @plfiles; -$test->ok($test->pm_file_compiles($_), "$_ compiles") for @pmfiles; - -$test->done_testing(); From a1383251753bee9962770cdb90c1443b64257067 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Mon, 11 Mar 2019 21:34:18 +0000 Subject: [PATCH 03/15] travis test all branches --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index af946ef6..31f15896 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,10 +6,10 @@ addons: - phantomjs hosts: - localhost -branches: - only: - - /^2\.\d{6}$/ - - 'master' +#branches: +# only: +# - /^2\.\d{6}$/ +# - 'master' install: true script: | perl Build.PL && \ From 65f695410e7b4dea2a451d04c37a9234edc300b6 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Tue, 12 Mar 2019 13:02:35 +0000 Subject: [PATCH 04/15] test compilation of all scripts and modules (#537) * test compilation of all scripts and modules passes * try adding NetSNMP::default_store * try adding NetSNMP::default_store * travis test all branches * make Configuration.pm safe for tests * remove dep * try adding net-snmp * dist: xenial * try building Net-SNMP locally * no need for Try::Tiny * allow test to pass for DPP:p * better testing setup for session cookies * yay! working compile tests for ALL! --- .travis.yml | 11 +++---- Build.PL | 1 + lib/App/Netdisco/Web.pm | 10 +++++-- lib/App/Netdisco/Worker/Plugin/DumpConfig.pm | 3 +- xt/00-compile.t | 30 ++++++++++++++++++++ 5 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 xt/00-compile.t diff --git a/.travis.yml b/.travis.yml index 31f15896..297e8260 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,11 +6,12 @@ addons: - phantomjs hosts: - localhost -#branches: -# only: -# - /^2\.\d{6}$/ -# - 'master' -install: true +branches: + only: + - /^2\.\d{6}$/ + - 'master' +install: + - cpanm --quiet --notest PkgConfig Test::CChecker Alien::zlib::Static Alien::OpenSSL::Static Alien::SNMP script: | perl Build.PL && \ ./Build && \ diff --git a/Build.PL b/Build.PL index 3d7fdeb6..fe0e4bba 100644 --- a/Build.PL +++ b/Build.PL @@ -96,6 +96,7 @@ Module::Build->new( test_requires => { 'Test::More' => '1.302083', 'Env::Path' => '0', + 'Test::Compile' => '0', 'Test::File::ShareDir::Dist' => '0', }, script_files => [ diff --git a/lib/App/Netdisco/Web.pm b/lib/App/Netdisco/Web.pm index 901eee0d..d95d1025 100644 --- a/lib/App/Netdisco/Web.pm +++ b/lib/App/Netdisco/Web.pm @@ -66,9 +66,13 @@ if (setting('template_paths') and ref [] eq ref setting('template_paths')) { # load cookie key from database setting('session_cookie_key' => undef); -my $sessions = schema('netdisco')->resultset('Session'); -my $skey = $sessions->find({id => 'dancer_session_cookie_key'}); -setting('session_cookie_key' => $skey->get_column('a_session')) if $skey; +setting('session_cookie_key' => 'this_is_for_testing_only') + if $ENV{HARNESS_ACTIVE}; +eval { + my $sessions = schema('netdisco')->resultset('Session'); + my $skey = $sessions->find({id => 'dancer_session_cookie_key'}); + setting('session_cookie_key' => $skey->get_column('a_session')) if $skey; +}; Dancer::Session::Cookie::init(session); # workaround for https://github.com/PerlDancer/Dancer/issues/935 diff --git a/lib/App/Netdisco/Worker/Plugin/DumpConfig.pm b/lib/App/Netdisco/Worker/Plugin/DumpConfig.pm index 3c57288a..d37e07a4 100644 --- a/lib/App/Netdisco/Worker/Plugin/DumpConfig.pm +++ b/lib/App/Netdisco/Worker/Plugin/DumpConfig.pm @@ -11,7 +11,8 @@ register_worker({ phase => 'main' }, sub { my $extra = $job->extra; my $config = config(); - p ($extra ? $config->{$extra} : $config); + my $dump = ($extra ? $config->{$extra} : $config); + p $dump; return Status->done('Dumped config'); }); diff --git a/xt/00-compile.t b/xt/00-compile.t new file mode 100644 index 00000000..307058af --- /dev/null +++ b/xt/00-compile.t @@ -0,0 +1,30 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +BEGIN { + use FindBin; + FindBin::again(); + + use Path::Class; + + # stuff useful locations into @INC and $PATH + unshift @INC, + dir($FindBin::RealBin)->parent->subdir('lib')->stringify, + dir($FindBin::RealBin, 'lib')->stringify; +} + +# for netdisco app config +use App::Netdisco; +use Test::Compile; + +my $test = Test::Compile->new(); + +my @plfiles = grep {$_ !~ m/(?:sshcollector|graph)/i} $test->all_pl_files(); +my @pmfiles = grep {$_ !~ m/(?:sshcollector|graph)/i} $test->all_pm_files(); + +$test->ok($test->pl_file_compiles($_), "$_ compiles") for @plfiles; +$test->ok($test->pm_file_compiles($_), "$_ compiles") for @pmfiles; + +$test->done_testing(); From b9218d91c8f3cb17ce1a106386ec7f71dcdc3744 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Tue, 12 Mar 2019 13:13:06 +0000 Subject: [PATCH 05/15] Support for external command to provide device_auth stanza (#532) * separate out generic device auth to DeviceAuth module * change config name to get_credentials * add debug lines and tested --- lib/App/Netdisco/Configuration.pm | 5 +- lib/App/Netdisco/Util/DeviceAuth.pm | 163 ++++++++++++++++++++++++++++ lib/App/Netdisco/Util/SNMP.pm | 116 +------------------- share/config.yml | 2 +- 4 files changed, 170 insertions(+), 116 deletions(-) create mode 100644 lib/App/Netdisco/Util/DeviceAuth.pm diff --git a/lib/App/Netdisco/Configuration.pm b/lib/App/Netdisco/Configuration.pm index 90cdc5ac..9ddd1d0f 100644 --- a/lib/App/Netdisco/Configuration.pm +++ b/lib/App/Netdisco/Configuration.pm @@ -1,7 +1,7 @@ package App::Netdisco::Configuration; use App::Netdisco::Environment; -use App::Netdisco::Util::SNMP (); +use App::Netdisco::Util::DeviceAuth (); use Dancer ':script'; use Path::Class 'dir'; @@ -84,7 +84,8 @@ if ((setting('snmp_auth') and 0 == scalar @{ setting('snmp_auth') }) config->{'community_rw'} = [ @{setting('community_rw')}, 'private' ]; } # fix up device_auth (or create it from old snmp_auth and community settings) -config->{'device_auth'} = [ App::Netdisco::Util::SNMP::fixup_device_auth() ]; +config->{'device_auth'} + = [ App::Netdisco::Util::DeviceAuth::fixup_device_auth() ]; # defaults for workers setting('workers')->{queue} ||= 'PostgreSQL'; diff --git a/lib/App/Netdisco/Util/DeviceAuth.pm b/lib/App/Netdisco/Util/DeviceAuth.pm new file mode 100644 index 00000000..bb7f79f5 --- /dev/null +++ b/lib/App/Netdisco/Util/DeviceAuth.pm @@ -0,0 +1,163 @@ +package App::Netdisco::Util::DeviceAuth; + +use Dancer qw/:syntax :script/; +use App::Netdisco::Util::DNS 'hostname_from_ip'; + +use Try::Tiny; + +use base 'Exporter'; +our @EXPORT = (); +our @EXPORT_OK = qw/ + fixup_device_auth get_external_credentials +/; +our %EXPORT_TAGS = (all => \@EXPORT_OK); + +=head1 NAME + +App::Netdisco::Util::DeviceAuth + +=head1 DESCRIPTION + +Helper functions for device authentication. + +There are no default exports, however the C<:all> tag will export all +subroutines. + +=head1 EXPORT_OK + +=head2 fixup_device_auth + +Rebuilds the C config with missing defaults and other fixups for +config changes over time. Returns a list which can replace C. + +=cut + +sub fixup_device_auth { + my $config = (setting('snmp_auth') || setting('device_auth')); + my @new_stanzas = (); + + # new style snmp config + foreach my $stanza (@$config) { + # user tagged + my $tag = ''; + if (1 == scalar keys %$stanza) { + $tag = (keys %$stanza)[0]; + $stanza = $stanza->{$tag}; + + # corner case: untagged lone community + if ($tag eq 'community') { + $tag = $stanza; + $stanza = {community => $tag}; + } + } + + # defaults + $stanza->{tag} ||= $tag; + $stanza->{read} = 1 if !exists $stanza->{read}; + $stanza->{no} ||= []; + $stanza->{only} ||= ['any']; + + die "error: config: snmpv2 community in device_auth must be single item, not list\n" + if ref $stanza->{community}; + + die "error: config: stanza in device_auth must have a tag\n" + if not $stanza->{tag} and exists $stanza->{user}; + + push @new_stanzas, $stanza + } + + # legacy config + # note: read strings tried before write + # note: read-write is no longer used for read operations + + push @new_stanzas, map {{ + read => 1, write => 0, + no => [], only => ['any'], + community => $_, + }} @{setting('community') || []}; + + push @new_stanzas, map {{ + write => 1, read => 0, + no => [], only => ['any'], + community => $_, + }} @{setting('community_rw') || []}; + + foreach my $stanza (@new_stanzas) { + $stanza->{driver} ||= 'snmp' + if exists $stanza->{community} + or exists $stanza->{user}; + } + + return @new_stanzas; +} + +=head2 get_external_credentials( $device, $mode ) + +Runs a command to gather SNMP credentials or a C stanza. + +Mode can be C or C and defaults to 'read'. + +=cut + +sub get_external_credentials { + my ($device, $mode) = @_; + my $cmd = (setting('get_credentials') || setting('get_community')); + my $ip = $device->ip; + my $host = ($device->dns || hostname_from_ip($ip) || $ip); + $mode ||= 'read'; + + if (defined $cmd and length $cmd) { + # replace variables + $cmd =~ s/\%MODE\%/$mode/egi; + $cmd =~ s/\%HOST\%/$host/egi; + $cmd =~ s/\%IP\%/$ip/egi; + + my $result = `$cmd`; # BACKTICKS + 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') { + debug sprintf '[%s] external read credentials added', + $device->ip; + + return map {{ + read => 1, + only => [$device->ip], + community => $_, + }} split(m/\s*,\s*/,$1); + } + } + elsif ($line =~ m/^setCommunity\s*=\s*(.*)\s*$/i) { + if (length $1 and $mode eq 'write') { + debug sprintf '[%s] external write credentials added', + $device->ip; + + return map {{ + write => 1, + only => [$device->ip], + community => $_, + }} split(m/\s*,\s*/,$1); + } + } + else { + my $stanza = undef; + try { + $stanza = from_json( $line ); + debug sprintf '[%s] external credentials stanza added', + $device->ip; + } + catch { + info sprintf '[%s] error! failed to parse external credentials stanza', + $device->ip; + }; + return $stanza if ref $stanza; + } + } + } + + return (); +} + +true; diff --git a/lib/App/Netdisco/Util/SNMP.pm b/lib/App/Netdisco/Util/SNMP.pm index 3fa6c0a6..ba5b54d6 100644 --- a/lib/App/Netdisco/Util/SNMP.pm +++ b/lib/App/Netdisco/Util/SNMP.pm @@ -1,14 +1,11 @@ package App::Netdisco::Util::SNMP; use Dancer qw/:syntax :script/; -use App::Netdisco::Util::DNS 'hostname_from_ip'; -use App::Netdisco::Util::Permission ':all'; +use App::Netdisco::Util::DeviceAuth 'get_external_credentials'; use base 'Exporter'; our @EXPORT = (); -our @EXPORT_OK = qw/ - fixup_device_auth get_communities snmp_comm_reindex -/; +our @EXPORT_OK = qw/ get_communities snmp_comm_reindex /; our %EXPORT_TAGS = (all => \@EXPORT_OK); =head1 NAME @@ -24,72 +21,6 @@ subroutines. =head1 EXPORT_OK -=head2 fixup_device_auth - -Rebuilds the C config with missing defaults and other fixups for -config changes over time. Returns a list which can replace C. - -=cut - -sub fixup_device_auth { - my $config = (setting('snmp_auth') || setting('device_auth')); - my @new_stanzas = (); - - # new style snmp config - foreach my $stanza (@$config) { - # user tagged - my $tag = ''; - if (1 == scalar keys %$stanza) { - $tag = (keys %$stanza)[0]; - $stanza = $stanza->{$tag}; - - # corner case: untagged lone community - if ($tag eq 'community') { - $tag = $stanza; - $stanza = {community => $tag}; - } - } - - # defaults - $stanza->{tag} ||= $tag; - $stanza->{read} = 1 if !exists $stanza->{read}; - $stanza->{no} ||= []; - $stanza->{only} ||= ['any']; - - die "error: config: snmpv2 community in device_auth must be single item, not list\n" - if ref $stanza->{community}; - - die "error: config: stanza in device_auth must have a tag\n" - if not $stanza->{tag} and exists $stanza->{user}; - - push @new_stanzas, $stanza - } - - # legacy config - # note: read strings tried before write - # note: read-write is no longer used for read operations - - push @new_stanzas, map {{ - read => 1, write => 0, - no => [], only => ['any'], - community => $_, - }} @{setting('community') || []}; - - push @new_stanzas, map {{ - write => 1, read => 0, - no => [], only => ['any'], - community => $_, - }} @{setting('community_rw') || []}; - - foreach my $stanza (@new_stanzas) { - $stanza->{driver} ||= 'snmp' - if exists $stanza->{community} - or exists $stanza->{user}; - } - - return @new_stanzas; -} - =head2 get_communities( $device, $mode ) Takes the current C setting and pushes onto the front of the list @@ -106,8 +37,7 @@ sub get_communities { my @communities = (); # first of all, use external command if configured - push @communities, _get_external_community($device, $mode) - if setting('get_community') and length setting('get_community'); + push @communities, get_external_credentials($device, $mode); # last known-good by tag my $tag_name = 'snmp_auth_tag_'. $mode; @@ -145,46 +75,6 @@ sub get_communities { return ( @communities, @$config ); } -sub _get_external_community { - my ($device, $mode) = @_; - my $cmd = setting('get_community'); - my $ip = $device->ip; - my $host = ($device->dns || hostname_from_ip($ip) || $ip); - - if (defined $cmd and length $cmd) { - # replace variables - $cmd =~ s/\%HOST\%/$host/egi; - $cmd =~ s/\%IP\%/$ip/egi; - - my $result = `$cmd`; # BACKTICKS - 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, - only => [$device->ip], - 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, - only => [$device->ip], - 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 diff --git a/share/config.yml b/share/config.yml index 24b31d66..9767019a 100644 --- a/share/config.yml +++ b/share/config.yml @@ -216,7 +216,7 @@ device_identity: [] community: [] community_rw: [] device_auth: [] -get_community: "" +get_credentials: "" bulkwalk_off: false bulkwalk_no: [] bulkwalk_repeaters: 20 From d44a8f56ea25496d460fb7708dd5436dd61abcb8 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Tue, 12 Mar 2019 18:50:24 +0000 Subject: [PATCH 06/15] Integrate netdisco-sshcollector into Worker::Plugin architecture (#489) (#535) * update changes and SNMP::Info dep * Integrate netdisco-sshcollector into Worker::Plugin architecture (#489) * Initial integration of sshcollector into Worker::Plugin architecture * add NodesBySSH.pm * update Build.PL and config.yml to integrate the new module * Further integration of sshcollector into Worker::Plugin architecture * added App::Netdisco::Transport::CLI loosely based on ::SNMP counterpart * switched to the more prevalent two-space tabs style * removed various TBD items, some new ones * Further steps to integration of sshcollector into Worker::Plugin architecture * cleaned up code * added various error handling * warning for bin/netdisco-sshcollector deprecation * device_auth allows passing master_opts to Net::OpenSSH * netdisco-do -D also toggles Net::OpenSSH debug * Merged NodesBySSH.pm into Nodes.pm * see https://github.com/netdisco/netdisco/pull/489#pullrequestreview-205603516 * Further integration of sshcollector into Worker::Plugin architecture * add snmp_arpnip_also option to sshcollector device_auth * cleanup code * Remove big TBD: comment from CLI.pm as doc is updated now * add transport/cli.pm to manifest * revert some changes to allow simpler merging * silent exit legacy script unless explicitly requested * move ssh code into Transport, part one * rewrite the CLI transport to provide an API * merge in og-get_external_credentials Squashed commit of the following: commit 3fe8f383a791055f8ef4d463d25af6640730ceef Author: Oliver Gorwits Date: Mon Mar 11 17:07:42 2019 +0000 add debug lines and tested commit 3249739e4205eb35ab5841f31b05a4ed34d55475 Author: Oliver Gorwits Date: Mon Mar 11 16:54:11 2019 +0000 change config name to get_credentials commit e78558397abf4b825f6b0a943e630133060565f2 Author: Oliver Gorwits Date: Mon Mar 11 16:51:11 2019 +0000 separate out generic device auth to DeviceAuth module commit 249f05165fd25bdd43802a95c523f0486fc013de Author: Oliver Gorwits Date: Wed Mar 6 18:43:31 2019 +0000 release 2.040007 commit e3af64df77613b98c5efde9d5e7381ab0f5de52d Author: Oliver Gorwits Date: Wed Mar 6 18:42:47 2019 +0000 #521-redux fix wifi date search commit 48857ae3002536b469acb678292981377b960b65 Author: Oliver Gorwits Date: Mon Mar 4 12:03:31 2019 +0000 release 2.040006 commit e09dab53622960bee715d9d423ed2dee91b2e36c Author: Oliver Gorwits Date: Mon Mar 4 11:39:12 2019 +0000 #527 update List::MoreUtils version requirement commit 6e7de3fff3719720da72db76801c9e2e45b5be78 Author: Oliver Gorwits Date: Mon Mar 4 09:59:41 2019 +0000 release 2.040005 commit 0c98318a4508d9c91a8d1182b38e556454f9c9fa Author: Oliver Gorwits Date: Mon Mar 4 09:57:18 2019 +0000 #526 fix discover syntax bug commit e9efc45182f590ea94ddd2928e8156162d022b0d Author: Oliver Gorwits Date: Sun Mar 3 14:56:48 2019 +0000 release 2.040004 commit 6cdfd80d10975c22a9aa2050a02e2ed45dbad3c6 Author: Oliver Gorwits Date: Sun Mar 3 14:34:00 2019 +0000 allow undiscovered neighbors report to use discover_{waps,phones} setting commit ac381e080235b2efc0878b4ccfaa5c2d6901b2ff Author: Oliver Gorwits Date: Sun Mar 3 14:13:20 2019 +0000 #506 was a red herring commit b83e614c851beafd68d131999698023c5380338c Author: Oliver Gorwits Date: Sun Mar 3 13:00:36 2019 +0000 make discover_{phones,waps} work with LLDP capabilities as well commit 189d234b55c01b8e7def428bed9c4be35022ea59 Author: Oliver Gorwits Date: Sun Mar 3 12:47:38 2019 +0000 check discover_no_type and friends earlier on in neighbors list build commit 9c956466f3bf2e799412fef5b61966fb2878bc49 Author: Oliver Gorwits Date: Sun Mar 3 12:32:07 2019 +0000 also update default config for new discover_phones and discover_waps settings commit 09d29954d211ad1e6c1911fb4d43df8980a00bae Author: Oliver Gorwits Date: Sun Mar 3 12:26:50 2019 +0000 #512 fix regression in phone/wap discovery exclusion commit 2bae91f1b669e2901ebcb59696fdaa562c0396b7 Author: Oliver Gorwits Date: Sun Mar 3 12:01:34 2019 +0000 rename match_devicetype() to match_to_setting() commit 57cb6ddb707b938b8a5c0d39a52b9e4c8a8892da Author: Oliver Gorwits Date: Sun Mar 3 09:19:39 2019 +0000 fix for over-eager fix to #506 commit ef560fb59aebf4f7cf64487931d41b6f5aa83d92 Author: Oliver Gorwits Date: Sat Mar 2 22:41:40 2019 +0000 #506 relax device renumber so it works for an alias commit 7a8bcb094e4d48dd0d900d275ca5ce781ddb42ba Author: Oliver Gorwits Date: Sat Mar 2 22:23:39 2019 +0000 #521 Search Node Date Range not working commit a643820a6200a7439724158a6817f3858732050c Author: Oliver Gorwits Date: Sat Mar 2 21:54:27 2019 +0000 #428 Port-Channels not showing in netmap commit 5ba5bcd295230cc77be42255836c380e99e54278 Merge: e7aacddb a1f95028 Author: Oliver Gorwits Date: Sat Mar 2 20:04:11 2019 +0000 Merge branch 'master' of github.com:netdisco/netdisco commit e7aacddbc615a48e5dd204b9dc32a5deadbdefea Author: Oliver Gorwits Date: Sat Mar 2 20:01:05 2019 +0000 #498 Map with VLAN filter omits unconnected devices commit a1f95028caf3d59133dac0bb43fd9d26c44a9dfb Author: nick n <39005454+inphobia@users.noreply.github.com> Date: Sat Mar 2 19:54:22 2019 +0100 catch up with changes noticed that rc-sshcollector-core received updates to changes, add them here as well. didn't mention #499 & #522 commit ce1b847ceabb3cb8ec6bac370071d55acd40dc48 Author: Oliver Gorwits Date: Sat Mar 2 18:47:44 2019 +0000 fix bug showing no nodes when only one matches in netmap commit 78e30a7926dbec941860420348c917ae823146f3 Author: Oliver Gorwits Date: Sat Mar 2 16:28:15 2019 +0000 #500 filtering in device/ports on native vlan duplicates entries commit 9952f0c6c723359c7c1e29abfc0dcad30a52c083 Author: Oliver Gorwits Date: Sat Mar 2 15:02:12 2019 +0000 #499 netdisco-do renumber reports wrong ip (inphobia) commit ca3fd8f466f144f76a9df6d760a5d8f34ae14621 Author: Oliver Gorwits Date: Sat Mar 2 15:00:18 2019 +0000 #505 device renumber should update device port properties and device skips commit 1265bc8470911d90c7c446c64976207c3285a151 Author: Oliver Gorwits Date: Sat Mar 2 14:52:21 2019 +0000 #520 catch slave ports defined without a master commit d4c7579c101d693827da2f3fad533ad725f97ba0 Author: Oliver Gorwits Date: Sat Mar 2 14:47:49 2019 +0000 #522 TypeAhead.pm can reference empty data (inphobia) commit 77decc23b73cbcda0cd0516fdc73972cda622a0b Author: Oliver Gorwits Date: Sat Mar 2 14:45:37 2019 +0000 #514 inconsistent results in ip inventory (inphobia) commit 3f211650b89e58c80d862632faf6c9529c6f8b27 Author: nick n <39005454+inphobia@users.noreply.github.com> Date: Fri Mar 1 12:34:42 2019 +0100 last pieces for db schema upgrade last piece of #510 * import legacy sshcollector config * add default use_legacy_sshcollector config * remove unneeded deps * various fixes and now tested * enable sshcollector platform tests --- Build.PL | 4 +- bin/netdisco-sshcollector | 3 + lib/App/Netdisco/Configuration.pm | 1 + lib/App/Netdisco/Transport/CLI.pm | 115 ++++++++++++++++++ lib/App/Netdisco/Transport/SNMP.pm | 2 +- lib/App/Netdisco/Util/DeviceAuth.pm | 18 ++- .../Netdisco/Worker/Plugin/Arpnip/Nodes.pm | 49 +++++++- share/config.yml | 1 + xt/00-compile.t | 4 +- 9 files changed, 187 insertions(+), 10 deletions(-) create mode 100644 lib/App/Netdisco/Transport/CLI.pm diff --git a/Build.PL b/Build.PL index fe0e4bba..9f20ce47 100644 --- a/Build.PL +++ b/Build.PL @@ -37,6 +37,7 @@ Module::Build->new( 'Dancer::Plugin::Auth::Extensible' => '0.30', 'Dancer::Plugin::Passphrase' => '2.0.1', 'Dancer::Session::Cookie' => '0.27', + 'Expect' => '0', 'File::ShareDir' => '1.03', 'File::Slurper' => '0.009', 'Guard' => '1.022', @@ -54,6 +55,7 @@ Module::Build->new( 'Net::Domain' => '1.23', 'Net::DNS' => '0.72', 'Net::LDAP' => '0', + 'Net::OpenSSH' => '0', 'NetAddr::MAC' => '0.93', 'NetAddr::IP' => '4.068', 'Opcode' => '1.07', @@ -90,8 +92,6 @@ Module::Build->new( recommends => { 'Graph' => '0', 'GraphViz' => '0', - 'Net::OpenSSH' => '0', - 'Expect' => '0', }, test_requires => { 'Test::More' => '1.302083', diff --git a/bin/netdisco-sshcollector b/bin/netdisco-sshcollector index 29c0e154..0f42f7c0 100755 --- a/bin/netdisco-sshcollector +++ b/bin/netdisco-sshcollector @@ -74,6 +74,9 @@ $ENV{DBIC_TRACE} ||= $sqltrace; # reconfigure logging to force console output Dancer::Logger->init('console', $CONFIG); +# silent exit unless explicitly requested +exit(0) unless setting('use_legacy_sshcollector'); + if ($opensshdebug){ $Net::OpenSSH::debug = ~0; } diff --git a/lib/App/Netdisco/Configuration.pm b/lib/App/Netdisco/Configuration.pm index 9ddd1d0f..cf076069 100644 --- a/lib/App/Netdisco/Configuration.pm +++ b/lib/App/Netdisco/Configuration.pm @@ -84,6 +84,7 @@ if ((setting('snmp_auth') and 0 == scalar @{ setting('snmp_auth') }) config->{'community_rw'} = [ @{setting('community_rw')}, 'private' ]; } # fix up device_auth (or create it from old snmp_auth and community settings) +# also imports legacy sshcollcetor config config->{'device_auth'} = [ App::Netdisco::Util::DeviceAuth::fixup_device_auth() ]; diff --git a/lib/App/Netdisco/Transport/CLI.pm b/lib/App/Netdisco/Transport/CLI.pm new file mode 100644 index 00000000..6f865c7b --- /dev/null +++ b/lib/App/Netdisco/Transport/CLI.pm @@ -0,0 +1,115 @@ +package App::Netdisco::Transport::CLI; + +use Dancer qw/:syntax :script/; + +use App::Netdisco::Util::Device 'get_device'; +use Module::Load (); +use Net::OpenSSH; +use Try::Tiny; + +use base 'Dancer::Object::Singleton'; + +=head1 NAME + +App::Netdisco::Transport::CLI + +=head1 DESCRIPTION + +Returns an object which has an active SSH connection which can be used +for some actions such as arpnip. + + my $cli = App::Netdisco::Transport::CLI->session_for( ... ); + +=cut + +__PACKAGE__->attributes(qw/ sessions /); + +sub init { + my ( $class, $self ) = @_; + $self->sessions( {} ); + return $self; +} + +=head1 session_for( $ip ) + +Given an IP address, returns an object instance configured for and connected +to that device. + +Returns C if the connection fails. + +=cut + +{ + package MySession; + use Moo; + + has 'ssh' => ( is => 'rw' ); + has 'auth' => ( is => 'rw' ); + has 'host' => ( is => 'rw' ); + has 'platform' => ( is => 'rw' ); + + sub arpnip { + my $self = shift; + $self->platform->arpnip(@_, $self->host, $self->ssh, $self->auth); + } +} + +sub session_for { + my ($class, $ip) = @_; + + my $device = get_device($ip) or return undef; + my $sessions = $class->instance->sessions or return undef; + + return $sessions->{$device->ip} if exists $sessions->{$device->ip}; + debug sprintf 'cli session cache warm: [%s]', $device->ip; + + my $auth = (setting('device_auth') || []); + if (1 != scalar @$auth) { + error sprintf " [%s] require only one matching auth stanza", $device->ip; + return undef; + } + $auth = $auth->[0]; + + my @master_opts = qw(-o BatchMode=no); + push(@master_opts, @{$auth->{ssh_master_opts}}) + if $auth->{ssh_master_opts}; + + $Net::OpenSSH::debug = $ENV{SSH_TRACE}; + my $ssh = Net::OpenSSH->new( + $device->ip, + user => $auth->{username}, + password => $auth->{password}, + timeout => 30, + async => 0, + default_stderr_file => '/dev/null', + master_opts => \@master_opts + ); + + if ($ssh->error) { + error sprintf " [%s] ssh connection error [%s]", $device->ip, $ssh->error; + return undef; + } + elsif (! $ssh) { + error sprintf " [%s] Net::OpenSSH instantiation error", $device->ip; + return undef; + } + + my $platform = "App::Netdisco::SSHCollector::Platform::" . $auth->{platform}; + my $happy = false; + try { + Module::Load::load $platform; + $happy = true; + } catch { error $_ }; + return unless $happy; + + my $sess = MySession->new( + ssh => $ssh, + auth => $auth, + host => $device->ip, + platform => $platform->new(), + ); + + return ($sessions->{$device->ip} = $sess); +} + +true; diff --git a/lib/App/Netdisco/Transport/SNMP.pm b/lib/App/Netdisco/Transport/SNMP.pm index 36cf57b3..f342155b 100644 --- a/lib/App/Netdisco/Transport/SNMP.pm +++ b/lib/App/Netdisco/Transport/SNMP.pm @@ -25,7 +25,7 @@ App::Netdisco::Transport::SNMP Singleton for SNMP connections. Returns cached L instance for a given device IP, or else undef. All methods are class methods, for example: - App::Netdisco::Transport::SNMP->reader_for( ... ); + my $snmp = App::Netdisco::Transport::SNMP->reader_for( ... ); =cut diff --git a/lib/App/Netdisco/Util/DeviceAuth.pm b/lib/App/Netdisco/Util/DeviceAuth.pm index bb7f79f5..31f68472 100644 --- a/lib/App/Netdisco/Util/DeviceAuth.pm +++ b/lib/App/Netdisco/Util/DeviceAuth.pm @@ -63,7 +63,23 @@ sub fixup_device_auth { die "error: config: stanza in device_auth must have a tag\n" if not $stanza->{tag} and exists $stanza->{user}; - push @new_stanzas, $stanza + push @new_stanzas, $stanza; + } + + # import legacy sshcollector configuration + my $sshcollector = (setting('sshcollector') || []); + foreach my $stanza (@$sshcollector) { + # defaults + $stanza->{driver} = 'cli'; + $stanza->{read} = 1; + $stanza->{no} ||= []; + + # fixups + $stanza->{only} ||= [ scalar delete $stanza->{ip} || + scalar delete $stanza->{hostname} ]; + $stanza->{username} = scalar delete $stanza->{user}; + + push @new_stanzas, $stanza; } # legacy config diff --git a/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm b/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm index 6805737a..3ac3c307 100644 --- a/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm +++ b/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm @@ -3,7 +3,7 @@ package App::Netdisco::Worker::Plugin::Arpnip::Nodes; use Dancer ':syntax'; use App::Netdisco::Worker::Plugin; use aliased 'App::Netdisco::Worker::Status'; - +use App::Netdisco::Transport::CLI (); use App::Netdisco::Transport::SNMP (); use App::Netdisco::Util::Node qw/check_mac store_arp/; use App::Netdisco::Util::FastResolver 'hostnames_resolve_async'; @@ -18,9 +18,9 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub { or return Status->defer("arpnip failed: could not SNMP connect to $device"); # get v4 arp table - my $v4 = get_arps($device, $snmp->at_paddr, $snmp->at_netaddr); + my $v4 = get_arps_snmp($device, $snmp->at_paddr, $snmp->at_netaddr); # get v6 neighbor cache - my $v6 = get_arps($device, $snmp->ipv6_n2p_mac, $snmp->ipv6_n2p_addr); + my $v6 = get_arps_snmp($device, $snmp->ipv6_n2p_mac, $snmp->ipv6_n2p_addr); # would be possible just to use now() on updated records, but by using this # same value for them all, we _can_ if we want add a job at the end to @@ -41,7 +41,7 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub { }); # get an arp table (v4 or v6) -sub get_arps { +sub get_arps_snmp { my ($device, $paddr, $netaddr) = @_; my @arps = (); @@ -63,4 +63,45 @@ sub get_arps { return $resolved_ips; } +register_worker({ phase => 'main', driver => 'cli' }, sub { + my ($job, $workerconf) = @_; + + my $device = $job->device; + my $cli = App::Netdisco::Transport::CLI->session_for($device) + or return Status->defer("arpnip failed: could not SSH connect to $device"); + + # should be both v4 and v6 + my $arps = get_arps_cli($device, [$cli->arpnip]); + + # update node_ip with ARP and Neighbor Cache entries + my $now = 'to_timestamp('. (join '.', gettimeofday) .')'; + store_arp(\%$_, $now) for @$arps; + debug sprintf ' [%s] arpnip - processed %s ARP / IPv6 Neighbor Cache entries', + $device->ip, scalar @$arps; + + $device->update({last_arpnip => \$now}); + return Status->done("Ended arpnip for $device"); +}); + +sub get_arps_cli { + my ($device, $entries) = @_; + my @arps = (); + $entries ||= []; + + foreach my $entry (@$entries) { + next unless check_mac($entry->{mac}, $device); + push @arps, { + node => $entry->{mac}, + ip => $entry->{ip}, + dns => $entry->{dns}, + }; + } + + debug sprintf ' resolving %d ARP entries with max %d outstanding requests', + scalar @arps, $ENV{'PERL_ANYEVENT_MAX_OUTSTANDING_DNS'}; + my $resolved_ips = hostnames_resolve_async(\@arps); + + return $resolved_ips; +} + true; diff --git a/share/config.yml b/share/config.yml index 9767019a..5422e4ea 100644 --- a/share/config.yml +++ b/share/config.yml @@ -216,6 +216,7 @@ device_identity: [] community: [] community_rw: [] device_auth: [] +use_legacy_sshcollector: false get_credentials: "" bulkwalk_off: false bulkwalk_no: [] diff --git a/xt/00-compile.t b/xt/00-compile.t index 307058af..f9e3b606 100644 --- a/xt/00-compile.t +++ b/xt/00-compile.t @@ -21,8 +21,8 @@ use Test::Compile; my $test = Test::Compile->new(); -my @plfiles = grep {$_ !~ m/(?:sshcollector|graph)/i} $test->all_pl_files(); -my @pmfiles = grep {$_ !~ m/(?:sshcollector|graph)/i} $test->all_pm_files(); +my @plfiles = grep {$_ !~ m/(?:graph)/i} $test->all_pl_files(); +my @pmfiles = grep {$_ !~ m/(?:graph)/i} $test->all_pm_files(); $test->ok($test->pl_file_compiles($_), "$_ compiles") for @plfiles; $test->ok($test->pm_file_compiles($_), "$_ compiles") for @pmfiles; From 0c62159c8543ffba7c30398ddee3e78e897d55d2 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Tue, 12 Mar 2019 19:59:35 +0000 Subject: [PATCH 07/15] release 2.041000 --- Changes | 10 ++++++++++ MANIFEST | 3 +++ META.json | 22 ++++++++++++++++------ META.yml | 17 ++++++++++++----- lib/App/Netdisco.pm | 2 +- 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/Changes b/Changes index 4f29f214..2d68984a 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,13 @@ +2.041000 - 2019-03-12 + + [NEW FEATURES] + + * netdisco-sshcollector no longer required - the functionality (arpnip via + ssh) will be run within netdisco's core schedule + + * get_credentials replaces get_community and accepts any device_auth stanza + in JSON format + 2.040007 - 2019-03-06 [BUG FIXES] diff --git a/MANIFEST b/MANIFEST index 32b20851..0994605d 100644 --- a/MANIFEST +++ b/MANIFEST @@ -109,8 +109,10 @@ lib/App/Netdisco/SSHCollector/Platform/IOSXR.pm lib/App/Netdisco/SSHCollector/Platform/Linux.pm lib/App/Netdisco/SSHCollector/Platform/NXOS.pm lib/App/Netdisco/SSHCollector/Platform/PaloAlto.pm +lib/App/Netdisco/Transport/CLI.pm lib/App/Netdisco/Transport/SNMP.pm lib/App/Netdisco/Util/Device.pm +lib/App/Netdisco/Util/DeviceAuth.pm lib/App/Netdisco/Util/DNS.pm lib/App/Netdisco/Util/ExpandParams.pm lib/App/Netdisco/Util/FastResolver.pm @@ -485,6 +487,7 @@ share/views/sidebar/report/subnets.tt share/views/sidebar/search/device.tt share/views/sidebar/search/node.tt share/views/sidebar/search/port.tt +xt/00-compile.t xt/10-sort_port.t xt/11-portsort.t xt/20-checkacl.t diff --git a/META.json b/META.json index c19aca81..b528a7cf 100644 --- a/META.json +++ b/META.json @@ -29,10 +29,8 @@ }, "runtime" : { "recommends" : { - "Expect" : "0", "Graph" : "0", - "GraphViz" : "0", - "Net::OpenSSH" : "0" + "GraphViz" : "0" }, "requires" : { "Algorithm::Cron" : "0.07", @@ -52,6 +50,7 @@ "Dancer::Plugin::Passphrase" : "v2.0.1", "Dancer::Session::Cookie" : "0.27", "Data::Printer" : "0", + "Expect" : "0", "File::ShareDir" : "1.03", "File::Slurper" : "0.009", "Guard" : "1.022", @@ -69,6 +68,7 @@ "Net::DNS" : "0.72", "Net::Domain" : "1.23", "Net::LDAP" : "0", + "Net::OpenSSH" : "0", "NetAddr::IP" : "4.068", "NetAddr::MAC" : "0.93", "Opcode" : "1.07", @@ -110,6 +110,7 @@ "test" : { "requires" : { "Env::Path" : "0", + "Test::Compile" : "0", "Test::File::ShareDir::Dist" : "0", "Test::More" : "1.302083" } @@ -118,7 +119,7 @@ "provides" : { "App::Netdisco" : { "file" : "lib/App/Netdisco.pm", - "version" : "2.040007" + "version" : "2.041000" }, "App::Netdisco::AnyEvent::Nbtstat" : { "file" : "lib/App/Netdisco/AnyEvent/Nbtstat.pm" @@ -406,6 +407,9 @@ "App::Netdisco::SSHCollector::Platform::PaloAlto" : { "file" : "lib/App/Netdisco/SSHCollector/Platform/PaloAlto.pm" }, + "App::Netdisco::Transport::CLI" : { + "file" : "lib/App/Netdisco/Transport/CLI.pm" + }, "App::Netdisco::Transport::SNMP" : { "file" : "lib/App/Netdisco/Transport/SNMP.pm" }, @@ -415,6 +419,9 @@ "App::Netdisco::Util::Device" : { "file" : "lib/App/Netdisco/Util/Device.pm" }, + "App::Netdisco::Util::DeviceAuth" : { + "file" : "lib/App/Netdisco/Util/DeviceAuth.pm" + }, "App::Netdisco::Util::ExpandParams" : { "file" : "lib/App/Netdisco/Util/ExpandParams.pm" }, @@ -783,6 +790,9 @@ }, "Dancer::Template::NetdiscoTemplateToolkit" : { "file" : "lib/Dancer/Template/NetdiscoTemplateToolkit.pm" + }, + "MySession" : { + "file" : "lib/App/Netdisco/Transport/CLI.pm" } }, "release_status" : "stable", @@ -792,7 +802,7 @@ }, "homepage" : "http://netdisco.org/", "license" : [ - "http://opensource.org/licenses/bsd-license.php" + "http://opensource.org/licenses/BSD-3-Clause" ], "repository" : { "url" : "https://github.com/netdisco/netdisco" @@ -800,6 +810,6 @@ "x_IRC" : "irc://irc.freenode.org/#netdisco", "x_MailingList" : "https://lists.sourceforge.net/lists/listinfo/netdisco-users" }, - "version" : "2.040007", + "version" : "2.041000", "x_serialization_backend" : "JSON::PP version 2.97001" } diff --git a/META.yml b/META.yml index f7cb0c94..f7914fae 100644 --- a/META.yml +++ b/META.yml @@ -7,6 +7,7 @@ build_requires: ExtUtils::Config: '0' ExtUtils::Helpers: '0' ExtUtils::InstallPaths: '0' + Test::Compile: '0' Test::File::ShareDir::Dist: '0' Test::More: '1.302083' configure_requires: @@ -22,7 +23,7 @@ name: App-Netdisco provides: App::Netdisco: file: lib/App/Netdisco.pm - version: '2.040007' + version: '2.041000' App::Netdisco::AnyEvent::Nbtstat: file: lib/App/Netdisco/AnyEvent/Nbtstat.pm App::Netdisco::Backend::Job: @@ -214,12 +215,16 @@ provides: file: lib/App/Netdisco/SSHCollector/Platform/NXOS.pm App::Netdisco::SSHCollector::Platform::PaloAlto: file: lib/App/Netdisco/SSHCollector/Platform/PaloAlto.pm + App::Netdisco::Transport::CLI: + file: lib/App/Netdisco/Transport/CLI.pm App::Netdisco::Transport::SNMP: file: lib/App/Netdisco/Transport/SNMP.pm App::Netdisco::Util::DNS: file: lib/App/Netdisco/Util/DNS.pm App::Netdisco::Util::Device: file: lib/App/Netdisco/Util/Device.pm + App::Netdisco::Util::DeviceAuth: + file: lib/App/Netdisco/Util/DeviceAuth.pm App::Netdisco::Util::ExpandParams: file: lib/App/Netdisco/Util/ExpandParams.pm App::Netdisco::Util::FastResolver: @@ -466,11 +471,11 @@ provides: file: lib/App/Netdisco/Worker/Status.pm Dancer::Template::NetdiscoTemplateToolkit: file: lib/Dancer/Template/NetdiscoTemplateToolkit.pm + MySession: + file: lib/App/Netdisco/Transport/CLI.pm recommends: - Expect: '0' Graph: '0' GraphViz: '0' - Net::OpenSSH: '0' requires: Algorithm::Cron: '0.07' AnyEvent: '7.05' @@ -489,6 +494,7 @@ requires: Dancer::Plugin::Passphrase: v2.0.1 Dancer::Session::Cookie: '0.27' Data::Printer: '0' + Expect: '0' File::ShareDir: '1.03' File::Slurper: '0.009' Guard: '1.022' @@ -506,6 +512,7 @@ requires: Net::DNS: '0.72' Net::Domain: '1.23' Net::LDAP: '0' + Net::OpenSSH: '0' NetAddr::IP: '4.068' NetAddr::MAC: '0.93' Opcode: '1.07' @@ -547,7 +554,7 @@ resources: MailingList: https://lists.sourceforge.net/lists/listinfo/netdisco-users bugtracker: https://github.com/netdisco/netdisco/issues homepage: http://netdisco.org/ - license: http://opensource.org/licenses/bsd-license.php + license: http://opensource.org/licenses/BSD-3-Clause repository: https://github.com/netdisco/netdisco -version: '2.040007' +version: '2.041000' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' diff --git a/lib/App/Netdisco.pm b/lib/App/Netdisco.pm index cecfe6ae..8f53e14e 100644 --- a/lib/App/Netdisco.pm +++ b/lib/App/Netdisco.pm @@ -4,7 +4,7 @@ use strict; use warnings; use 5.010_000; -our $VERSION = '2.040007'; +our $VERSION = '2.041000'; use App::Netdisco::Configuration; =head1 NAME From 76f8ec961c0d710251f0374edacb44a806219503 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Wed, 13 Mar 2019 22:21:22 +0000 Subject: [PATCH 08/15] add rc9000 to latest change --- Changes | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 2d68984a..10750c17 100644 --- a/Changes +++ b/Changes @@ -3,10 +3,10 @@ [NEW FEATURES] * netdisco-sshcollector no longer required - the functionality (arpnip via - ssh) will be run within netdisco's core schedule + ssh) will be run within netdisco's core schedule (rc9000 and ollyg) * get_credentials replaces get_community and accepts any device_auth stanza - in JSON format + in JSON format (ollyg) 2.040007 - 2019-03-06 From 9b39d1e452825b10c989cdb6ea60ef8d75315946 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Wed, 13 Mar 2019 22:23:02 +0000 Subject: [PATCH 09/15] rename CLI Transport to SSH --- lib/App/Netdisco/Transport/{CLI.pm => SSH.pm} | 6 +++--- lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm | 4 ++-- share/config.yml | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) rename lib/App/Netdisco/Transport/{CLI.pm => SSH.pm} (94%) diff --git a/lib/App/Netdisco/Transport/CLI.pm b/lib/App/Netdisco/Transport/SSH.pm similarity index 94% rename from lib/App/Netdisco/Transport/CLI.pm rename to lib/App/Netdisco/Transport/SSH.pm index 6f865c7b..64190858 100644 --- a/lib/App/Netdisco/Transport/CLI.pm +++ b/lib/App/Netdisco/Transport/SSH.pm @@ -1,4 +1,4 @@ -package App::Netdisco::Transport::CLI; +package App::Netdisco::Transport::SSH; use Dancer qw/:syntax :script/; @@ -11,14 +11,14 @@ use base 'Dancer::Object::Singleton'; =head1 NAME -App::Netdisco::Transport::CLI +App::Netdisco::Transport::SSH =head1 DESCRIPTION Returns an object which has an active SSH connection which can be used for some actions such as arpnip. - my $cli = App::Netdisco::Transport::CLI->session_for( ... ); + my $cli = App::Netdisco::Transport::SSH->session_for( ... ); =cut diff --git a/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm b/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm index 3ac3c307..e303f0dc 100644 --- a/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm +++ b/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm @@ -3,7 +3,7 @@ package App::Netdisco::Worker::Plugin::Arpnip::Nodes; use Dancer ':syntax'; use App::Netdisco::Worker::Plugin; use aliased 'App::Netdisco::Worker::Status'; -use App::Netdisco::Transport::CLI (); +use App::Netdisco::Transport::SSH (); use App::Netdisco::Transport::SNMP (); use App::Netdisco::Util::Node qw/check_mac store_arp/; use App::Netdisco::Util::FastResolver 'hostnames_resolve_async'; @@ -67,7 +67,7 @@ register_worker({ phase => 'main', driver => 'cli' }, sub { my ($job, $workerconf) = @_; my $device = $job->device; - my $cli = App::Netdisco::Transport::CLI->session_for($device) + my $cli = App::Netdisco::Transport::SSH->session_for($device) or return Status->defer("arpnip failed: could not SSH connect to $device"); # should be both v4 and v6 diff --git a/share/config.yml b/share/config.yml index 5422e4ea..9ff5906b 100644 --- a/share/config.yml +++ b/share/config.yml @@ -415,7 +415,6 @@ worker_plugins: - 'Vlan::Core' extra_worker_plugins: [] -# - Discover::ConfigBackup::CLI driver_priority: restconf: 500 From b6028685e27a659c47bedefb76c339c36f4930a2 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Wed, 13 Mar 2019 22:38:24 +0000 Subject: [PATCH 10/15] update docs to specify curl and postgresql packages --- lib/App/Netdisco.pm | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/App/Netdisco.pm b/lib/App/Netdisco.pm index 8f53e14e..26e56217 100644 --- a/lib/App/Netdisco.pm +++ b/lib/App/Netdisco.pm @@ -70,16 +70,19 @@ L. =head1 Dependencies Netdisco has several Perl library dependencies which will be automatically -installed. However it's I recommended that you first install -L, L, and a compiler using your operating system packages. +installed. However it's required that you first install the following +operating system packages: On Ubuntu/Debian: - root:~# apt-get install libdbd-pg-perl libsnmp-perl libssl-dev libio-socket-ssl-perl build-essential + root:~# apt-get install libdbd-pg-perl libsnmp-perl libssl-dev libio-socket-ssl-perl curl postgresql build-essential On Fedora/Red-Hat: - root:~# yum install perl-core perl-DBD-Pg net-snmp-perl net-snmp-devel openssl-devel make automake gcc + root:~# yum install perl-core perl-DBD-Pg net-snmp-perl net-snmp-devel openssl-devel curl postgresql-server postgresql-contrib make automake gcc + root:~# postgresql-setup initdb + root:~# systemctl start postgresql + root:~# systemctl enable postgresql On BSD systems please see L. From 154db22ac09b727781c49b4a49737a9fb644aefc Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Wed, 13 Mar 2019 22:54:51 +0000 Subject: [PATCH 11/15] direct link to pg_hba.conf fix --- lib/App/Netdisco.pm | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/App/Netdisco.pm b/lib/App/Netdisco.pm index 26e56217..2cce1691 100644 --- a/lib/App/Netdisco.pm +++ b/lib/App/Netdisco.pm @@ -57,9 +57,9 @@ L are =back We have several other pages with tips for -L, +L, L, -L, +L, and L. You can also speak to someone in the C<#netdisco@freenode> IRC channel, or on @@ -107,9 +107,11 @@ application: postgres:~$ createdb -O netdisco netdisco -The default PostgreSQL configuration isn't well tuned for modern server -hardware. We strongly recommend that you use the C Python program to -auto-tune your C file: +You may wish to L +so that local connections are working. The default PostgreSQL configuration +also needs tuning for modern server hardware. We recommend that you use the +C Python program to auto-tune your C file: =over 4 From c4e7d98c56e0dc8121237032a1a7bd60bde17453 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Fri, 15 Mar 2019 05:18:44 +0000 Subject: [PATCH 12/15] fix device port change check --- lib/App/Netdisco/Util/Port.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/App/Netdisco/Util/Port.pm b/lib/App/Netdisco/Util/Port.pm index 383e893b..780ff13b 100644 --- a/lib/App/Netdisco/Util/Port.pm +++ b/lib/App/Netdisco/Util/Port.pm @@ -219,7 +219,7 @@ Returns true if the C<$port> L object has a phone connected. =cut sub port_has_phone { - return (shift)->with_properties->remote_is_phone; + return (shift)->properties->remote_is_phone; } 1; From b5329d228baded08ee3c5662a651405ca5215d13 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Fri, 15 Mar 2019 05:20:57 +0000 Subject: [PATCH 13/15] Add store phase and update Arpnip::Nodes to use it (#538) * add store phase * rework arpnip nodes to use store phase * add late phase too so that users can still access content in db --- lib/App/Netdisco/Backend/Job.pm | 4 +- lib/App/Netdisco/Worker/Loader.pm | 6 +- .../Netdisco/Worker/Plugin/Arpnip/Nodes.pm | 73 ++++++++++++------- lib/App/Netdisco/Worker/Runner.pm | 2 +- 4 files changed, 52 insertions(+), 33 deletions(-) diff --git a/lib/App/Netdisco/Backend/Job.pm b/lib/App/Netdisco/Backend/Job.pm index d1d31d08..ea28c258 100644 --- a/lib/App/Netdisco/Backend/Job.pm +++ b/lib/App/Netdisco/Backend/Job.pm @@ -93,7 +93,7 @@ phase. sub finalise_status { my $job = shift; - # use DDP; p $job->_statuslist; + # use DDP; p $job->_statuslist; # fallback $job->status('error'); @@ -103,7 +103,7 @@ sub finalise_status { foreach my $status (reverse @{ $job->_statuslist }) { next if $status->phase - and $status->phase !~ m/^(?:check|early|main)$/; + and $status->phase !~ m/^(?:check|early|main|store|late)$/; # done() from check phase should not be the action's done() next if $status->phase eq 'check' and $status->is_ok; diff --git a/lib/App/Netdisco/Worker/Loader.pm b/lib/App/Netdisco/Worker/Loader.pm index dc87d977..f8a94d1e 100644 --- a/lib/App/Netdisco/Worker/Loader.pm +++ b/lib/App/Netdisco/Worker/Loader.pm @@ -12,7 +12,9 @@ use namespace::clean; has [qw/workers_check workers_early workers_main - workers_user/] => ( is => 'rw' ); + workers_user + workers_store + workers_late/] => ( is => 'rw' ); sub load_workers { my $self = shift; @@ -37,7 +39,7 @@ sub load_workers { my $workers = vars->{'workers'}->{$action} || {}; #use DDP; p vars->{'workers'}; - foreach my $phase (qw/check early main user/) { + foreach my $phase (qw/check early main user store late/) { my $pname = "workers_${phase}"; my @wset = (); diff --git a/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm b/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm index e303f0dc..50af14c6 100644 --- a/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm +++ b/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm @@ -1,15 +1,43 @@ package App::Netdisco::Worker::Plugin::Arpnip::Nodes; use Dancer ':syntax'; +use Dancer::Plugin::DBIC 'schema'; + use App::Netdisco::Worker::Plugin; use aliased 'App::Netdisco::Worker::Status'; + use App::Netdisco::Transport::SSH (); use App::Netdisco::Transport::SNMP (); + use App::Netdisco::Util::Node qw/check_mac store_arp/; use App::Netdisco::Util::FastResolver 'hostnames_resolve_async'; -use Dancer::Plugin::DBIC 'schema'; + +use NetAddr::IP::Lite ':lower'; use Time::HiRes 'gettimeofday'; +register_worker({ phase => 'store' }, sub { + my ($job, $workerconf) = @_; + my $device = $job->device; + + # would be possible just to use now() on updated records, but by using this + # same value for them all, we _can_ if we want add a job at the end to + # select and do something with the updated set (no reason to yet, though) + my $now = 'to_timestamp('. (join '.', gettimeofday) .')'; + + # update node_ip with ARP and Neighbor Cache entries + + store_arp(\%$_, $now) for @{ vars->{'v4arps'} }; + debug sprintf ' [%s] arpnip - processed %s ARP Cache entries', + $device->ip, scalar @{ vars->{'v4arps'} }; + + store_arp(\%$_, $now) for @{ vars->{'v6arps'} }; + debug sprintf ' [%s] arpnip - processed %s IPv6 Neighbor Cache entries', + $device->ip, scalar @{ vars->{'v6arps'} }; + + $device->update({last_arpnip => \$now}); + return Status->done("Ended arpnip for $device"); +}); + register_worker({ phase => 'main', driver => 'snmp' }, sub { my ($job, $workerconf) = @_; @@ -17,27 +45,15 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub { my $snmp = App::Netdisco::Transport::SNMP->reader_for($device) or return Status->defer("arpnip failed: could not SNMP connect to $device"); - # get v4 arp table - my $v4 = get_arps_snmp($device, $snmp->at_paddr, $snmp->at_netaddr); - # get v6 neighbor cache - my $v6 = get_arps_snmp($device, $snmp->ipv6_n2p_mac, $snmp->ipv6_n2p_addr); + # cache v4 arp table + push @{ vars->{'v4arps'} }, + @{ get_arps_snmp($device, $snmp->at_paddr, $snmp->at_netaddr) }; - # would be possible just to use now() on updated records, but by using this - # same value for them all, we _can_ if we want add a job at the end to - # select and do something with the updated set (no reason to yet, though) - my $now = 'to_timestamp('. (join '.', gettimeofday) .')'; + # cache v6 neighbor cache + push @{ vars->{'v6arps'} }, + @{get_arps_snmp($device, $snmp->ipv6_n2p_mac, $snmp->ipv6_n2p_addr) }; - # update node_ip with ARP and Neighbor Cache entries - store_arp(\%$_, $now) for @$v4; - debug sprintf ' [%s] arpnip - processed %s ARP Cache entries', - $device->ip, scalar @$v4; - - store_arp(\%$_, $now) for @$v6; - debug sprintf ' [%s] arpnip - processed %s IPv6 Neighbor Cache entries', - $device->ip, scalar @$v6; - - $device->update({last_arpnip => \$now}); - return Status->done("Ended arpnip for $device"); + return Status->info("Gathered arp caches from $device"); }); # get an arp table (v4 or v6) @@ -71,16 +87,17 @@ register_worker({ phase => 'main', driver => 'cli' }, sub { or return Status->defer("arpnip failed: could not SSH connect to $device"); # should be both v4 and v6 - my $arps = get_arps_cli($device, [$cli->arpnip]); + my @arps = @{ get_arps_cli($device, [$cli->arpnip]) }; - # update node_ip with ARP and Neighbor Cache entries - my $now = 'to_timestamp('. (join '.', gettimeofday) .')'; - store_arp(\%$_, $now) for @$arps; - debug sprintf ' [%s] arpnip - processed %s ARP / IPv6 Neighbor Cache entries', - $device->ip, scalar @$arps; + # cache v4 arp table + push @{ vars->{'v4arps'} }, + grep { NetAddr::IP::Lite->new($_->{ip})->bits == 32 } @arps; - $device->update({last_arpnip => \$now}); - return Status->done("Ended arpnip for $device"); + # cache v6 neighbor cache + push @{ vars->{'v6arps'} }, + grep { NetAddr::IP::Lite->new($_->{ip})->bits == 128 } @arps; + + return Status->info("Gathered arp caches from $device"); }); sub get_arps_cli { diff --git a/lib/App/Netdisco/Worker/Runner.pm b/lib/App/Netdisco/Worker/Runner.pm index 193281ca..2c5e21ef 100644 --- a/lib/App/Netdisco/Worker/Runner.pm +++ b/lib/App/Netdisco/Worker/Runner.pm @@ -69,7 +69,7 @@ sub run { # run other phases if ($job->check_passed) { - $self->run_workers("workers_${_}") for qw/early main user/; + $self->run_workers("workers_${_}") for qw/early main user store late/; } }; From 3c16a0faaef1815a07f42df986361aeaba7a997a Mon Sep 17 00:00:00 2001 From: Ambroise Date: Fri, 15 Mar 2019 06:25:46 +0100 Subject: [PATCH 14/15] Fix an issue with the reindixing for VRF (#539) --- lib/App/Netdisco/Util/SNMP.pm | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/App/Netdisco/Util/SNMP.pm b/lib/App/Netdisco/Util/SNMP.pm index ba5b54d6..26708726 100644 --- a/lib/App/Netdisco/Util/SNMP.pm +++ b/lib/App/Netdisco/Util/SNMP.pm @@ -100,11 +100,19 @@ sub snmp_comm_reindex { } $prefix ||= 'vlan-'; - debug - sprintf '[%s] reindexing to "%s%s" (ver: %s, class: %s)', + if ($vlan =~ /^[0-9]+$/i && $vlan) { + debug sprintf '[%s] reindexing to "%s%s" (ver: %s, class: %s)', $device->ip, $prefix, $vlan, $ver, $snmp->class; - $vlan ? $snmp->update(Context => ($prefix . $vlan)) - : $snmp->update(Context => ''); + $snmp->update(Context => ($prefix . $vlan)); + } elsif ($vlan =~ /^[a-z0-9]+$/i && $vlan) { + debug sprintf '[%s] reindexing to "%s" (ver: %s, class: %s)', + $device->ip, $vlan, $ver, $snmp->class; + $snmp->update(Context => ($vlan)); + } else { + debug sprintf '[%s] reindexing without context (ver: %s, class: %s)', + $device->ip, $ver, $snmp->class; + $snmp->update(Context => ''); + } } else { my $comm = $snmp->snmp_comm; From 9b947369f9bb9c53311b563df91ebc24d9234085 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Fri, 15 Mar 2019 05:33:27 +0000 Subject: [PATCH 15/15] release 2.041001 --- Changes | 12 ++++++++++++ MANIFEST | 2 +- META.json | 12 ++++++------ META.yml | 10 +++++----- lib/App/Netdisco.pm | 2 +- 5 files changed, 25 insertions(+), 13 deletions(-) diff --git a/Changes b/Changes index 10750c17..241c651e 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,15 @@ +2.041001 - 2019-03-15 + + [ENHANCEMENTS] + + * add "store" and "late" phases to backend workers + * documentation updates + + [BUG FIXES] + + * #539 fix an issue with VLAN reindixing for VRFs (earendilfr) + * fix device port change check + 2.041000 - 2019-03-12 [NEW FEATURES] diff --git a/MANIFEST b/MANIFEST index 0994605d..20db16c8 100644 --- a/MANIFEST +++ b/MANIFEST @@ -109,8 +109,8 @@ lib/App/Netdisco/SSHCollector/Platform/IOSXR.pm lib/App/Netdisco/SSHCollector/Platform/Linux.pm lib/App/Netdisco/SSHCollector/Platform/NXOS.pm lib/App/Netdisco/SSHCollector/Platform/PaloAlto.pm -lib/App/Netdisco/Transport/CLI.pm lib/App/Netdisco/Transport/SNMP.pm +lib/App/Netdisco/Transport/SSH.pm lib/App/Netdisco/Util/Device.pm lib/App/Netdisco/Util/DeviceAuth.pm lib/App/Netdisco/Util/DNS.pm diff --git a/META.json b/META.json index b528a7cf..89bbd957 100644 --- a/META.json +++ b/META.json @@ -119,7 +119,7 @@ "provides" : { "App::Netdisco" : { "file" : "lib/App/Netdisco.pm", - "version" : "2.041000" + "version" : "2.041001" }, "App::Netdisco::AnyEvent::Nbtstat" : { "file" : "lib/App/Netdisco/AnyEvent/Nbtstat.pm" @@ -407,12 +407,12 @@ "App::Netdisco::SSHCollector::Platform::PaloAlto" : { "file" : "lib/App/Netdisco/SSHCollector/Platform/PaloAlto.pm" }, - "App::Netdisco::Transport::CLI" : { - "file" : "lib/App/Netdisco/Transport/CLI.pm" - }, "App::Netdisco::Transport::SNMP" : { "file" : "lib/App/Netdisco/Transport/SNMP.pm" }, + "App::Netdisco::Transport::SSH" : { + "file" : "lib/App/Netdisco/Transport/SSH.pm" + }, "App::Netdisco::Util::DNS" : { "file" : "lib/App/Netdisco/Util/DNS.pm" }, @@ -792,7 +792,7 @@ "file" : "lib/Dancer/Template/NetdiscoTemplateToolkit.pm" }, "MySession" : { - "file" : "lib/App/Netdisco/Transport/CLI.pm" + "file" : "lib/App/Netdisco/Transport/SSH.pm" } }, "release_status" : "stable", @@ -810,6 +810,6 @@ "x_IRC" : "irc://irc.freenode.org/#netdisco", "x_MailingList" : "https://lists.sourceforge.net/lists/listinfo/netdisco-users" }, - "version" : "2.041000", + "version" : "2.041001", "x_serialization_backend" : "JSON::PP version 2.97001" } diff --git a/META.yml b/META.yml index f7914fae..1fb921b8 100644 --- a/META.yml +++ b/META.yml @@ -23,7 +23,7 @@ name: App-Netdisco provides: App::Netdisco: file: lib/App/Netdisco.pm - version: '2.041000' + version: '2.041001' App::Netdisco::AnyEvent::Nbtstat: file: lib/App/Netdisco/AnyEvent/Nbtstat.pm App::Netdisco::Backend::Job: @@ -215,10 +215,10 @@ provides: file: lib/App/Netdisco/SSHCollector/Platform/NXOS.pm App::Netdisco::SSHCollector::Platform::PaloAlto: file: lib/App/Netdisco/SSHCollector/Platform/PaloAlto.pm - App::Netdisco::Transport::CLI: - file: lib/App/Netdisco/Transport/CLI.pm App::Netdisco::Transport::SNMP: file: lib/App/Netdisco/Transport/SNMP.pm + App::Netdisco::Transport::SSH: + file: lib/App/Netdisco/Transport/SSH.pm App::Netdisco::Util::DNS: file: lib/App/Netdisco/Util/DNS.pm App::Netdisco::Util::Device: @@ -472,7 +472,7 @@ provides: Dancer::Template::NetdiscoTemplateToolkit: file: lib/Dancer/Template/NetdiscoTemplateToolkit.pm MySession: - file: lib/App/Netdisco/Transport/CLI.pm + file: lib/App/Netdisco/Transport/SSH.pm recommends: Graph: '0' GraphViz: '0' @@ -556,5 +556,5 @@ resources: homepage: http://netdisco.org/ license: http://opensource.org/licenses/BSD-3-Clause repository: https://github.com/netdisco/netdisco -version: '2.041000' +version: '2.041001' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' diff --git a/lib/App/Netdisco.pm b/lib/App/Netdisco.pm index 2cce1691..71cf175d 100644 --- a/lib/App/Netdisco.pm +++ b/lib/App/Netdisco.pm @@ -4,7 +4,7 @@ use strict; use warnings; use 5.010_000; -our $VERSION = '2.041000'; +our $VERSION = '2.041001'; use App::Netdisco::Configuration; =head1 NAME