From eac55a581ddd8707814f212384a4e7097ef537af Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Fri, 14 Jul 2023 17:37:52 +0100 Subject: [PATCH] #1066 implement snmp_try_slow_connect and fast device discover from queue --- lib/App/Netdisco/JobQueue/PostgreSQL.pm | 2 +- lib/App/Netdisco/Transport/SNMP.pm | 45 ++++++++++++++----- lib/App/Netdisco/Worker/Loader.pm | 13 +++--- .../Plugin/Internal/SNMPFastDiscover.pm | 18 ++++++++ share/config.yml | 2 + 5 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 lib/App/Netdisco/Worker/Plugin/Internal/SNMPFastDiscover.pm diff --git a/lib/App/Netdisco/JobQueue/PostgreSQL.pm b/lib/App/Netdisco/JobQueue/PostgreSQL.pm index e89b8eb2..3cc0e22e 100644 --- a/lib/App/Netdisco/JobQueue/PostgreSQL.pm +++ b/lib/App/Netdisco/JobQueue/PostgreSQL.pm @@ -246,7 +246,7 @@ sub jq_defer { # lock db row and update to show job is available schema(vars->{'tenant'})->resultset('Admin') ->search({ job => $job->id }, { for => 'update' }) - ->update({ status => 'queued', started => undef }); + ->update({ status => 'queued', started => undef, log => $job->log }); }); $happy = true; } diff --git a/lib/App/Netdisco/Transport/SNMP.pm b/lib/App/Netdisco/Transport/SNMP.pm index 209a0cce..f5cef713 100644 --- a/lib/App/Netdisco/Transport/SNMP.pm +++ b/lib/App/Netdisco/Transport/SNMP.pm @@ -209,9 +209,37 @@ sub _snmp_connect_generic { unshift @classes, $device->snmp_class; } - my $info = undef; - my $orig_retries = $snmp_args{Retries}; - my $orig_timeout = $snmp_args{Timeout}; + # first try the communities in a fast pass using best version + + VERSION: foreach my $ver (3, 2) { + my %local_args = (%snmp_args, + Version => $ver, Retries => 0, Timeout => 200000); + + COMMUNITY: foreach my $comm (@communities) { + next unless $comm; + + next if $ver eq 3 and exists $comm->{community}; + next if $ver ne 3 and !exists $comm->{community}; + + my $info = _try_connect($device, $classes[0], $comm, $mode, \%local_args, + ($useclass ? 0 : 1) ); + + # if successful, restore the default/user timeouts and return + if ($info) { + my $class = $info->device_type; + return $class->new( + %snmp_args, Version => $ver, + _mk_info_commargs($comm), + ); + } + } + } + + # then revert to conservative settings and repeat with all versions + + # unless user wants just the fast connections for bulk discovery + # or we are on the first discovery attempt of a new device + return unless setting('snmp_try_slow_connect'); CLASS: foreach my $class (@classes) { next unless $class; @@ -226,19 +254,14 @@ sub _snmp_connect_generic { next if $ver eq 3 and exists $comm->{community}; next if $ver ne 3 and !exists $comm->{community}; - # $local_args{Retries} = $comm->{_tried} ? $orig_retries : 0; - # $local_args{Timeout} = $comm->{_tried} ? $orig_timeout : 500000; - - $info = _try_connect($device, $class, $comm, $mode, \%local_args, + my $info = _try_connect($device, $class, $comm, $mode, \%local_args, ($useclass ? 0 : 1) ); - last CLASS if $info; - - # ++$comm->{_tried}; + return $info if $info; } } } - return $info; + return undef; } sub _try_connect { diff --git a/lib/App/Netdisco/Worker/Loader.pm b/lib/App/Netdisco/Worker/Loader.pm index 01047207..b46e127e 100644 --- a/lib/App/Netdisco/Worker/Loader.pm +++ b/lib/App/Netdisco/Worker/Loader.pm @@ -31,27 +31,28 @@ sub load_workers { if $plugin !~ m/^\+/; $plugin =~ s/^\+//; - next unless $plugin =~ m/::Plugin::${action}(?:::|$)/i; + next unless $plugin =~ m/::Plugin::(?:${action}|Internal)(?:::|$)/i; $ENV{ND2_LOG_PLUGINS} && debug "loading worker plugin $plugin"; Module::Load::load $plugin; } # now vars->{workers} is populated, we set the dispatch order - my $workers = vars->{'workers'}->{$action} || {}; + my %workers = ( %{ vars->{'workers'}->{$action} || {} }, + %{ vars->{'workers'}->{'internal'} || {} } ); my $driverless_main = 0; - #use DDP; p vars->{'workers'}; + # use DDP; p vars{'workers'}; p %workers; foreach my $phase (qw/check early main user store late/) { my $pname = "workers_${phase}"; my @wset = (); - foreach my $namespace (sort keys %{ $workers->{$phase} }) { + foreach my $namespace (sort keys %{ $workers{$phase} }) { foreach my $priority (sort {$b <=> $a} - keys %{ $workers->{$phase}->{$namespace} }) { + keys %{ $workers{$phase}->{$namespace} }) { ++$driverless_main if $phase eq 'main' and ($priority == 0 or $priority == setting('driver_priority')->{'direct'}); - push @wset, @{ $workers->{$phase}->{$namespace}->{$priority} }; + push @wset, @{ $workers{$phase}->{$namespace}->{$priority} }; } } diff --git a/lib/App/Netdisco/Worker/Plugin/Internal/SNMPFastDiscover.pm b/lib/App/Netdisco/Worker/Plugin/Internal/SNMPFastDiscover.pm new file mode 100644 index 00000000..7a9818f1 --- /dev/null +++ b/lib/App/Netdisco/Worker/Plugin/Internal/SNMPFastDiscover.pm @@ -0,0 +1,18 @@ +package App::Netdisco::Worker::Plugin::Internal::SNMPFastDiscover; + +use Dancer ':syntax'; +use App::Netdisco::Worker::Plugin; +use aliased 'App::Netdisco::Worker::Status'; + +register_worker({ phase => 'check', driver => 'direct' }, sub { + my ($job, $workerconf) = @_; + + # if the job is a queued job, and discover, and the first one... + if ($job->job and $job->action eq 'discover' and not $job->log) { + config->{'snmp_try_slow_connect'} = false; + debug sprintf '[%s] skipping long SNMP timeouts for initial discover', + $job->device; + } +}); + +true; diff --git a/share/config.yml b/share/config.yml index 0a2ca736..e899b52e 100644 --- a/share/config.yml +++ b/share/config.yml @@ -345,6 +345,7 @@ snmpver: 3 snmptimeout: 3000000 snmpretries: 2 net_snmp_options: {} +snmp_try_slow_connect: true snmp_remoteport: {} snmp_field_protection: device: @@ -527,6 +528,7 @@ worker_plugins: - 'Hook' - 'Hook::Exec' - 'Hook::HTTP' + - 'Internal::SNMPFastDiscover' - 'LoadMIBs' - 'Location' - 'Macsuck'