diff --git a/lib/App/Netdisco/Worker/Plugin/Discover/Interfaces.pm b/lib/App/Netdisco/Worker/Plugin/Discover/Interfaces.pm deleted file mode 100644 index 4d25dae8..00000000 --- a/lib/App/Netdisco/Worker/Plugin/Discover/Interfaces.pm +++ /dev/null @@ -1,150 +0,0 @@ -package App::Netdisco::Worker::Plugin::Discover::Interfaces; - -use Dancer ':syntax'; -use App::Netdisco::Worker::Plugin; -use aliased 'App::Netdisco::Worker::Status'; - -use App::Netdisco::Transport::SNMP (); -use Dancer::Plugin::DBIC 'schema'; -use Encode; - -register_worker({ phase => 'early', driver => 'snmp' }, sub { - my ($job, $workerconf) = @_; - - my $device = $job->device; - my $snmp = App::Netdisco::Transport::SNMP->reader_for($device) - or return Status->defer("discover failed: could not SNMP connect to $device"); - - my $interfaces = $snmp->interfaces; - my $i_type = $snmp->i_type; - my $i_ignore = $snmp->i_ignore; - my $i_descr = $snmp->i_description; - my $i_mtu = $snmp->i_mtu; - my $i_speed = $snmp->i_speed; - my $i_mac = $snmp->i_mac; - my $i_up = $snmp->i_up; - my $i_up_admin = $snmp->i_up_admin; - my $i_name = $snmp->i_name; - my $i_duplex = $snmp->i_duplex; - my $i_duplex_admin = $snmp->i_duplex_admin; - my $i_stp_state = $snmp->i_stp_state; - my $i_vlan = $snmp->i_vlan; - my $i_lastchange = $snmp->i_lastchange; - my $agg_ports = $snmp->agg_ports; - - # clear the cached uptime and get a new one - my $dev_uptime = $snmp->load_uptime; - if (!defined $dev_uptime) { - error sprintf ' [%s] interfaces - Error! Failed to get uptime from device!', - $device->ip; - return Status->error("discover failed: no uptime from device $device!"); - } - - # used to track how many times the device uptime wrapped - my $dev_uptime_wrapped = 0; - - # use SNMP-FRAMEWORK-MIB::snmpEngineTime if available to - # fix device uptime if wrapped - if (defined $snmp->snmpEngineTime) { - $dev_uptime_wrapped = int( $snmp->snmpEngineTime * 100 / 2**32 ); - if ($dev_uptime_wrapped > 0) { - info sprintf ' [%s] interface - device uptime wrapped %d times - correcting', - $device->ip, $dev_uptime_wrapped; - $device->uptime( $dev_uptime + $dev_uptime_wrapped * 2**32 ); - } - } - - # build device interfaces suitable for DBIC - my %interfaces; - foreach my $entry (keys %$interfaces) { - my $port = $interfaces->{$entry}; - - if (not $port) { - debug sprintf ' [%s] interfaces - ignoring %s (no port mapping)', - $device->ip, $entry; - next; - } - - if (scalar grep {$port =~ m/^$_$/} @{setting('ignore_interfaces') || []}) { - debug sprintf - ' [%s] interfaces - ignoring %s (%s) (config:ignore_interfaces)', - $device->ip, $entry, $port; - next; - } - - if (exists $i_ignore->{$entry}) { - debug sprintf ' [%s] interfaces - ignoring %s (%s) (%s)', - $device->ip, $entry, $port, $i_type->{$entry}; - next; - } - - my $lc = $i_lastchange->{$entry} || 0; - if (not $dev_uptime_wrapped and $lc > $dev_uptime) { - info sprintf ' [%s] interfaces - device uptime wrapped (%s) - correcting', - $device->ip, $port; - $device->uptime( $dev_uptime + 2**32 ); - $dev_uptime_wrapped = 1; - } - - if ($device->is_column_changed('uptime') and $lc) { - if ($lc < $dev_uptime) { - # ambiguous: lastchange could be sysUptime before or after wrap - if ($dev_uptime > 30000 and $lc < 30000) { - # uptime wrap more than 5min ago but lastchange within 5min - # assume lastchange was directly after boot -> no action - } - else { - # uptime wrap less than 5min ago or lastchange > 5min ago - # to be on safe side, assume lastchange after counter wrap - debug sprintf - ' [%s] interfaces - correcting LastChange for %s, assuming sysUptime wrap', - $device->ip, $port; - $lc += $dev_uptime_wrapped * 2**32; - } - } - } - - $interfaces{$port} = { - port => $port, - descr => $i_descr->{$entry}, - up => $i_up->{$entry}, - up_admin => $i_up_admin->{$entry}, - mac => $i_mac->{$entry}, - speed => $i_speed->{$entry}, - mtu => $i_mtu->{$entry}, - name => Encode::decode('UTF-8', $i_name->{$entry}), - duplex => $i_duplex->{$entry}, - duplex_admin => $i_duplex_admin->{$entry}, - stp => $i_stp_state->{$entry}, - type => $i_type->{$entry}, - vlan => $i_vlan->{$entry}, - pvid => $i_vlan->{$entry}, - is_master => 'false', - slave_of => undef, - lastchange => $lc, - }; - } - - # must do this after building %interfaces so that we can set is_master - foreach my $sidx (keys %$agg_ports) { - my $slave = $interfaces->{$sidx} or next; - my $master = $interfaces->{ $agg_ports->{$sidx} } or next; - next unless exists $interfaces{$slave} and exists $interfaces{$master}; - - $interfaces{$slave}->{slave_of} = $master; - $interfaces{$master}->{is_master} = 'true'; - } - - schema('netdisco')->resultset('DevicePort')->txn_do_locked(sub { - my $gone = $device->ports->delete({keep_nodes => 1}); - debug sprintf ' [%s] interfaces - removed %d interfaces', - $device->ip, $gone; - $device->update_or_insert(undef, {for => 'update'}); - $device->ports->populate([values %interfaces]); - - return Status->noop(sprintf ' [%s] interfaces - added %d new interfaces', - $device->ip, scalar values %interfaces); - }); -}); - -true; diff --git a/lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm b/lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm index 487724d6..1ffd228c 100644 --- a/lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm +++ b/lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm @@ -12,7 +12,7 @@ use Dancer::Plugin::DBIC 'schema'; use NetAddr::IP::Lite ':lower'; use Encode; -register_worker({ phase => 'main', driver => 'snmp' }, sub { +register_worker({ phase => 'early', driver => 'snmp' }, sub { my ($job, $workerconf) = @_; my $device = $job->device; @@ -102,4 +102,143 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub { return Status->done("Ended discover for $device"); }); +register_worker({ phase => 'early', driver => 'snmp' }, sub { + my ($job, $workerconf) = @_; + + my $device = $job->device; + my $snmp = App::Netdisco::Transport::SNMP->reader_for($device) + or return Status->defer("discover failed: could not SNMP connect to $device"); + + my $interfaces = $snmp->interfaces; + my $i_type = $snmp->i_type; + my $i_ignore = $snmp->i_ignore; + my $i_descr = $snmp->i_description; + my $i_mtu = $snmp->i_mtu; + my $i_speed = $snmp->i_speed; + my $i_mac = $snmp->i_mac; + my $i_up = $snmp->i_up; + my $i_up_admin = $snmp->i_up_admin; + my $i_name = $snmp->i_name; + my $i_duplex = $snmp->i_duplex; + my $i_duplex_admin = $snmp->i_duplex_admin; + my $i_stp_state = $snmp->i_stp_state; + my $i_vlan = $snmp->i_vlan; + my $i_lastchange = $snmp->i_lastchange; + my $agg_ports = $snmp->agg_ports; + + # clear the cached uptime and get a new one + my $dev_uptime = $snmp->load_uptime; + if (!defined $dev_uptime) { + error sprintf ' [%s] interfaces - Error! Failed to get uptime from device!', + $device->ip; + return Status->error("discover failed: no uptime from device $device!"); + } + + # used to track how many times the device uptime wrapped + my $dev_uptime_wrapped = 0; + + # use SNMP-FRAMEWORK-MIB::snmpEngineTime if available to + # fix device uptime if wrapped + if (defined $snmp->snmpEngineTime) { + $dev_uptime_wrapped = int( $snmp->snmpEngineTime * 100 / 2**32 ); + if ($dev_uptime_wrapped > 0) { + info sprintf ' [%s] interface - device uptime wrapped %d times - correcting', + $device->ip, $dev_uptime_wrapped; + $device->uptime( $dev_uptime + $dev_uptime_wrapped * 2**32 ); + } + } + + # build device interfaces suitable for DBIC + my %interfaces; + foreach my $entry (keys %$interfaces) { + my $port = $interfaces->{$entry}; + + if (not $port) { + debug sprintf ' [%s] interfaces - ignoring %s (no port mapping)', + $device->ip, $entry; + next; + } + + if (scalar grep {$port =~ m/^$_$/} @{setting('ignore_interfaces') || []}) { + debug sprintf + ' [%s] interfaces - ignoring %s (%s) (config:ignore_interfaces)', + $device->ip, $entry, $port; + next; + } + + if (exists $i_ignore->{$entry}) { + debug sprintf ' [%s] interfaces - ignoring %s (%s) (%s)', + $device->ip, $entry, $port, $i_type->{$entry}; + next; + } + + my $lc = $i_lastchange->{$entry} || 0; + if (not $dev_uptime_wrapped and $lc > $dev_uptime) { + info sprintf ' [%s] interfaces - device uptime wrapped (%s) - correcting', + $device->ip, $port; + $device->uptime( $dev_uptime + 2**32 ); + $dev_uptime_wrapped = 1; + } + + if ($device->is_column_changed('uptime') and $lc) { + if ($lc < $dev_uptime) { + # ambiguous: lastchange could be sysUptime before or after wrap + if ($dev_uptime > 30000 and $lc < 30000) { + # uptime wrap more than 5min ago but lastchange within 5min + # assume lastchange was directly after boot -> no action + } + else { + # uptime wrap less than 5min ago or lastchange > 5min ago + # to be on safe side, assume lastchange after counter wrap + debug sprintf + ' [%s] interfaces - correcting LastChange for %s, assuming sysUptime wrap', + $device->ip, $port; + $lc += $dev_uptime_wrapped * 2**32; + } + } + } + + $interfaces{$port} = { + port => $port, + descr => $i_descr->{$entry}, + up => $i_up->{$entry}, + up_admin => $i_up_admin->{$entry}, + mac => $i_mac->{$entry}, + speed => $i_speed->{$entry}, + mtu => $i_mtu->{$entry}, + name => Encode::decode('UTF-8', $i_name->{$entry}), + duplex => $i_duplex->{$entry}, + duplex_admin => $i_duplex_admin->{$entry}, + stp => $i_stp_state->{$entry}, + type => $i_type->{$entry}, + vlan => $i_vlan->{$entry}, + pvid => $i_vlan->{$entry}, + is_master => 'false', + slave_of => undef, + lastchange => $lc, + }; + } + + # must do this after building %interfaces so that we can set is_master + foreach my $sidx (keys %$agg_ports) { + my $slave = $interfaces->{$sidx} or next; + my $master = $interfaces->{ $agg_ports->{$sidx} } or next; + next unless exists $interfaces{$slave} and exists $interfaces{$master}; + + $interfaces{$slave}->{slave_of} = $master; + $interfaces{$master}->{is_master} = 'true'; + } + + schema('netdisco')->resultset('DevicePort')->txn_do_locked(sub { + my $gone = $device->ports->delete({keep_nodes => 1}); + debug sprintf ' [%s] interfaces - removed %d interfaces', + $device->ip, $gone; + $device->update_or_insert(undef, {for => 'update'}); + $device->ports->populate([values %interfaces]); + + return Status->noop(sprintf ' [%s] interfaces - added %d new interfaces', + $device->ip, scalar values %interfaces); + }); +}); + true; diff --git a/lib/App/Netdisco/Worker/Plugin/Macsuck/Nodes.pm b/lib/App/Netdisco/Worker/Plugin/Macsuck/Nodes.pm index 2a01d7e9..24fc23f8 100644 --- a/lib/App/Netdisco/Worker/Plugin/Macsuck/Nodes.pm +++ b/lib/App/Netdisco/Worker/Plugin/Macsuck/Nodes.pm @@ -14,7 +14,7 @@ use Dancer::Plugin::DBIC 'schema'; use Time::HiRes 'gettimeofday'; use Scope::Guard 'guard'; -register_worker({ phase => 'check', driver => 'snmp' }, sub { +register_worker({ phase => 'main', driver => 'snmp' }, sub { my ($job, $workerconf) = @_; my $device = $job->device; diff --git a/lib/App/Netdisco/Worker/Plugin/Nbtstat/Core.pm b/lib/App/Netdisco/Worker/Plugin/Nbtstat/Core.pm index f50f31d7..7b12ebea 100644 --- a/lib/App/Netdisco/Worker/Plugin/Nbtstat/Core.pm +++ b/lib/App/Netdisco/Worker/Plugin/Nbtstat/Core.pm @@ -9,7 +9,7 @@ use App::Netdisco::Util::Node 'is_nbtstatable'; use Dancer::Plugin::DBIC 'schema'; use Time::HiRes 'gettimeofday'; -register_worker({ phase => 'check' }, sub { +register_worker({ phase => 'main' }, sub { my ($job, $workerconf) = @_; my $host = $job->device->ip; diff --git a/lib/App/Netdisco/Worker/Plugin/Vlan.pm b/lib/App/Netdisco/Worker/Plugin/Vlan.pm index 52cf4bfb..89a735d8 100644 --- a/lib/App/Netdisco/Worker/Plugin/Vlan.pm +++ b/lib/App/Netdisco/Worker/Plugin/Vlan.pm @@ -4,7 +4,6 @@ use Dancer ':syntax'; use App::Netdisco::Worker::Plugin; use aliased 'App::Netdisco::Worker::Status'; -use App::Netdisco::Transport::SNMP; use App::Netdisco::Util::Port ':all'; register_worker({ phase => 'check' }, sub { @@ -25,75 +24,7 @@ register_worker({ phase => 'check' }, sub { return Status->error("Cannot alter vlan: $vlan_reconfig_check") if $vlan_reconfig_check; - return Status->done("Check phase for update [$pn] vlan $data done."); -}); - -register_worker({ phase => 'main' }, sub { - my ($job, $workerconf) = @_; - my ($device, $pn, $data) = map {$job->$_} qw/device port extra/; - - # snmp connect using rw community - my $snmp = App::Netdisco::Transport::SNMP->writer_for($device) - or return Status->defer("failed to connect to $device to update pvid"); - - my $port = get_port($device, $pn) - or return Status->error("Unknown port name [$pn] on device $device"); - - my $iid = get_iid($snmp, $port) - or return Status->error("Failed to get port ID for [$pn] from $device"); - - my $rv = $snmp->set_i_pvid($data, $iid); - - if (!defined $rv) { - return Status->error(sprintf 'Failed to set [%s] pvid to [%s] on $device: %s', - $pn, $data, ($snmp->error || '')); - } - - # confirm the set happened - $snmp->clear_cache; - my $state = ($snmp->i_pvid($iid) || ''); - if (ref {} ne ref $state or $state->{$iid} ne $data) { - return Status->error("Verify of [$pn] pvid failed on $device"); - } - - # update netdisco DB - $port->update({pvid => $data}); - - return Status->done("Updated [$pn] pvid on [$device] to [$data]"); -}); - -register_worker({ phase => 'main' }, sub { - my ($job, $workerconf) = @_; - my ($device, $pn, $data) = map {$job->$_} qw/device port extra/; - - # snmp connect using rw community - my $snmp = App::Netdisco::Transport::SNMP->writer_for($device) - or return Status->defer("failed to connect to $device to update vlan"); - - my $port = get_port($device, $pn) - or return Status->error("Unknown port name [$pn] on device $device"); - - my $iid = get_iid($snmp, $port) - or return Status->error("Failed to get port ID for [$pn] from $device"); - - my $rv = $snmp->set_i_vlan($data, $iid); - - if (!defined $rv) { - return Status->error(sprintf 'Failed to set [%s] vlan to [%s] on $device: %s', - $pn, $data, ($snmp->error || '')); - } - - # confirm the set happened - $snmp->clear_cache; - my $state = ($snmp->i_vlan($iid) || ''); - if (ref {} ne ref $state or $state->{$iid} ne $data) { - return Status->error("Verify of [$pn] vlan failed on $device"); - } - - # update netdisco DB - $port->update({vlan => $data}); - - return Status->done("Updated [$pn] vlan on [$device] to [$data]"); + return Status->done("Vlan is able to run."); }); true; diff --git a/lib/App/Netdisco/Worker/Plugin/Vlan/Native.pm b/lib/App/Netdisco/Worker/Plugin/Vlan/Native.pm new file mode 100644 index 00000000..12746e5b --- /dev/null +++ b/lib/App/Netdisco/Worker/Plugin/Vlan/Native.pm @@ -0,0 +1,44 @@ +package App::Netdisco::Worker::Plugin::Vlan::Native; + +use Dancer ':syntax'; +use App::Netdisco::Worker::Plugin; +use aliased 'App::Netdisco::Worker::Status'; + +use App::Netdisco::Transport::SNMP; +use App::Netdisco::Util::Port ':all'; + +register_worker({ phase => 'main' }, sub { + my ($job, $workerconf) = @_; + my ($device, $pn, $data) = map {$job->$_} qw/device port extra/; + + # snmp connect using rw community + my $snmp = App::Netdisco::Transport::SNMP->writer_for($device) + or return Status->defer("failed to connect to $device to update vlan"); + + my $port = get_port($device, $pn) + or return Status->error("Unknown port name [$pn] on device $device"); + + my $iid = get_iid($snmp, $port) + or return Status->error("Failed to get port ID for [$pn] from $device"); + + my $rv = $snmp->set_i_vlan($data, $iid); + + if (!defined $rv) { + return Status->error(sprintf 'Failed to set [%s] vlan to [%s] on $device: %s', + $pn, $data, ($snmp->error || '')); + } + + # confirm the set happened + $snmp->clear_cache; + my $state = ($snmp->i_vlan($iid) || ''); + if (ref {} ne ref $state or $state->{$iid} ne $data) { + return Status->error("Verify of [$pn] vlan failed on $device"); + } + + # update netdisco DB + $port->update({vlan => $data}); + + return Status->done("Updated [$pn] vlan on [$device] to [$data]"); +}); + +true; diff --git a/lib/App/Netdisco/Worker/Plugin/Vlan/Port.pm b/lib/App/Netdisco/Worker/Plugin/Vlan/Port.pm new file mode 100644 index 00000000..fdf80c73 --- /dev/null +++ b/lib/App/Netdisco/Worker/Plugin/Vlan/Port.pm @@ -0,0 +1,44 @@ +package App::Netdisco::Worker::Plugin::Vlan::Port; + +use Dancer ':syntax'; +use App::Netdisco::Worker::Plugin; +use aliased 'App::Netdisco::Worker::Status'; + +use App::Netdisco::Transport::SNMP; +use App::Netdisco::Util::Port ':all'; + +register_worker({ phase => 'main' }, sub { + my ($job, $workerconf) = @_; + my ($device, $pn, $data) = map {$job->$_} qw/device port extra/; + + # snmp connect using rw community + my $snmp = App::Netdisco::Transport::SNMP->writer_for($device) + or return Status->defer("failed to connect to $device to update pvid"); + + my $port = get_port($device, $pn) + or return Status->error("Unknown port name [$pn] on device $device"); + + my $iid = get_iid($snmp, $port) + or return Status->error("Failed to get port ID for [$pn] from $device"); + + my $rv = $snmp->set_i_pvid($data, $iid); + + if (!defined $rv) { + return Status->error(sprintf 'Failed to set [%s] pvid to [%s] on $device: %s', + $pn, $data, ($snmp->error || '')); + } + + # confirm the set happened + $snmp->clear_cache; + my $state = ($snmp->i_pvid($iid) || ''); + if (ref {} ne ref $state or $state->{$iid} ne $data) { + return Status->error("Verify of [$pn] pvid failed on $device"); + } + + # update netdisco DB + $port->update({pvid => $data}); + + return Status->done("Updated [$pn] pvid on [$device] to [$data]"); +}); + +true; diff --git a/lib/App/Netdisco/Worker/Runner.pm b/lib/App/Netdisco/Worker/Runner.pm index b347d543..d831a06c 100644 --- a/lib/App/Netdisco/Worker/Runner.pm +++ b/lib/App/Netdisco/Worker/Runner.pm @@ -82,7 +82,6 @@ sub run_workers { return unless scalar @{ $store->get_hooks_for($hook) }; debug "running workers for hook: $hook"; - my $max_level = 0; foreach my $worker (@{ $store->get_hooks_for($hook) }) { try { @@ -90,10 +89,11 @@ sub run_workers { my $retval = $worker->($self->job); if (ref $retval eq 'App::Netdisco::Worker::Status') { - # update (save) the status if we're in check or main phases + # update (save) the status if we're in check, early, or main phases # because these logs can end up in the job queue as status message $self->jobstat($retval) - if ($phase =~ m/^(?:check|main)$/) and $retval->level >= $max_level; + if ($phase =~ m/^(?:check|early|main)$/) + and $retval->level >= $self->jobstat->level; debug $retval->log if $retval->log; }