diff --git a/lib/App/Netdisco/JobQueue/PostgreSQL.pm b/lib/App/Netdisco/JobQueue/PostgreSQL.pm index e332131a..c8faf5b8 100644 --- a/lib/App/Netdisco/JobQueue/PostgreSQL.pm +++ b/lib/App/Netdisco/JobQueue/PostgreSQL.pm @@ -79,6 +79,19 @@ sub jq_warm_thrusters { actionset => $actionset{$_}, }, { key => 'primary' }) for keys %actionset; }); + + # fix up the pseudo devices which need layer 3 + # TODO remove this after next release + schema('netdisco')->txn_do(sub { + my @hosts = grep { defined } + map { schema('netdisco')->resultset('Device')->search_for_device($_->{only}) } + grep { exists $_->{only} and ref '' eq ref $_->{only} } + grep { exists $_->{driver} and $_->{driver} eq 'cli' } + @{ setting('device_auth') }; + + $_->update({ layers => \[q{overlay(layers placing '1' from 6 for 1)}] }) + for @hosts; + }); } sub jq_getsome { diff --git a/lib/App/Netdisco/Transport/SNMP.pm b/lib/App/Netdisco/Transport/SNMP.pm index f342155b..5fbf5fed 100644 --- a/lib/App/Netdisco/Transport/SNMP.pm +++ b/lib/App/Netdisco/Transport/SNMP.pm @@ -58,8 +58,11 @@ Returns C if the connection fails. sub reader_for { my ($class, $ip, $useclass) = @_; my $device = get_device($ip) or return undef; + return undef if $device->in_storage and $device->is_pseudo; + my $readers = $class->instance->readers or return undef; return $readers->{$device->ip} if exists $readers->{$device->ip}; + debug sprintf 'snmp reader cache warm: [%s]', $device->ip; return ($readers->{$device->ip} = _snmp_connect_generic('read', $device, $useclass)); @@ -104,8 +107,11 @@ Returns C if the connection fails. sub writer_for { my ($class, $ip, $useclass) = @_; my $device = get_device($ip) or return undef; + return undef if $device->in_storage and $device->is_pseudo; + my $writers = $class->instance->writers or return undef; return $writers->{$device->ip} if exists $writers->{$device->ip}; + debug sprintf 'snmp writer cache warm: [%s]', $device->ip; return ($writers->{$device->ip} = _snmp_connect_generic('write', $device, $useclass)); diff --git a/lib/App/Netdisco/Util/Device.pm b/lib/App/Netdisco/Util/Device.pm index e0fbd211..6c31583a 100644 --- a/lib/App/Netdisco/Util/Device.pm +++ b/lib/App/Netdisco/Util/Device.pm @@ -158,6 +158,8 @@ If C<$device_type> is also given, then C will be checked. Also respects C and C if either are set to false. +Also checks if the device is a pseudo device (vendor is C). + Returns false if the host is not permitted to discover the target device. =cut @@ -168,6 +170,9 @@ sub is_discoverable { $remote_type ||= ''; $remote_cap ||= []; + return _bail_msg("is_discoverable: $device is pseudo-device") + if $device->is_pseudo; + return _bail_msg("is_discoverable: $device matches wap_platforms but discover_waps is not enabled") if ((not setting('discover_waps')) and (match_to_setting($remote_type, 'wap_platforms') or @@ -192,9 +197,8 @@ sub is_discoverable { =head2 is_discoverable_now( $ip, $device_type? ) -Same as C, but also checks the last_discover field if the -device is in storage, and returns false if that host has been too recently -discovered. +Same as C, but also compares the C field +of the C to the C configuration. Returns false if the host is not permitted to discover the target device. @@ -222,6 +226,8 @@ the local configuration to arpnip the device. The configuration items C and C are checked against the given IP. +Also checks if the device reports layer 3 capability. + Returns false if the host is not permitted to arpnip the target device. =cut @@ -230,6 +236,9 @@ sub is_arpnipable { my $ip = shift; my $device = get_device($ip) or return 0; + return _bail_msg("is_arpnipable: $device has no layer 3 capability") + unless $device->has_layer(3); + return _bail_msg("is_arpnipable: $device matched arpnip_no") if check_acl_no($device, 'arpnip_no'); @@ -241,9 +250,8 @@ sub is_arpnipable { =head2 is_arpnipable_now( $ip ) -Same as C, but also checks the last_arpnip field if the -device is in storage, and returns false if that host has been too recently -arpnipped. +Same as C, but also compares the C field +of the C to the C configuration. Returns false if the host is not permitted to arpnip the target device. @@ -271,6 +279,8 @@ the local configuration to macsuck the device. The configuration items C and C are checked against the given IP. +Also checks if the device reports layer 2 capability. + Returns false if the host is not permitted to macsuck the target device. =cut @@ -279,6 +289,9 @@ sub is_macsuckable { my $ip = shift; my $device = get_device($ip) or return 0; + return _bail_msg("is_macsuckable: $device has no layer 2 capability") + unless $device->has_layer(2); + return _bail_msg("is_macsuckable: $device matched macsuck_no") if check_acl_no($device, 'macsuck_no'); @@ -290,9 +303,8 @@ sub is_macsuckable { =head2 is_macsuckable_now( $ip ) -Same as C, but also checks the last_macsuck field if the -device is in storage, and returns false if that host has been too recently -macsucked. +Same as C, but also compares the C field +of the C to the C configuration. Returns false if the host is not permitted to macsuck the target device. diff --git a/lib/App/Netdisco/Web/Plugin/AdminTask/PseudoDevice.pm b/lib/App/Netdisco/Web/Plugin/AdminTask/PseudoDevice.pm index 15d3f15d..dac18e58 100644 --- a/lib/App/Netdisco/Web/Plugin/AdminTask/PseudoDevice.pm +++ b/lib/App/Netdisco/Web/Plugin/AdminTask/PseudoDevice.pm @@ -36,7 +36,7 @@ ajax '/ajax/control/admin/pseudodevice/add' => require_role admin => sub { ip => param('ip'), dns => param('dns'), vendor => 'netdisco', - layers => '00000100', + layers => param('layers'), last_discover => \'now()', }); return unless $device; @@ -87,6 +87,9 @@ ajax '/ajax/control/admin/pseudodevice/update' => require_role admin => sub { })->delete; } } + + # also set layers + $device->update({layers => param('layers')}); }); }; diff --git a/lib/App/Netdisco/Worker/Plugin/Arpnip.pm b/lib/App/Netdisco/Worker/Plugin/Arpnip.pm index 12e8f1e3..1637b5df 100644 --- a/lib/App/Netdisco/Worker/Plugin/Arpnip.pm +++ b/lib/App/Netdisco/Worker/Plugin/Arpnip.pm @@ -16,9 +16,6 @@ register_worker({ phase => 'check' }, sub { return Status->error("arpnip skipped: $device not yet discovered") unless $device->in_storage; - return Status->info("arpnip skipped: $device has no layer 3 capability") - unless $device->has_layer(3); - return Status->info("arpnip skipped: $device is not arpnipable") unless is_arpnipable_now($device); diff --git a/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm b/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm index b6122f35..91ba0303 100644 --- a/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm +++ b/lib/App/Netdisco/Worker/Plugin/Arpnip/Nodes.pm @@ -55,6 +55,7 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub { push @{ vars->{'v6arps'} }, @{get_arps_snmp($device, $snmp->ipv6_n2p_mac, $snmp->ipv6_n2p_addr) }; + $device->update({layers => \[q{overlay(layers placing '1' from 6 for 1)}]}); return Status->done("Gathered arp caches from $device"); }); @@ -82,24 +83,25 @@ sub get_arps_snmp { } register_worker({ phase => 'main', driver => 'cli' }, sub { - my ($job, $workerconf) = @_; + my ($job, $workerconf) = @_; - my $device = $job->device; - my $cli = App::Netdisco::Transport::SSH->session_for($device) - or return Status->defer("arpnip failed: could not SSH connect to $device"); + my $device = $job->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 - my @arps = @{ get_arps_cli($device, [$cli->arpnip]) }; + # should be both v4 and v6 + my @arps = @{ get_arps_cli($device, [$cli->arpnip]) }; - # cache v4 arp table - push @{ vars->{'v4arps'} }, - grep { NetAddr::IP::Lite->new($_->{ip})->bits == 32 } @arps; + # cache v4 arp table + push @{ vars->{'v4arps'} }, + grep { NetAddr::IP::Lite->new($_->{ip})->bits == 32 } @arps; - # cache v6 neighbor cache - push @{ vars->{'v6arps'} }, - grep { NetAddr::IP::Lite->new($_->{ip})->bits == 128 } @arps; + # cache v6 neighbor cache + push @{ vars->{'v6arps'} }, + grep { NetAddr::IP::Lite->new($_->{ip})->bits == 128 } @arps; - return Status->done("Gathered arp caches from $device"); + $device->update({layers => \[q{overlay(layers placing '1' from 6 for 1)}]}); + return Status->done("Gathered arp caches from $device"); }); sub get_arps_cli { diff --git a/lib/App/Netdisco/Worker/Plugin/Discover.pm b/lib/App/Netdisco/Worker/Plugin/Discover.pm index d65d274e..5934b8b3 100644 --- a/lib/App/Netdisco/Worker/Plugin/Discover.pm +++ b/lib/App/Netdisco/Worker/Plugin/Discover.pm @@ -16,9 +16,6 @@ register_worker({ phase => 'check' }, sub { return Status->error("discover failed: no device param (need -d ?)") if $device->ip eq '0.0.0.0'; - return Status->info("discover skipped: $device is pseudo-device") - if $device->is_pseudo; - # runner has already called get_device to promote $job->device return $job->cancel("fresh discover cancelled: $device already known") if $device->in_storage diff --git a/lib/App/Netdisco/Worker/Plugin/Macsuck.pm b/lib/App/Netdisco/Worker/Plugin/Macsuck.pm index 8f90fdf0..13b61065 100644 --- a/lib/App/Netdisco/Worker/Plugin/Macsuck.pm +++ b/lib/App/Netdisco/Worker/Plugin/Macsuck.pm @@ -16,12 +16,6 @@ register_worker({ phase => 'check' }, sub { return Status->error("macsuck skipped: $device not yet discovered") unless $device->in_storage; - return Status->info("macsuck skipped: $device is pseudo-device") - if $device->is_pseudo; - - return Status->info("macsuck skipped: $device has no layer 2 capability") - unless $device->has_layer(2); - return Status->info("macsuck skipped: $device is not macsuckable") unless is_macsuckable_now($device); diff --git a/share/public/css/netdisco.css b/share/public/css/netdisco.css index 71136174..5e2fedaf 100644 --- a/share/public/css/netdisco.css +++ b/share/public/css/netdisco.css @@ -245,6 +245,13 @@ td > form.nd_inline-form { text-decoration: none; } +/* badge for pseudo devices layer three toggle */ +.nd_layer-three-link { + text-decoration: none !important; + display: inline-block; + margin-left: -4px; +} + /* for the job control admin page play/pause links */ #nd_countdown-refresh:hover, #nd_countdown-control:hover { text-decoration: none; diff --git a/share/schema_versions/App-Netdisco-DB-58-59-PostgreSQL.sql b/share/schema_versions/App-Netdisco-DB-58-59-PostgreSQL.sql index cd073f78..53983c95 100644 --- a/share/schema_versions/App-Netdisco-DB-58-59-PostgreSQL.sql +++ b/share/schema_versions/App-Netdisco-DB-58-59-PostgreSQL.sql @@ -2,4 +2,10 @@ BEGIN; ALTER TABLE users ADD COLUMN "radius" boolean DEFAULT false; +UPDATE device SET layers = NULL WHERE vendor = 'netdisco'; + +UPDATE device SET layers = '00000000' WHERE layers IS NULL; + +ALTER TABLE device ALTER layers SET DEFAULT '00000000'; + COMMIT; diff --git a/share/views/ajax/admintask/pseudodevice.tt b/share/views/ajax/admintask/pseudodevice.tt index d08fce1b..7416eace 100644 --- a/share/views/ajax/admintask/pseudodevice.tt +++ b/share/views/ajax/admintask/pseudodevice.tt @@ -4,6 +4,7 @@ Device Name Device IP Number of Ports + Services Action @@ -11,7 +12,12 @@ - + + +    + 3     + + @@ -26,6 +32,11 @@ + +    + 3     + + @@ -68,6 +79,17 @@ $(document).ready(function() { } ], [% INCLUDE 'ajax/datatabledefaults.tt' -%] } ); + $('.nd_layer-three-link').click(function() { + var badge = $(this).children('span').first(); + var layers = $(this).parent().children('input').first(); + $(badge).toggleClass('badge-success'); + if ($(badge).hasClass('badge-success')) { + $(layers).attr('value', '00000100'); + } + else { + $(layers).attr('value', '00000000'); + } + }); } ); diff --git a/share/views/ajax/admintask/users.tt b/share/views/ajax/admintask/users.tt index 2378a358..f5fbfa05 100644 --- a/share/views/ajax/admintask/users.tt +++ b/share/views/ajax/admintask/users.tt @@ -26,7 +26,7 @@ - + @@ -62,7 +62,7 @@ - +