diff --git a/Build.PL b/Build.PL index ded87058..3d7fdeb6 100644 --- a/Build.PL +++ b/Build.PL @@ -46,7 +46,7 @@ Module::Build->new( 'JSON' => '2.90', 'JSON::XS' => '3.01', 'List::Util' => '1.49', - 'List::MoreUtils' => '0.33', + 'List::MoreUtils' => '0.428', 'MIME::Base64' => '3.13', 'Module::Load' => '0.32', 'Moo' => '1.001000', @@ -72,7 +72,7 @@ Module::Build->new( 'Starman' => '0.4008', 'Storable' => '0', 'Sys::SigAction' => '0', - 'SNMP::Info' => '3.64', + 'SNMP::Info' => '3.65', 'SQL::Abstract' => '1.85', 'SQL::Translator' => '0.11024', 'Template' => '2.24', diff --git a/Changes b/Changes index 708c7b09..f8a2cb73 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,43 @@ +2.040006 - 2019-03-04 + + [BUG FIXES] + + * #527 update List::MoreUtils version requirement + +2.040005 - 2019-03-04 + + [BUG FIXES] + + * #526 fix discover syntax bug + +2.040004 - 2019-03-03 + + [NEW FEATURES] + + * #510 store ifindex in Device Port Properties table (rc9000) + * new discover_waps and discover_phones boolean settings (ollyg) + + [ENHANCEMENTS] + + * #428 Port-Channels now showing in netmap (ollyg) + * #490 use new LLDP capability checks for ports having phones (ollyg) + * #494 update Cisco ASA ssh collector (stromsoe) + + [BUG FIXES] + + * #492 Port Control incorrectly uses VLAN config check (inphobia) + * #493 HTML tag fix (inphobia) + * #498 Map with VLAN filter omits unconnected devices (ollyg) + * #499 netdisco-do renumber reports wrong ip (inphobia) + * #500 no more duplicate entries in vlan filter (ollyg) + * #505 renumbering device missed a few tables (ollyg) + * #512 fix regression in phone/wap discovery exclusion (ollyg) + * #514 ipinventory report returns consistent data (inphobia) + * #520 make sure aggports have a master<->slave (ollyg) + * #521 Search Node Date Range not working (ollyg) + * #522 TypeAhead.pm can reference empty data (inphobia) + * fix bug showing no nodes when only one matches in netmap (ollyg) + 2.040003 - 2019-01-18 [NEW FEATURES] diff --git a/MANIFEST b/MANIFEST index 338458ca..32b20851 100644 --- a/MANIFEST +++ b/MANIFEST @@ -364,6 +364,7 @@ share/schema_versions/App-Netdisco-DB-5-6-PostgreSQL.sql share/schema_versions/App-Netdisco-DB-50-51-PostgreSQL.sql share/schema_versions/App-Netdisco-DB-51-52-PostgreSQL.sql share/schema_versions/App-Netdisco-DB-52-53-PostgreSQL.sql +share/schema_versions/App-Netdisco-DB-53-54-PostgreSQL.sql share/schema_versions/App-Netdisco-DB-6-7-PostgreSQL.sql share/schema_versions/App-Netdisco-DB-7-8-PostgreSQL.sql share/schema_versions/App-Netdisco-DB-8-9-PostgreSQL.sql diff --git a/META.json b/META.json index d25d2b90..5b18dc40 100644 --- a/META.json +++ b/META.json @@ -60,7 +60,7 @@ "IO::Socket::SSL" : "2.048", "JSON" : "2.90", "JSON::XS" : "3.01", - "List::MoreUtils" : "0.33", + "List::MoreUtils" : "0.428", "List::Util" : "1.49", "MCE" : "1.703", "MIME::Base64" : "3.13", @@ -81,7 +81,7 @@ "Plack::Middleware::ReverseProxy" : "0.15", "Pod::Usage" : "0", "Role::Tiny" : "1.002005", - "SNMP::Info" : "3.64", + "SNMP::Info" : "3.65", "SQL::Abstract" : "1.85", "SQL::Translator" : "0.11024", "Scope::Guard" : "0", @@ -118,7 +118,7 @@ "provides" : { "App::Netdisco" : { "file" : "lib/App/Netdisco.pm", - "version" : "2.040003" + "version" : "2.040006" }, "App::Netdisco::AnyEvent::Nbtstat" : { "file" : "lib/App/Netdisco/AnyEvent/Nbtstat.pm" @@ -140,7 +140,7 @@ }, "App::Netdisco::DB" : { "file" : "lib/App/Netdisco/DB.pm", - "version" : "53" + "version" : "54" }, "App::Netdisco::DB::ExplicitLocking" : { "file" : "lib/App/Netdisco/DB/ExplicitLocking.pm" @@ -800,6 +800,6 @@ "x_IRC" : "irc://irc.freenode.org/#netdisco", "x_MailingList" : "https://lists.sourceforge.net/lists/listinfo/netdisco-users" }, - "version" : "2.040003", + "version" : "2.040006", "x_serialization_backend" : "JSON::PP version 2.97001" } diff --git a/META.yml b/META.yml index 42d85541..a5071bc5 100644 --- a/META.yml +++ b/META.yml @@ -22,7 +22,7 @@ name: App-Netdisco provides: App::Netdisco: file: lib/App/Netdisco.pm - version: '2.040003' + version: '2.040006' App::Netdisco::AnyEvent::Nbtstat: file: lib/App/Netdisco/AnyEvent/Nbtstat.pm App::Netdisco::Backend::Job: @@ -37,7 +37,7 @@ provides: file: lib/App/Netdisco/Configuration.pm App::Netdisco::DB: file: lib/App/Netdisco/DB.pm - version: '53' + version: '54' App::Netdisco::DB::ExplicitLocking: file: lib/App/Netdisco/DB/ExplicitLocking.pm App::Netdisco::DB::Result::Admin: @@ -497,7 +497,7 @@ requires: IO::Socket::SSL: '2.048' JSON: '2.90' JSON::XS: '3.01' - List::MoreUtils: '0.33' + List::MoreUtils: '0.428' List::Util: '1.49' MCE: '1.703' MIME::Base64: '3.13' @@ -518,7 +518,7 @@ requires: Plack::Middleware::ReverseProxy: '0.15' Pod::Usage: '0' Role::Tiny: '1.002005' - SNMP::Info: '3.64' + SNMP::Info: '3.65' SQL::Abstract: '1.85' SQL::Translator: '0.11024' Scope::Guard: '0' @@ -549,5 +549,5 @@ resources: homepage: http://netdisco.org/ license: http://opensource.org/licenses/bsd-license.php repository: https://github.com/netdisco/netdisco -version: '2.040003' +version: '2.040006' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' diff --git a/lib/App/Netdisco.pm b/lib/App/Netdisco.pm index d88cdab0..bca470bc 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.040003'; +our $VERSION = '2.040006'; use App::Netdisco::Configuration; =head1 NAME diff --git a/lib/App/Netdisco/DB/Result/Device.pm b/lib/App/Netdisco/DB/Result/Device.pm index a6e06545..412ecdaa 100644 --- a/lib/App/Netdisco/DB/Result/Device.pm +++ b/lib/App/Netdisco/DB/Result/Device.pm @@ -262,20 +262,27 @@ sub renumber { foreach my $set (qw/ DeviceIp DeviceModule - DevicePower - DeviceVlan DevicePort DevicePortLog DevicePortPower + DevicePortProperties DevicePortSsid DevicePortVlan DevicePortWireless + DevicePower + DeviceVlan /) { $schema->resultset($set) ->search({ip => $old_ip}) ->update({ip => $new_ip}); } + $schema->resultset('DeviceSkip') + ->search({device => $new_ip})->delete; + $schema->resultset('DeviceSkip') + ->search({device => $old_ip}) + ->update({device => $new_ip}); + $schema->resultset('DevicePort') ->search({remote_ip => $old_ip}) ->update({remote_ip => $new_ip}); diff --git a/lib/App/Netdisco/DB/Result/Virtual/DeviceLinks.pm b/lib/App/Netdisco/DB/Result/Virtual/DeviceLinks.pm index a503a3ae..9d2339ca 100644 --- a/lib/App/Netdisco/DB/Result/Virtual/DeviceLinks.pm +++ b/lib/App/Netdisco/DB/Result/Virtual/DeviceLinks.pm @@ -22,8 +22,8 @@ __PACKAGE__->result_source_instance->view_definition(<result_source_instance->view_definition(<result_source_instance->view_definition(<result_source_instance->view_definition(<result_source_instance->view_definition(<<'ENDSQL'); d.ip, d.name, d.dns, p.port, p.name AS port_description, p.remote_ip, p.remote_id, p.remote_type, p.remote_port, + dpp.remote_is_wap, dpp.remote_is_phone, l.log AS comment, a.log, a.finished @@ -23,6 +24,7 @@ __PACKAGE__->result_source_instance->view_definition(<<'ENDSQL'); INNER JOIN device d USING (ip) LEFT OUTER JOIN device_skip ds ON ('discover' = ANY(ds.actionset) AND p.remote_ip = ds.device) + LEFT OUTER JOIN device_port_properties dpp USING (ip, port) LEFT OUTER JOIN device_port_log l USING (ip, port) LEFT OUTER JOIN admin a ON (p.remote_ip = a.device AND a.action = 'discover') @@ -58,6 +60,10 @@ __PACKAGE__->add_columns( { data_type => "text", is_nullable => 1 }, "remote_id", { data_type => "text", is_nullable => 1 }, + "remote_is_wap", + { data_type => "boolean", is_nullable => 1 }, + "remote_is_phone", + { data_type => "boolean", is_nullable => 1 }, "comment", { data_type => "text", is_nullable => 1 }, "log", diff --git a/lib/App/Netdisco/DB/ResultSet/Device.pm b/lib/App/Netdisco/DB/ResultSet/Device.pm index 27e6defc..271eeda6 100644 --- a/lib/App/Netdisco/DB/ResultSet/Device.pm +++ b/lib/App/Netdisco/DB/ResultSet/Device.pm @@ -47,16 +47,16 @@ sub with_times { ->search({}, { '+columns' => { - uptime_age => \("replace(age(timestamp 'epoch' + uptime / 100 * interval '1 second', " + uptime_age => \("replace(age(timestamp 'epoch' + me.uptime / 100 * interval '1 second', " ."timestamp '1970-01-01 00:00:00-00')::text, 'mon', 'month')"), first_seen_stamp => \"to_char(me.creation, 'YYYY-MM-DD HH24:MI')", - last_discover_stamp => \"to_char(last_discover, 'YYYY-MM-DD HH24:MI')", - last_macsuck_stamp => \"to_char(last_macsuck, 'YYYY-MM-DD HH24:MI')", - last_arpnip_stamp => \"to_char(last_arpnip, 'YYYY-MM-DD HH24:MI')", + last_discover_stamp => \"to_char(me.last_discover, 'YYYY-MM-DD HH24:MI')", + last_macsuck_stamp => \"to_char(me.last_macsuck, 'YYYY-MM-DD HH24:MI')", + last_arpnip_stamp => \"to_char(me.last_arpnip, 'YYYY-MM-DD HH24:MI')", since_first_seen => \"extract(epoch from (age(now(), me.creation)))", - since_last_discover => \"extract(epoch from (age(now(), last_discover)))", - since_last_macsuck => \"extract(epoch from (age(now(), last_macsuck)))", - since_last_arpnip => \"extract(epoch from (age(now(), last_arpnip)))", + since_last_discover => \"extract(epoch from (age(now(), me.last_discover)))", + since_last_macsuck => \"extract(epoch from (age(now(), me.last_macsuck)))", + since_last_arpnip => \"extract(epoch from (age(now(), me.last_arpnip)))", }, }); } diff --git a/lib/App/Netdisco/Util/Device.pm b/lib/App/Netdisco/Util/Device.pm index a6af95fa..e0fbd211 100644 --- a/lib/App/Netdisco/Util/Device.pm +++ b/lib/App/Netdisco/Util/Device.pm @@ -10,7 +10,7 @@ our @EXPORT_OK = qw/ get_device delete_device renumber_device - match_devicetype + match_to_setting is_discoverable is_discoverable_now is_arpnipable is_arpnipable_now is_macsuckable is_macsuckable_now @@ -120,7 +120,7 @@ sub renumber_device { schema('netdisco')->resultset('UserLog')->create({ username => session('logged_in_user'), userip => scalar eval {request->remote_address}, - event => (sprintf "Renumber device %s to %s", $device->ip, $new_ip), + event => (sprintf "Renumber device %s to %s", $ip, $new_ip), }); $happy = 1; @@ -129,7 +129,7 @@ sub renumber_device { return $happy; } -=head2 match_devicetype( $type, $setting_name ) +=head2 match_to_setting( $type, $setting_name ) Given a C<$type> (which may be any text value), returns true if any of the list of regular expressions in C<$setting_name> is matched, otherwise returns @@ -137,7 +137,7 @@ false. =cut -sub match_devicetype { +sub match_to_setting { my ($type, $setting_name) = @_; return 0 unless $type and $setting_name; return (scalar grep {$type =~ m/$_/} @@ -146,7 +146,7 @@ sub match_devicetype { sub _bail_msg { debug $_[0]; return 0; } -=head2 is_discoverable( $ip, $device_type? ) +=head2 is_discoverable( $ip, [$device_type, \@device_capabilities]? ) Given an IP address, returns C if Netdisco on this host is permitted by the local configuration to discover the device. @@ -154,20 +154,32 @@ the local configuration to discover the device. The configuration items C and C are checked against the given IP. -If C<$device_type> is also given, then C will also be -checked. +If C<$device_type> is also given, then C will be checked. +Also respects C and C if either are set to +false. Returns false if the host is not permitted to discover the target device. =cut sub is_discoverable { - my ($ip, $remote_type) = @_; + my ($ip, $remote_type, $remote_cap) = @_; my $device = get_device($ip) or return 0; + $remote_type ||= ''; + $remote_cap ||= []; - if (match_devicetype($remote_type, 'discover_no_type')) { - return _bail_msg("is_discoverable: $device matched discover_no_type"); - } + 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 + scalar grep {match_to_setting($_, 'wap_capabilities')} @$remote_cap)); + + return _bail_msg("is_discoverable: $device matches phone_platforms but discover_phones is not enabled") + if ((not setting('discover_phones')) and + (match_to_setting($remote_type, 'phone_platforms') or + scalar grep {match_to_setting($_, 'phone_capabilities')} @$remote_cap)); + + return _bail_msg("is_discoverable: $device matched discover_no_type") + if (match_to_setting($remote_type, 'discover_no_type')); return _bail_msg("is_discoverable: $device matched discover_no") if check_acl_no($device, 'discover_no'); diff --git a/lib/App/Netdisco/Web/Device.pm b/lib/App/Netdisco/Web/Device.pm index e4cfdd00..010ed550 100644 --- a/lib/App/Netdisco/Web/Device.pm +++ b/lib/App/Netdisco/Web/Device.pm @@ -7,7 +7,7 @@ use Dancer::Plugin::Auth::Extensible; use URI (); use URL::Encode 'url_params_mixed'; -use App::Netdisco::Util::Device 'match_devicetype'; +use App::Netdisco::Util::Device 'match_to_setting'; # build view settings for port connected nodes and devices set('connected_properties' => [ @@ -20,7 +20,7 @@ hook 'before_template' => sub { my $tokens = shift; # allow checking of discoverability of remote connected device - $tokens->{has_snmp} = sub { not match_devicetype(shift, 'discover_no_type') }; + $tokens->{has_snmp} = sub { not match_to_setting(shift, 'discover_no_type') }; my $defaults = var('sidebar_defaults')->{'device_ports'} or return; diff --git a/lib/App/Netdisco/Web/Plugin/AdminTask/UndiscoveredNeighbors.pm b/lib/App/Netdisco/Web/Plugin/AdminTask/UndiscoveredNeighbors.pm index d409d3cb..293d2525 100644 --- a/lib/App/Netdisco/Web/Plugin/AdminTask/UndiscoveredNeighbors.pm +++ b/lib/App/Netdisco/Web/Plugin/AdminTask/UndiscoveredNeighbors.pm @@ -27,6 +27,8 @@ get '/ajax/content/admin/undiscoveredneighbors' => require_role admin => sub { # create a new row object to avoid hitting the DB in get_device() my $dev = schema('netdisco')->resultset('Device')->new({ip => $r->{remote_ip}}); next unless is_discoverable( $dev, $r->{remote_type} ); + next if (not setting('discover_waps')) and $r->{remote_is_wap}; + next if (not setting('discover_phones')) and $r->{remote_is_phone}; push @discoverable_results, $r; } return unless scalar @discoverable_results; diff --git a/lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm b/lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm index bc1e3aec..bb63739e 100644 --- a/lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm +++ b/lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm @@ -125,18 +125,13 @@ sub make_link_infostring { (my $left_name = lc($link->{left_dns} || $link->{left_name} || $link->{left_ip})) =~ s/$domain$//; (my $right_name = lc($link->{right_dns} || $link->{right_name} || $link->{right_ip})) =~ s/$domain$//; - if ($link->{aggports} == 1) { - return sprintf '%s:%s (%s)
%s:%s (%s)', - $left_name, $link->{left_port}->[0], - ($link->{left_descr}->[0] || 'no description'), - $right_name, $link->{right_port}->[0], - ($link->{right_descr}->[0] || 'no description'); - } - else { - return sprintf '%s:(%s)
%s:(%s)', - $left_name, join(',', @{$link->{left_port}}), - $right_name, join(',', @{$link->{right_port}}); - } + my @zipped = List::MoreUtils::zip6 + @{$link->{left_port}}, @{$link->{left_descr}}, + @{$link->{right_port}}, @{$link->{right_descr}}; + + return join '

', map { sprintf '%s:%s (%s)
%s:%s (%s)', + $left_name, $_->[0], ($_->[1] || 'no description'), + $right_name, $_->[2], ($_->[3] || 'no description') } @zipped; } ajax '/ajax/data/device/netmap' => require_login sub { @@ -179,17 +174,6 @@ ajax '/ajax/data/device/netmap' => require_login sub { ]) : ()) }, { result_class => 'DBIx::Class::ResultClass::HashRefInflator' }); - if ($vlan) { - $links = $links->search({ - -or => [ - { 'left_vlans.vlan' => $vlan }, - { 'right_vlans.vlan' => $vlan }, - ], - }, { - join => [qw/left_vlans right_vlans/], - }); - } - while (my $link = $links->next) { push @{$data{'links'}}, { FROMID => $link->{left_ip}, @@ -217,10 +201,19 @@ ajax '/ajax/data/device/netmap' => require_login sub { join => 'throughput', })->with_times; + # filter by vlan for all or neighbors only + if ($vlan) { + $devices = $devices->search( + { 'vlans.vlan' => $vlan }, + { join => 'vlans' } + ); + } + DEVICE: while (my $device = $devices->next) { - # if in neighbors or vlan mode then use %ok_dev to filter - next DEVICE if (($mapshow eq 'neighbors') or $vlan) - and (not $ok_dev{$device->ip}); + # if in neighbors mode then use %ok_dev to filter + next DEVICE if ($device->ip ne $qdev->ip) + and ($mapshow eq 'neighbors') + and (not $ok_dev{$device->ip}); # showing only neighbors but no link # if location picked then filter next DEVICE if ((scalar @lgrplist) and ((!defined $device->location) diff --git a/lib/App/Netdisco/Web/Plugin/Device/Ports.pm b/lib/App/Netdisco/Web/Plugin/Device/Ports.pm index b5276052..be5f98ea 100644 --- a/lib/App/Netdisco/Web/Plugin/Device/Ports.pm +++ b/lib/App/Netdisco/Web/Plugin/Device/Ports.pm @@ -25,25 +25,6 @@ get '/ajax/content/device/ports' => require_login sub { if ($f) { if (($prefer eq 'vlan') or (not $prefer and $f =~ m/^\d+$/)) { return unless $f =~ m/^\d+$/; - - if (param('invert')) { - $set = $set->search({ - 'me.vlan' => { '!=' => $f }, - 'port_vlans.vlan' => [ - '-or' => { '!=' => $f }, { '=' => undef } - ], - }, { join => 'port_vlans' }); - } - else { - $set = $set->search({ - -or => { - 'me.vlan' => $f, - 'port_vlans.vlan' => $f, - }, - }, { join => 'port_vlans' }); - } - - return unless $set->count; } else { if (param('partial')) { @@ -120,7 +101,7 @@ get '/ajax/content/device/ports' => require_login sub { # now begin to join tables depending on the selected columns/options # get vlans on the port - # leave this query dormant (lazy) unless c_vmember is set + # leave this query dormant (lazy) unless c_vmember is set or vlan filtering my $vlans = $set->search({}, { select => [ 'port', @@ -131,7 +112,7 @@ get '/ajax/content/device/ports' => require_login sub { group_by => 'me.port', }); - if (param('c_vmember')) { + if (param('c_vmember') or ($prefer eq 'vlan') or (not $prefer and $f =~ m/^\d+$/)) { $vlans = { map {( $_->port => { # DBIC smart enough to work out this should be an arrayref :) @@ -194,13 +175,37 @@ get '/ajax/content/device/ports' => require_login sub { # also get remote LLDP inventory if asked for $set = $set->with_remote_inventory if param('n_inventory'); - # sort ports (empty set would be a 'no records' msg) - my $results = [ sort { &App::Netdisco::Util::Web::sort_port($a->port, $b->port) } $set->all ]; - return unless scalar @$results; + # run query + my @results = $set->all; + + # filter for tagged vlan using existing agg query, + # which is better than join inflation + if (($prefer eq 'vlan') or (not $prefer and $f =~ m/^\d+$/)) { + if (param('invert')) { + @results = grep { + (!defined $_->vlan or $_->vlan ne $f) + and + (0 == scalar grep {defined and $_ ne $f} @{ $vlans->{$_->port}->{vlan_set} }) + } @results; + } + else { + @results = grep { + ($_->vlan eq $f) + or + (scalar grep {defined and $_ eq $f} @{ $vlans->{$_->port}->{vlan_set} }) + } @results; + } + } + + # sort ports + @results = sort { &App::Netdisco::Util::Web::sort_port($a->port, $b->port) } @results; + + # empty set would be a 'no records' msg + return unless scalar @results; if (request->is_ajax) { template 'ajax/device/ports.tt', { - results => $results, + results => \@results, nodes => $nodes_name, ips => $ips_name, device => $device, @@ -210,7 +215,7 @@ get '/ajax/content/device/ports' => require_login sub { else { header( 'Content-Type' => 'text/comma-separated-values' ); template 'ajax/device/ports_csv.tt', { - results => $results, + results => \@results, nodes => $nodes_name, ips => $ips_name, device => $device, diff --git a/lib/App/Netdisco/Web/Plugin/Report/IpInventory.pm b/lib/App/Netdisco/Web/Plugin/Report/IpInventory.pm index 315db783..0fc809f0 100644 --- a/lib/App/Netdisco/Web/Plugin/Report/IpInventory.pm +++ b/lib/App/Netdisco/Web/Plugin/Report/IpInventory.pm @@ -110,12 +110,12 @@ get '/ajax/content/report/ipinventory' => require_login sub { 'ip', 'mac', 'dns', 'time_last', 'time_first', 'active', 'node', 'age' ], - order_by => [{-asc => 'ip'}, {-desc => 'active'}], + order_by => [{-asc => 'ip'}, {-desc => 'active'}, {-asc => 'node'}], } )->as_query; my $rs; - if ( $start && $end ) { + if ( $start and $end ) { $start = $start . ' 00:00:00'; $end = $end . ' 23:59:59'; diff --git a/lib/App/Netdisco/Web/Plugin/Search/Node.pm b/lib/App/Netdisco/Web/Plugin/Search/Node.pm index 45394e2c..090802a5 100644 --- a/lib/App/Netdisco/Web/Plugin/Search/Node.pm +++ b/lib/App/Netdisco/Web/Plugin/Search/Node.pm @@ -27,35 +27,51 @@ ajax '/ajax/content/search/node' => require_login sub { my @active = (param('archived') ? () : (-bool => 'active')); my (@times, @wifitimes, @porttimes); - if ($start and $end) { + if ( $start and $end ) { $start = $start . ' 00:00:00'; $end = $end . ' 23:59:59'; + if ($agenot) { @times = (-or => [ - time_first => [ { '<', $start }, undef ], - time_last => { '>', $end }, + time_first => [ undef ], + time_last => [ { '<', $start }, { '>', $end } ] ]); @wifitimes = (-or => [ - time_last => { '<', $start }, - time_last => { '>', $end }, + time_first => [ undef ], + time_last => [ { '<', $start }, { '>', $end } ] ]); @porttimes = (-or => [ - creation => { '<', $start }, - creation => { '>', $end }, + creation => [ undef ], + creation => [ { '<', $start }, { '>', $end } ] ]); } else { - @times = (-and => [ - time_first => { '>=', $start }, - time_last => { '<=', $end }, + @times = (-or => [ + -and => [ + time_first => undef, + time_last => undef, + ], + -and => [ + time_last => { '>=', $start }, + time_last => { '<=', $end }, + ], ]); - @wifitimes = (-and => [ - time_last => { '>=', $start }, - time_last => { '<=', $end }, + @wifitimes = (-or => [ + -and => [ + time_first => undef, + time_last => undef, + ], + -and => [ + time_last => { '>=', $start }, + time_last => { '<=', $end }, + ], ]); - @porttimes = (-and => [ - creation => { '>=', $start }, - creation => { '<=', $end }, + @porttimes = (-or => [ + creation => undef, + -and => [ + creation => { '>=', $start }, + creation => { '<=', $end }, + ], ]); } } diff --git a/lib/App/Netdisco/Web/TypeAhead.pm b/lib/App/Netdisco/Web/TypeAhead.pm index 3994302e..40c7da62 100644 --- a/lib/App/Netdisco/Web/TypeAhead.pm +++ b/lib/App/Netdisco/Web/TypeAhead.pm @@ -49,7 +49,7 @@ ajax '/ajax/data/port/typeahead' => require_login sub { if $port; my $results = [ - map {{ label => (sprintf "%s (%s)", $_->port, $_->name), value => $_->port }} + map {{ label => (sprintf "%s (%s)", $_->port, ($_->name || '')), value => $_->port }} sort { &App::Netdisco::Util::Web::sort_port($a->port, $b->port) } $set->all ]; diff --git a/lib/App/Netdisco/Worker/Plugin/Discover/Neighbors.pm b/lib/App/Netdisco/Worker/Plugin/Discover/Neighbors.pm index 6a64b8ee..a546a58d 100644 --- a/lib/App/Netdisco/Worker/Plugin/Discover/Neighbors.pm +++ b/lib/App/Netdisco/Worker/Plugin/Discover/Neighbors.pm @@ -45,7 +45,7 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub { # only enqueue if device is not already discovered, # discover_* config permits the discovery foreach my $neighbor (@to_discover) { - my ($ip, $remote_type, $remote_id) = @$neighbor; + my ($ip, $remote_id) = @$neighbor; if ($seen_ip{ $ip }++) { debug sprintf ' queue - skip: IP %s is already queued from %s', @@ -63,13 +63,6 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub { my $newdev = get_device($ip); next if $newdev->in_storage; - if (not is_discoverable($newdev, $remote_type)) { - debug sprintf - ' queue - skip: %s of type [%s] excluded by discover_* config', - $ip, ($remote_type || ''); - next; - } - # risk of things going wrong...? # https://quickview.cloudapps.cisco.com/quickview/bug/CSCur12254 @@ -127,6 +120,7 @@ sub store_neighbors { my $c_port = $snmp->c_port; my $c_id = $snmp->c_id; my $c_platform = $snmp->c_platform; + my $c_cap = $snmp->c_cap; # cache the device ports to save hitting the database for many single rows vars->{'device_ports'} = @@ -176,6 +170,7 @@ sub store_neighbors { my $remote_port = undef; my $remote_type = Encode::decode('UTF-8', $c_platform->{$entry} || ''); my $remote_id = Encode::decode('UTF-8', $c_id->{$entry}); + my $remote_cap = $c_cap->{$entry} || []; next unless $remote_ip; my $r_netaddr = NetAddr::IP::Lite->new($remote_ip); @@ -246,7 +241,15 @@ sub store_neighbors { # what we came here to do.... discover the neighbor debug sprintf ' [%s] neigh - %s with ID [%s] on %s', $device->ip, $remote_ip, ($remote_id || ''), $port; - push @to_discover, [$remote_ip, $remote_type, $remote_id]; + + if (is_discoverable($remote_ip, $remote_type, $remote_cap)) { + push @to_discover, [$remote_ip, $remote_id]; + } + else { + debug sprintf + ' [%s] neigh - skip: %s of type [%s] excluded by discover_* config', + $device->ip, $remote_ip, ($remote_type || ''); + } $remote_port = $c_port->{$entry}; if (defined $remote_port) { diff --git a/lib/App/Netdisco/Worker/Plugin/Discover/PortProperties.pm b/lib/App/Netdisco/Worker/Plugin/Discover/PortProperties.pm index 8b492021..5803cc6c 100644 --- a/lib/App/Netdisco/Worker/Plugin/Discover/PortProperties.pm +++ b/lib/App/Netdisco/Worker/Plugin/Discover/PortProperties.pm @@ -8,7 +8,7 @@ use App::Netdisco::Transport::SNMP (); use Dancer::Plugin::DBIC 'schema'; use Encode; -use App::Netdisco::Util::Device 'match_devicetype'; +use App::Netdisco::Util::Device 'match_to_setting'; register_worker({ phase => 'main', driver => 'snmp' }, sub { my ($job, $workerconf) = @_; @@ -86,12 +86,12 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub { my $remote_type = Encode::decode('UTF-8', $c_platform->{$idx} || ''); $properties{ $port }->{remote_is_wap} = 'true' - if scalar grep {match_devicetype($_, 'wap_capabilities')} @$remote_cap - or match_devicetype($remote_type, 'wap_platforms'); + if scalar grep {match_to_setting($_, 'wap_capabilities')} @$remote_cap + or match_to_setting($remote_type, 'wap_platforms'); $properties{ $port }->{remote_is_phone} = 'true' - if scalar grep {match_devicetype($_, 'phone_capabilities')} @$remote_cap - or match_devicetype($remote_type, 'phone_platforms'); + if scalar grep {match_to_setting($_, 'phone_capabilities')} @$remote_cap + or match_to_setting($remote_type, 'phone_platforms'); next unless scalar grep {defined && m/^inventory$/} @{ $rem_media_cap->{$idx} }; diff --git a/lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm b/lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm index 63240c3d..95d2340d 100644 --- a/lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm +++ b/lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm @@ -238,6 +238,7 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub { # 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; + next unless defined $agg_ports->{$sidx}; # slave without a master?! my $master = $interfaces->{ $agg_ports->{$sidx} } or next; next unless exists $interfaces{$slave} and exists $interfaces{$master}; diff --git a/lib/App/Netdisco/Worker/Plugin/Macsuck/Nodes.pm b/lib/App/Netdisco/Worker/Plugin/Macsuck/Nodes.pm index 0b150d1c..9ea9dfb9 100644 --- a/lib/App/Netdisco/Worker/Plugin/Macsuck/Nodes.pm +++ b/lib/App/Netdisco/Worker/Plugin/Macsuck/Nodes.pm @@ -7,7 +7,7 @@ use aliased 'App::Netdisco::Worker::Status'; use App::Netdisco::Transport::SNMP (); use App::Netdisco::Util::Permission 'check_acl_no'; use App::Netdisco::Util::PortMAC 'get_port_macs'; -use App::Netdisco::Util::Device 'match_devicetype'; +use App::Netdisco::Util::Device 'match_to_setting'; use App::Netdisco::Util::Node 'check_mac'; use App::Netdisco::Util::SNMP 'snmp_comm_reindex'; use Dancer::Plugin::DBIC 'schema'; @@ -342,7 +342,7 @@ sub walk_fwtable { # neighbors otherwise it would kill the DB with device lookups. my $neigh_cannot_macsuck = eval { # can fail check_acl_no(($device_port->neighbor || "0 but true"), 'macsuck_unsupported') || - match_devicetype($device_port->remote_type, 'macsuck_unsupported_type') }; + match_to_setting($device_port->remote_type, 'macsuck_unsupported_type') }; if ($device_port->is_uplink) { if ($neigh_cannot_macsuck) { diff --git a/share/config.yml b/share/config.yml index be6950f2..24b31d66 100644 --- a/share/config.yml +++ b/share/config.yml @@ -229,9 +229,9 @@ devices_no: [] devices_only: [] discover_no: [] discover_only: [] -discover_no_type: - - '(?i)phone' - - '(?i)(?:wap|wireless)' +discover_no_type: [] +discover_waps: true +discover_phones: false discover_min_age: 0 macsuck_no: [] macsuck_only: [] diff --git a/share/environments/deployment.yml b/share/environments/deployment.yml index cd792907..a1147c97 100644 --- a/share/environments/deployment.yml +++ b/share/environments/deployment.yml @@ -39,20 +39,18 @@ device_auth: # ¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸ +# +# SOME MORE INTERESTING SETTINGS WHERE THE DEFAULTS ARE PROBABLY OKAY +# # ¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸ -# --------------------------------------------------------------- -# OTHER INTERESTING SETTINGS WHERE THE DEFAULTS ARE PROBABLY OKAY -# --------------------------------------------------------------- - -# do not discover IP Phones or Wireless Access Points. +# discover Wireless Access Points, but not IP Phones # usually these are visible as device neighbors but don't support # SNMP, which just clogs up the job queue. # ``````````````````````````````````````````````````````````````` -#discover_no_type: -# - '(?i)phone' -# - '(?i)(?:wap|wireless)' +#discover_waps: true +#disover_phones: false # this is the schedule for automatically keeping netdisco up-to-date; # these are good defaults, so only uncomment if needing to change.