#925 implement ignore_deviceports and hide_deviceports
This commit is contained in:
1
Build.PL
1
Build.PL
@@ -90,6 +90,7 @@ Module::Build->new(
|
|||||||
'SNMP::Info' => '3.89',
|
'SNMP::Info' => '3.89',
|
||||||
'SQL::Abstract' => '1.85',
|
'SQL::Abstract' => '1.85',
|
||||||
'SQL::Translator' => '0.11024',
|
'SQL::Translator' => '0.11024',
|
||||||
|
'Sub::Install' => '0',
|
||||||
'Sub::Util' => '1.40',
|
'Sub::Util' => '1.40',
|
||||||
'Template' => '2.24',
|
'Template' => '2.24',
|
||||||
'Template::AutoFilter' => '0',
|
'Template::AutoFilter' => '0',
|
||||||
|
|||||||
@@ -204,6 +204,30 @@ if (ref {} eq ref setting('macsuck_no_deviceport')) {
|
|||||||
}
|
}
|
||||||
else { config->{'macsuck_no_deviceport'} ||= [] }
|
else { config->{'macsuck_no_deviceport'} ||= [] }
|
||||||
|
|
||||||
|
if (ref {} eq ref setting('hide_deviceports')) {
|
||||||
|
config->{'hide_deviceports'} = [ setting('hide_deviceports') ];
|
||||||
|
}
|
||||||
|
else { config->{'hide_deviceports'} ||= [] }
|
||||||
|
|
||||||
|
if (ref {} eq ref setting('ignore_deviceports')) {
|
||||||
|
config->{'ignore_deviceports'} = [ setting('ignore_deviceports') ];
|
||||||
|
}
|
||||||
|
else { config->{'ignore_deviceports'} ||= [] }
|
||||||
|
|
||||||
|
# copy old ignore_* into new settings
|
||||||
|
if (scalar @{ config->{'ignore_interfaces'} }) {
|
||||||
|
config->{'host_groups'}->{'__IGNORE_INTERFACES__'}
|
||||||
|
= config->{'ignore_interfaces'};
|
||||||
|
}
|
||||||
|
if (scalar @{ config->{'ignore_interface_types'} }) {
|
||||||
|
config->{'host_groups'}->{'__IGNORE_INTERFACE_TYPES__'}
|
||||||
|
= config->{'ignore_interface_types'};
|
||||||
|
}
|
||||||
|
if (scalar @{ config->{'ignore_notpresent_types'} }) {
|
||||||
|
config->{'host_groups'}->{'__NOTPRESENT_TYPES__'}
|
||||||
|
= config->{'ignore_notpresent_types'};
|
||||||
|
}
|
||||||
|
|
||||||
# copy devices_no and devices_only into others
|
# copy devices_no and devices_only into others
|
||||||
foreach my $name (qw/devices_no devices_only
|
foreach my $name (qw/devices_no devices_only
|
||||||
discover_no macsuck_no arpnip_no nbtstat_no
|
discover_no macsuck_no arpnip_no nbtstat_no
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use base 'App::Netdisco::DB::Result';
|
use base 'App::Netdisco::DB::Result';
|
||||||
|
use Sub::Install;
|
||||||
|
|
||||||
__PACKAGE__->table("device_ip");
|
__PACKAGE__->table("device_ip");
|
||||||
__PACKAGE__->add_columns(
|
__PACKAGE__->add_columns(
|
||||||
"ip",
|
"ip",
|
||||||
@@ -47,9 +49,41 @@ routed port or virtual interface).
|
|||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
__PACKAGE__->add_unique_constraint(['alias']);
|
|
||||||
|
|
||||||
__PACKAGE__->belongs_to( device_port => 'App::Netdisco::DB::Result::DevicePort',
|
__PACKAGE__->belongs_to( device_port => 'App::Netdisco::DB::Result::DevicePort',
|
||||||
{ 'foreign.port' => 'self.port', 'foreign.ip' => 'self.ip' } );
|
{ 'foreign.port' => 'self.port', 'foreign.ip' => 'self.ip' } );
|
||||||
|
|
||||||
|
=head2 device_port fields
|
||||||
|
|
||||||
|
All C<device_port> fields are mapped to accessors on this object.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
foreach my $field (qw/
|
||||||
|
descr
|
||||||
|
up
|
||||||
|
up_admin
|
||||||
|
type
|
||||||
|
duplex
|
||||||
|
duplex_admin
|
||||||
|
speed
|
||||||
|
speed_admin
|
||||||
|
name
|
||||||
|
mac
|
||||||
|
mtu
|
||||||
|
stp
|
||||||
|
remote_ip
|
||||||
|
remote_port
|
||||||
|
remote_type
|
||||||
|
remote_id
|
||||||
|
vlan
|
||||||
|
pvid
|
||||||
|
lastchange
|
||||||
|
/) {
|
||||||
|
|
||||||
|
Sub::Install::install_sub({
|
||||||
|
code => sub { return eval { (shift)->device_port->$field } },
|
||||||
|
as => $field,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ sub test_connection {
|
|||||||
my $addr = NetAddr::IP::Lite->new($ip) or return undef;
|
my $addr = NetAddr::IP::Lite->new($ip) or return undef;
|
||||||
# avoid renumbering to localhost loopbacks
|
# avoid renumbering to localhost loopbacks
|
||||||
return undef if $addr->addr eq '0.0.0.0'
|
return undef if $addr->addr eq '0.0.0.0'
|
||||||
or check_acl_no($addr->addr, 'group:__LOCAL_ADDRESSES__');
|
or check_acl_no($addr->addr, 'group:__LOOPBACK_ADDRESSES__');
|
||||||
my $device = schema('netdisco')->resultset('Device')
|
my $device = schema('netdisco')->resultset('Device')
|
||||||
->new_result({ ip => $addr->addr }) or return undef;
|
->new_result({ ip => $addr->addr }) or return undef;
|
||||||
my $readers = $class->instance->readers or return undef;
|
my $readers = $class->instance->readers or return undef;
|
||||||
|
|||||||
@@ -94,25 +94,26 @@ sub check_acl {
|
|||||||
|
|
||||||
my $real_ip = $thing;
|
my $real_ip = $thing;
|
||||||
if (blessed $thing) {
|
if (blessed $thing) {
|
||||||
$real_ip = ($thing->can('alias') ? $thing->alias : (
|
$real_ip = (
|
||||||
|
$thing->can('alias') ? $thing->alias : (
|
||||||
$thing->can('ip') ? $thing->ip : (
|
$thing->can('ip') ? $thing->ip : (
|
||||||
$thing->can('addr') ? $thing->addr : $thing )));
|
$thing->can('addr') ? $thing->addr : $thing )));
|
||||||
}
|
}
|
||||||
return 0 if !defined $real_ip
|
return 0 if blessed $real_ip; # class we do not understand
|
||||||
or blessed $real_ip; # class we do not understand
|
$real_ip ||= ''; # valid to be empty
|
||||||
|
|
||||||
$config = [$config] if ref '' eq ref $config;
|
$config = [$config] if ref q{} eq ref $config;
|
||||||
if (ref [] ne ref $config) {
|
if (ref [] ne ref $config) {
|
||||||
error "error: acl is not a single item or list (cannot compare to $real_ip)";
|
error "error: acl is not a single item or list (cannot compare to '$real_ip')";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
my $all = (scalar grep {$_ eq 'op:and'} @$config);
|
my $all = (scalar grep {$_ eq 'op:and'} @$config);
|
||||||
|
|
||||||
# common case of using plain IP in ACL, so string compare for speed
|
# common case of using plain IP in ACL, so string compare for speed
|
||||||
my $find = (scalar grep {not reftype $_ and $_ eq $real_ip} @$config);
|
my $find = (scalar grep {not reftype $_ and $_ eq $real_ip} @$config);
|
||||||
return 1 if $find and not $all;
|
return 1 if $real_ip and $find and not $all;
|
||||||
|
|
||||||
my $addr = NetAddr::IP::Lite->new($real_ip) or return 0;
|
my $addr = NetAddr::IP::Lite->new($real_ip);
|
||||||
my $name = undef; # only look up once, and only if qr// is used
|
my $name = undef; # only look up once, and only if qr// is used
|
||||||
my $ropt = { retry => 1, retrans => 1, udp_timeout => 1, tcp_timeout => 2 };
|
my $ropt = { retry => 1, retrans => 1, udp_timeout => 1, tcp_timeout => 2 };
|
||||||
my $qref = ref qr//;
|
my $qref = ref qr//;
|
||||||
@@ -122,6 +123,9 @@ sub check_acl {
|
|||||||
next INLIST if !defined $item or $item eq 'op:and';
|
next INLIST if !defined $item or $item eq 'op:and';
|
||||||
|
|
||||||
if ($qref eq ref $item) {
|
if ($qref eq ref $item) {
|
||||||
|
# if no IP addr, cannot match its dns
|
||||||
|
next INLIST unless $addr;
|
||||||
|
|
||||||
$name = ($name || hostname_from_ip($addr->addr, $ropt) || '!!none!!');
|
$name = ($name || hostname_from_ip($addr->addr, $ropt) || '!!none!!');
|
||||||
if ($name =~ $item) {
|
if ($name =~ $item) {
|
||||||
return 1 if not $all;
|
return 1 if not $all;
|
||||||
@@ -147,18 +151,25 @@ sub check_acl {
|
|||||||
next INLIST;
|
next INLIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($item =~ m/^([^:]+):([^:]+)$/) {
|
if ($item =~ m/^([^:]+):([^:]*)$/) {
|
||||||
my $prop = $1;
|
my $prop = $1;
|
||||||
my $match = $2;
|
my $match = $2 || '';
|
||||||
|
|
||||||
# if not an object, we can't do much with properties
|
# if not an object, we can't do much with properties
|
||||||
next INLIST unless blessed $thing;
|
next INLIST unless blessed $thing;
|
||||||
|
|
||||||
# lazy version of vendor: and model:
|
# prop:val
|
||||||
if ($neg xor ($thing->can($prop) and defined eval { $thing->$prop }
|
if ($neg xor ($thing->can($prop) and
|
||||||
|
defined eval { $thing->$prop } and
|
||||||
|
ref $thing->$prop eq q{}
|
||||||
and $thing->$prop =~ m/^$match$/) ) {
|
and $thing->$prop =~ m/^$match$/) ) {
|
||||||
return 1 if not $all;
|
return 1 if not $all;
|
||||||
}
|
}
|
||||||
|
# empty or missing property
|
||||||
|
elsif ($neg xor ($match eq q{} and
|
||||||
|
(!defined eval { $thing->$prop } or $thing->$prop eq q{})) ) {
|
||||||
|
return 1 if not $all;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return 0 if $all;
|
return 0 if $all;
|
||||||
}
|
}
|
||||||
@@ -169,6 +180,9 @@ sub check_acl {
|
|||||||
my $first = $1;
|
my $first = $1;
|
||||||
my $last = $2;
|
my $last = $2;
|
||||||
|
|
||||||
|
# if no IP addr, cannot match IP range
|
||||||
|
next INLIST unless $addr;
|
||||||
|
|
||||||
if ($item =~ m/:/) {
|
if ($item =~ m/:/) {
|
||||||
next INLIST if $addr->bits != 128 and not $all;
|
next INLIST if $addr->bits != 128 and not $all;
|
||||||
|
|
||||||
@@ -208,6 +222,9 @@ sub check_acl {
|
|||||||
# could be something in error, and IP/host is only option left
|
# could be something in error, and IP/host is only option left
|
||||||
next INLIST if ref $item;
|
next INLIST if ref $item;
|
||||||
|
|
||||||
|
# if no IP addr, cannot match IP prefix
|
||||||
|
next INLIST unless $addr;
|
||||||
|
|
||||||
my $ip = NetAddr::IP::Lite->new($item)
|
my $ip = NetAddr::IP::Lite->new($item)
|
||||||
or next INLIST;
|
or next INLIST;
|
||||||
next INLIST if $ip->bits != $addr->bits and not $all;
|
next INLIST if $ip->bits != $addr->bits and not $all;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use Dancer ':syntax';
|
|||||||
use Dancer::Plugin::DBIC;
|
use Dancer::Plugin::DBIC;
|
||||||
use Dancer::Plugin::Auth::Extensible;
|
use Dancer::Plugin::Auth::Extensible;
|
||||||
|
|
||||||
|
use App::Netdisco::Util::Permission 'check_acl_no';
|
||||||
use App::Netdisco::Util::Port 'port_reconfig_check';
|
use App::Netdisco::Util::Port 'port_reconfig_check';
|
||||||
use App::Netdisco::Util::Web (); # for sort_port
|
use App::Netdisco::Util::Web (); # for sort_port
|
||||||
use App::Netdisco::Web::Plugin;
|
use App::Netdisco::Web::Plugin;
|
||||||
@@ -214,6 +215,35 @@ get '/ajax/content/device/ports' => require_login sub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# filter out hidden ones
|
||||||
|
if (not param('p_include_hidden')) {
|
||||||
|
my $device_ips = {};
|
||||||
|
map { push @{ $device_ips->{$_->port} }, $_ }
|
||||||
|
$device->device_ips(undef, {prefetch => 'device_port'})->all;
|
||||||
|
|
||||||
|
map { push @{ $device_ips->{$_->port} }, $_ }
|
||||||
|
grep { ! exists $device_ips->{$_->port} }
|
||||||
|
@results;
|
||||||
|
|
||||||
|
foreach my $map (@{ setting('hide_deviceports')}) {
|
||||||
|
next unless ref {} eq ref $map;
|
||||||
|
|
||||||
|
foreach my $key (sort keys %$map) {
|
||||||
|
# lhs matches device, rhs matches port
|
||||||
|
next unless check_acl_no($device, $key);
|
||||||
|
|
||||||
|
PORT: foreach my $port (sort keys %$device_ips) {
|
||||||
|
foreach my $thing (@{ $device_ips->{$port} }) {
|
||||||
|
next unless check_acl_no($thing, $map->{$key});
|
||||||
|
|
||||||
|
@results = grep { $_->port ne $port } @results;
|
||||||
|
next PORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# sort ports
|
# sort ports
|
||||||
@results = sort { &App::Netdisco::Util::Web::sort_port($a->port, $b->port) } @results;
|
@results = sort { &App::Netdisco::Util::Web::sort_port($a->port, $b->port) } @results;
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ sub gather_subnets {
|
|||||||
my $addr = $ip->addr;
|
my $addr = $ip->addr;
|
||||||
|
|
||||||
next if $addr eq '0.0.0.0';
|
next if $addr eq '0.0.0.0';
|
||||||
next if check_acl_no($ip, 'group:__LOCAL_ADDRESSES__');
|
next if check_acl_no($ip, 'group:__LOOPBACK_ADDRESSES__');
|
||||||
next if setting('ignore_private_nets') and $ip->is_rfc1918;
|
next if setting('ignore_private_nets') and $ip->is_rfc1918;
|
||||||
|
|
||||||
my $netmask = $ip_netmask->{$addr} || $ip->bits();
|
my $netmask = $ip_netmask->{$addr} || $ip->bits();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use App::Netdisco::Worker::Plugin;
|
|||||||
use aliased 'App::Netdisco::Worker::Status';
|
use aliased 'App::Netdisco::Worker::Status';
|
||||||
|
|
||||||
use App::Netdisco::Transport::SNMP ();
|
use App::Netdisco::Transport::SNMP ();
|
||||||
use App::Netdisco::Util::Permission 'check_acl_only';
|
use App::Netdisco::Util::Permission 'check_acl_no';
|
||||||
use App::Netdisco::Util::DNS 'ipv4_from_hostname';
|
use App::Netdisco::Util::DNS 'ipv4_from_hostname';
|
||||||
use App::Netdisco::Util::Device 'is_discoverable';
|
use App::Netdisco::Util::Device 'is_discoverable';
|
||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
@@ -44,8 +44,8 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
|
|
||||||
foreach my $key (sort keys %$map) {
|
foreach my $key (sort keys %$map) {
|
||||||
# lhs matches device, rhs matches device_ip
|
# lhs matches device, rhs matches device_ip
|
||||||
if (check_acl_only($device, $key)
|
if (check_acl_no($device, $key)
|
||||||
and check_acl_only($alias, $map->{$key})) {
|
and check_acl_no($alias, $map->{$key})) {
|
||||||
|
|
||||||
if (not is_discoverable( $alias->alias )) {
|
if (not is_discoverable( $alias->alias )) {
|
||||||
debug sprintf ' [%s] device - cannot renumber to %s - not discoverable',
|
debug sprintf ' [%s] device - cannot renumber to %s - not discoverable',
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ sub store_neighbors {
|
|||||||
# useable remote IP...
|
# useable remote IP...
|
||||||
|
|
||||||
if ((! $r_netaddr) or ($remote_ip eq '0.0.0.0') or
|
if ((! $r_netaddr) or ($remote_ip eq '0.0.0.0') or
|
||||||
check_acl_no($remote_ip, 'group:__LOCAL_ADDRESSES__')) {
|
check_acl_no($remote_ip, 'group:__LOOPBACK_ADDRESSES__')) {
|
||||||
|
|
||||||
if ($remote_id) {
|
if ($remote_id) {
|
||||||
my $devices = schema('netdisco')->resultset('Device');
|
my $devices = schema('netdisco')->resultset('Device');
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use App::Netdisco::Worker::Plugin;
|
|||||||
use aliased 'App::Netdisco::Worker::Status';
|
use aliased 'App::Netdisco::Worker::Status';
|
||||||
|
|
||||||
use App::Netdisco::Transport::SNMP ();
|
use App::Netdisco::Transport::SNMP ();
|
||||||
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
|
use App::Netdisco::Util::Permission 'check_acl_no';
|
||||||
use App::Netdisco::Util::FastResolver 'hostnames_resolve_async';
|
use App::Netdisco::Util::FastResolver 'hostnames_resolve_async';
|
||||||
use App::Netdisco::Util::Device 'get_device';
|
use App::Netdisco::Util::Device 'get_device';
|
||||||
use App::Netdisco::Util::DNS 'hostname_from_ip';
|
use App::Netdisco::Util::DNS 'hostname_from_ip';
|
||||||
@@ -66,7 +66,7 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
my $protect = setting('snmp_field_protection')->{'device'} || {};
|
my $protect = setting('snmp_field_protection')->{'device'} || {};
|
||||||
my %dirty = $device->get_dirty_columns;
|
my %dirty = $device->get_dirty_columns;
|
||||||
foreach my $field (keys %dirty) {
|
foreach my $field (keys %dirty) {
|
||||||
next unless check_acl_only($ip, $protect->{$field});
|
next unless check_acl_no($ip, $protect->{$field});
|
||||||
if (!defined $dirty{$field} or $dirty{$field} eq '') {
|
if (!defined $dirty{$field} or $dirty{$field} eq '') {
|
||||||
return $job->cancel("discover cancelled: $ip failed to return valid $field");
|
return $job->cancel("discover cancelled: $ip failed to return valid $field");
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Status->info(" [$device] device - OK to continue discover");
|
return Status->info(" [$device] device - OK to continue discover (not a duplicate)");
|
||||||
});
|
});
|
||||||
|
|
||||||
register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
||||||
@@ -113,7 +113,7 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
my $snmp = App::Netdisco::Transport::SNMP->reader_for($device)
|
my $snmp = App::Netdisco::Transport::SNMP->reader_for($device)
|
||||||
or return Status->defer("discover failed: could not SNMP connect to $device");
|
or return Status->defer("discover failed: could not SNMP connect to $device");
|
||||||
|
|
||||||
my $pass = Status->info(" [$device] device - OK to continue discover");
|
my $pass = Status->info(" [$device] device - OK to continue discover (valid interfaces)");
|
||||||
my $interfaces = $snmp->interfaces;
|
my $interfaces = $snmp->interfaces;
|
||||||
|
|
||||||
# OK if no interfaces
|
# OK if no interfaces
|
||||||
@@ -172,6 +172,8 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
# NOTE must come after the IP Aliases gathering for ignore ACLs to work
|
||||||
register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
||||||
my ($job, $workerconf) = @_;
|
my ($job, $workerconf) = @_;
|
||||||
|
|
||||||
@@ -180,6 +182,13 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
my $snmp = App::Netdisco::Transport::SNMP->reader_for($device)
|
my $snmp = App::Netdisco::Transport::SNMP->reader_for($device)
|
||||||
or return Status->defer("discover failed: could not SNMP connect to $device");
|
or return Status->defer("discover failed: could not SNMP connect to $device");
|
||||||
|
|
||||||
|
# gather device_ips for use in ACLs later
|
||||||
|
my $device_ips = {};
|
||||||
|
foreach my $dip ($device->device_ips()->all) {
|
||||||
|
next unless defined $dip->port and $dip->port;
|
||||||
|
push @{ $device_ips->{ $dip->port } }, $dip;
|
||||||
|
}
|
||||||
|
|
||||||
my $interfaces = $snmp->interfaces;
|
my $interfaces = $snmp->interfaces;
|
||||||
my $i_type = $snmp->i_type;
|
my $i_type = $snmp->i_type;
|
||||||
my $i_ignore = $snmp->i_ignore;
|
my $i_ignore = $snmp->i_ignore;
|
||||||
@@ -222,41 +231,20 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# build device interfaces suitable for DBIC
|
# build device interfaces suitable for DBIC
|
||||||
my %interfaces;
|
my %deviceports;
|
||||||
foreach my $entry (keys %$interfaces) {
|
PORT: foreach my $entry (keys %$interfaces) {
|
||||||
my $port = $interfaces->{$entry};
|
my $port = $interfaces->{$entry};
|
||||||
|
|
||||||
if (not $port) {
|
if (not $port) {
|
||||||
debug sprintf ' [%s] interfaces - ignoring %s (no port mapping)',
|
debug sprintf ' [%s] interfaces - ignoring %s (no port mapping)',
|
||||||
$device->ip, $entry;
|
$device->ip, $entry;
|
||||||
next;
|
next PORT;
|
||||||
}
|
|
||||||
|
|
||||||
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}) {
|
if (exists $i_ignore->{$entry}) {
|
||||||
debug sprintf ' [%s] interfaces - ignoring %s (%s) (%s) (SNMP::Info::i_ignore)',
|
debug sprintf ' [%s] interfaces - ignoring %s (%s) (%s) (SNMP::Info::i_ignore)',
|
||||||
$device->ip, $entry, $port, ($i_type->{$entry} || '');
|
$device->ip, $entry, $port, ($i_type->{$entry} || '');
|
||||||
next;
|
next PORT;
|
||||||
}
|
|
||||||
|
|
||||||
# Skip interfaces by type filter
|
|
||||||
if (defined $i_type->{$entry} and (scalar grep {$i_type->{$entry} =~ m/^$_$/} @{setting('ignore_interface_types') || []})) {
|
|
||||||
debug sprintf ' [%s] interfaces - ignoring %s (%s) (%s) (config:ignore_interface_types)',
|
|
||||||
$device->ip, $entry, $port, $i_type->{$entry};
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Skip interfaces which are 'notPresent' and match the notpresent type filter
|
|
||||||
if (defined $i_up->{$entry} and defined $i_type->{$entry} and $i_up->{$entry} eq 'notPresent' and (scalar grep {$i_type->{$entry} =~ m/^$_$/} @{setting('ignore_notpresent_types') || []}) ) {
|
|
||||||
debug sprintf ' [%s] interfaces - ignoring %s (%s) (%s) (config:ignore_notpresent_types)',
|
|
||||||
$device->ip, $entry, $port, $i_up->{$entry};
|
|
||||||
next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
my $lc = $i_lastchange->{$entry} || 0;
|
my $lc = $i_lastchange->{$entry} || 0;
|
||||||
@@ -285,7 +273,9 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$interfaces{$port} = {
|
# create a DBIx::Class row for this port which can be used to test ACLs
|
||||||
|
# also include the Device IP alias if we have one for L3 interfaces
|
||||||
|
$deviceports{$port} = {
|
||||||
port => $port,
|
port => $port,
|
||||||
descr => $i_descr->{$entry},
|
descr => $i_descr->{$entry},
|
||||||
up => $i_up->{$entry},
|
up => $i_up->{$entry},
|
||||||
@@ -308,15 +298,53 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
# must do this after building %interfaces so that we can set is_master
|
if (scalar @{ setting('ignore_deviceports') }) {
|
||||||
|
foreach my $port (keys %$device_ips) {
|
||||||
|
if (!exists $deviceports{$port}) {
|
||||||
|
delete $device_ips->{$port};
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
foreach my $dip (@{ $device_ips->{$port} }) {
|
||||||
|
$dip->set_inflated_columns({ device_port => $deviceports{$port} });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach my $port (keys %deviceports) {
|
||||||
|
next if exists $device_ips->{$port};
|
||||||
|
push @{ $device_ips->{$port} },
|
||||||
|
schema('netdisco')->resultset('DevicePort')
|
||||||
|
->new_result( $deviceports{$port} );
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $map (@{ setting('ignore_deviceports')}) {
|
||||||
|
next unless ref {} eq ref $map;
|
||||||
|
|
||||||
|
foreach my $key (sort keys %$map) {
|
||||||
|
# lhs matches device, rhs matches port
|
||||||
|
next unless check_acl_no($device, $key);
|
||||||
|
|
||||||
|
PORT: foreach my $port (sort keys %$device_ips) {
|
||||||
|
foreach my $thing (@{ $device_ips->{$port} }) {
|
||||||
|
next unless check_acl_no($thing, $map->{$key});
|
||||||
|
|
||||||
|
debug sprintf ' [%s] interfaces - ignoring %s (config:ignore_deviceports)',
|
||||||
|
$device->ip, $port;
|
||||||
|
delete $deviceports{$port};
|
||||||
|
next PORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# must do this after building %deviceports so that we can set is_master
|
||||||
foreach my $sidx (keys %$agg_ports) {
|
foreach my $sidx (keys %$agg_ports) {
|
||||||
my $slave = $interfaces->{$sidx} or next;
|
my $slave = $interfaces->{$sidx} or next;
|
||||||
next unless defined $agg_ports->{$sidx}; # slave without a master?!
|
next unless defined $agg_ports->{$sidx}; # slave without a master?!
|
||||||
my $master = $interfaces->{ $agg_ports->{$sidx} } or next;
|
my $master = $interfaces->{ $agg_ports->{$sidx} } or next;
|
||||||
next unless exists $interfaces{$slave} and exists $interfaces{$master};
|
next unless exists $deviceports{$slave} and exists $deviceports{$master};
|
||||||
|
|
||||||
$interfaces{$slave}->{slave_of} = $master;
|
$deviceports{$slave}->{slave_of} = $master;
|
||||||
$interfaces{$master}->{is_master} = 'true';
|
$deviceports{$master}->{is_master} = 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
# also for VLAN subinterfaces
|
# also for VLAN subinterfaces
|
||||||
@@ -325,27 +353,29 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
# parent without subinterfaces?
|
# parent without subinterfaces?
|
||||||
next unless defined $i_subs->{$pidx}
|
next unless defined $i_subs->{$pidx}
|
||||||
and ref [] eq ref $i_subs->{$pidx}
|
and ref [] eq ref $i_subs->{$pidx}
|
||||||
and scalar @{ $i_subs->{$pidx} };
|
and scalar @{ $i_subs->{$pidx} }
|
||||||
|
and exists $deviceports{$parent};
|
||||||
|
|
||||||
$interfaces{$parent}->{has_subinterfaces} = 'true';
|
$deviceports{$parent}->{has_subinterfaces} = 'true';
|
||||||
foreach my $sidx (@{ $i_subs->{$pidx} }) {
|
foreach my $sidx (@{ $i_subs->{$pidx} }) {
|
||||||
my $sub = $interfaces->{$sidx} or next;
|
my $sub = $interfaces->{$sidx} or next;
|
||||||
$interfaces{$sub}->{slave_of} = $parent;
|
next unless exists $deviceports{$sub};
|
||||||
|
$deviceports{$sub}->{slave_of} = $parent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# support for Hooks
|
# support for Hooks
|
||||||
vars->{'hook_data'}->{'ports'} = [values %interfaces];
|
vars->{'hook_data'}->{'ports'} = [values %deviceports];
|
||||||
|
|
||||||
schema('netdisco')->resultset('DevicePort')->txn_do_locked(sub {
|
schema('netdisco')->resultset('DevicePort')->txn_do_locked(sub {
|
||||||
my $gone = $device->ports->delete({keep_nodes => 1});
|
my $gone = $device->ports->delete({keep_nodes => 1});
|
||||||
debug sprintf ' [%s] interfaces - removed %d interfaces',
|
debug sprintf ' [%s] interfaces - removed %d interfaces',
|
||||||
$device->ip, $gone;
|
$device->ip, $gone;
|
||||||
$device->update_or_insert(undef, {for => 'update'});
|
$device->update_or_insert(undef, {for => 'update'});
|
||||||
$device->ports->populate([values %interfaces]);
|
$device->ports->populate([values %deviceports]);
|
||||||
|
|
||||||
return Status->info(sprintf ' [%s] interfaces - added %d new interfaces',
|
return Status->info(sprintf ' [%s] interfaces - added %d new interfaces',
|
||||||
$device->ip, scalar values %interfaces);
|
$device->ip, scalar values %deviceports);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -397,7 +427,7 @@ sub _get_ipv4_aliases {
|
|||||||
my $addr = $ip->addr;
|
my $addr = $ip->addr;
|
||||||
|
|
||||||
next if $addr eq '0.0.0.0';
|
next if $addr eq '0.0.0.0';
|
||||||
next if check_acl_no($ip, 'group:__LOCAL_ADDRESSES__');
|
next if check_acl_no($ip, 'group:__LOOPBACK_ADDRESSES__');
|
||||||
next if setting('ignore_private_nets') and $ip->is_rfc1918;
|
next if setting('ignore_private_nets') and $ip->is_rfc1918;
|
||||||
|
|
||||||
my $iid = $ip_index->{$addr};
|
my $iid = $ip_index->{$addr};
|
||||||
@@ -450,7 +480,7 @@ sub _get_ipv6_aliases {
|
|||||||
my $addr = $ip->addr;
|
my $addr = $ip->addr;
|
||||||
|
|
||||||
next if $addr eq '::0';
|
next if $addr eq '::0';
|
||||||
next if check_acl_no($ip, 'group:__LOCAL_ADDRESSES__');
|
next if check_acl_no($ip, 'group:__LOOPBACK_ADDRESSES__');
|
||||||
|
|
||||||
my $port = $interfaces->{ $ipv6_index->{$iid} };
|
my $port = $interfaces->{ $ipv6_index->{$iid} };
|
||||||
my $subnet = $ipv6_pfxlen->{$iid}
|
my $subnet = $ipv6_pfxlen->{$iid}
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ sidebar_defaults:
|
|||||||
age_unit: { default: months }
|
age_unit: { default: months }
|
||||||
p_vlan_names: { label: 'Use VLAN Names', default: null, idx: 0 }
|
p_vlan_names: { label: 'Use VLAN Names', default: null, idx: 0 }
|
||||||
p_hide1002: { label: 'Hide VLAN 1002-1005', default: null, idx: 1 }
|
p_hide1002: { label: 'Hide VLAN 1002-1005', default: null, idx: 1 }
|
||||||
|
p_include_hidden: { label: 'Include Hidden Ports', default: null, idx: 2 }
|
||||||
device_netmap:
|
device_netmap:
|
||||||
showips: { default: null }
|
showips: { default: null }
|
||||||
showspeed: { default: null }
|
showspeed: { default: null }
|
||||||
@@ -209,6 +210,7 @@ check_userlog: false
|
|||||||
devport_vlan_limit: 150
|
devport_vlan_limit: 150
|
||||||
login_logo: ""
|
login_logo: ""
|
||||||
defanged_admin: 'admin'
|
defanged_admin: 'admin'
|
||||||
|
hide_deviceports: []
|
||||||
|
|
||||||
# -------------
|
# -------------
|
||||||
# NETDISCO CORE
|
# NETDISCO CORE
|
||||||
@@ -220,9 +222,51 @@ host_groups:
|
|||||||
__ANY__:
|
__ANY__:
|
||||||
- '0.0.0.0/0'
|
- '0.0.0.0/0'
|
||||||
- '::/0'
|
- '::/0'
|
||||||
__LOCAL_ADDRESSES__:
|
__LOOPBACK_ADDRESSES__:
|
||||||
- '::1'
|
- '::1'
|
||||||
- '127.0.0.0/8'
|
- '127.0.0.0/8'
|
||||||
|
__LOCAL_ADDRESSES__:
|
||||||
|
- '169.254.0.0/16'
|
||||||
|
- 'fe80::/10'
|
||||||
|
__LOOPBACK_WITH_NO_IP__:
|
||||||
|
- 'op:and'
|
||||||
|
- 'alias:'
|
||||||
|
- 'type:softwareLoopback'
|
||||||
|
__IGNORE_INTERFACES__:
|
||||||
|
- 'port:EOBC'
|
||||||
|
- 'port:unrouted VLAN(?: \d+)?'
|
||||||
|
- 'port:StackPort'
|
||||||
|
- 'port:Control Plane Interface'
|
||||||
|
- 'port:SPAN (S|R)P Interface'
|
||||||
|
- 'port:StackSub-.*'
|
||||||
|
- 'port:StackPort\d+'
|
||||||
|
- 'port:netflow'
|
||||||
|
- 'port:Vlan\d+-mpls layer'
|
||||||
|
- 'port:BRI\S+-Bearer Channel'
|
||||||
|
- 'port:BRI\S+-Physical'
|
||||||
|
- 'port:BRI\S+-Signalling'
|
||||||
|
- 'port:BRI\S+-Signaling'
|
||||||
|
- 'port:Embedded-Service-Engine\d+\/\d+'
|
||||||
|
- 'port:Virtual-Template\d+'
|
||||||
|
- 'port:Virtual-Access\d+'
|
||||||
|
- 'port:(E|T)\d \d\/\d\/\d'
|
||||||
|
- 'port:InLoopback0'
|
||||||
|
- 'port:NULL\d'
|
||||||
|
- 'port:Register-Tunnel\d'
|
||||||
|
- 'port:Blade-Aggregation\d'
|
||||||
|
- 'port:M-GigabitEthernet\d\/\d\/\d'
|
||||||
|
- 'port:Ethernet(?:-| )QOS Packet Scheduler'
|
||||||
|
- 'port:Ethernet(?:-| )WFP (?:802\.3|Native) MAC Layer Lightweight Filter'
|
||||||
|
- 'port:ii\d\/\d\/\d+'
|
||||||
|
__IGNORE_INTERFACE_TYPES__: []
|
||||||
|
__NOTPRESENT_TYPES__:
|
||||||
|
- 'type:ethernetCsmacd'
|
||||||
|
- 'type:tunnel'
|
||||||
|
- 'type:ieee8023adLag'
|
||||||
|
__IGNORE_NOTPRESENT_TYPES__:
|
||||||
|
- 'op:and'
|
||||||
|
- 'up:notPresent'
|
||||||
|
- 'group:__NOTPRESENT_TYPES__'
|
||||||
host_group_displaynames: {}
|
host_group_displaynames: {}
|
||||||
device_identity: []
|
device_identity: []
|
||||||
community: []
|
community: []
|
||||||
@@ -290,37 +334,18 @@ expire_userlog: 365
|
|||||||
expire_nodeip_freshness: null
|
expire_nodeip_freshness: null
|
||||||
store_wireless_clients: true
|
store_wireless_clients: true
|
||||||
store_modules: true
|
store_modules: true
|
||||||
ignore_interfaces:
|
ignore_deviceports:
|
||||||
- 'EOBC'
|
'group:__ANY__':
|
||||||
- 'unrouted VLAN(?: \d+)?'
|
- 'group:__IGNORE_INTERFACES__'
|
||||||
- 'StackPort'
|
- 'group:__IGNORE_INTERFACE_TYPES__'
|
||||||
- 'Control Plane Interface'
|
- 'group:__IGNORE_NOTPRESENT_TYPES__'
|
||||||
- 'SPAN (S|R)P Interface'
|
'vendor:juniper':
|
||||||
- 'StackSub-.*'
|
- 'subnet:128\.0\.0\.0/2'
|
||||||
- 'StackPort\d+'
|
- 'port:.+\.1638\d'
|
||||||
- 'netflow'
|
- 'port:.+\.3276\d'
|
||||||
- 'Vlan\d+-mpls layer'
|
ignore_interfaces: []
|
||||||
- 'BRI\S+-Bearer Channel'
|
|
||||||
- 'BRI\S+-Physical'
|
|
||||||
- 'BRI\S+-Signalling'
|
|
||||||
- 'BRI\S+-Signaling'
|
|
||||||
- 'Embedded-Service-Engine\d+\/\d+'
|
|
||||||
- 'Virtual-Template\d+'
|
|
||||||
- 'Virtual-Access\d+'
|
|
||||||
- '(E|T)\d \d\/\d\/\d'
|
|
||||||
- 'InLoopback0'
|
|
||||||
- 'NULL\d'
|
|
||||||
- 'Register-Tunnel\d'
|
|
||||||
- 'Blade-Aggregation\d'
|
|
||||||
- 'M-GigabitEthernet\d\/\d\/\d'
|
|
||||||
- 'Ethernet(?:-| )QOS Packet Scheduler'
|
|
||||||
- 'Ethernet(?:-| )WFP (?:802\.3|Native) MAC Layer Lightweight Filter'
|
|
||||||
- 'ii\d\/\d\/\d+'
|
|
||||||
ignore_interface_types: []
|
ignore_interface_types: []
|
||||||
ignore_notpresent_types:
|
ignore_notpresent_types: []
|
||||||
- 'ethernetCsmacd'
|
|
||||||
- 'tunnel'
|
|
||||||
- 'ieee8023adLag'
|
|
||||||
ignore_private_nets: false
|
ignore_private_nets: false
|
||||||
reverse_sysname: false
|
reverse_sysname: false
|
||||||
phone_capabilities:
|
phone_capabilities:
|
||||||
@@ -357,7 +382,7 @@ jobs_qdepth: 50
|
|||||||
dns:
|
dns:
|
||||||
max_outstanding: 50
|
max_outstanding: 50
|
||||||
hosts_file: '/etc/hosts'
|
hosts_file: '/etc/hosts'
|
||||||
no: ['group:__LOCAL_ADDRESSES__','169.254.0.0/16','fe80::/10']
|
no: ['group:__LOCAL_ADDRESSES__','group:__LOOPBACK_ADDRESSES__']
|
||||||
|
|
||||||
hooks: []
|
hooks: []
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ my @conf = (
|
|||||||
'op:and', # 20
|
'op:and', # 20
|
||||||
'group:groupreftest', # 21
|
'group:groupreftest', # 21
|
||||||
'!group:groupreftest', # 22
|
'!group:groupreftest', # 22
|
||||||
|
|
||||||
|
'192.0.2.1', #23
|
||||||
);
|
);
|
||||||
|
|
||||||
# name, ipv4, ipv6, v4 prefix, v6 prefix
|
# name, ipv4, ipv6, v4 prefix, v6 prefix
|
||||||
@@ -109,7 +111,29 @@ ok(check_acl('localhost',$conf[0]), 'scalar promoted');
|
|||||||
ok(check_acl('localhost',$conf[1]), 'not scalar promoted');
|
ok(check_acl('localhost',$conf[1]), 'not scalar promoted');
|
||||||
is(check_acl('www.microsoft.com',$conf[0]), 0, 'failed scalar promoted');
|
is(check_acl('www.microsoft.com',$conf[0]), 0, 'failed scalar promoted');
|
||||||
|
|
||||||
# device property
|
use App::Netdisco::DB;
|
||||||
# negated device property
|
my $dip = App::Netdisco::DB->resultset('DeviceIp')->new_result({
|
||||||
|
ip => '127.0.0.1',
|
||||||
|
port => 'TenGigabitEthernet1/10',
|
||||||
|
alias => '192.0.2.1',
|
||||||
|
device_port =>
|
||||||
|
App::Netdisco::DB->resultset('DevicePort')->new_result({
|
||||||
|
ip => '127.0.0.1',
|
||||||
|
port => 'TenGigabitEthernet1/10',
|
||||||
|
type => 'l3ipvlan',
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
# device properties
|
||||||
|
ok(check_acl($dip, [$conf[23]]), 'instance anon property deviceport:alias');
|
||||||
|
ok(check_acl($dip, ['ip:'.$conf[2]]), 'instance named property deviceport:ip');
|
||||||
|
ok(check_acl($dip, ['!ip:'. $conf[23]]), 'negated instance named property deviceport:ip');
|
||||||
|
is(check_acl($dip, ['port:'.$conf[2]]), 0, 'failed instance named property deviceport:ip');
|
||||||
|
ok(check_acl($dip, ['port:.*GigabitEthernet.*']), 'instance named property regexp deviceport:port');
|
||||||
|
|
||||||
|
ok(check_acl($dip, ['type:l3ipvlan']), 'related item field match');
|
||||||
|
ok(check_acl($dip, ['remote_ip:']), 'related item field empty');
|
||||||
|
ok(check_acl($dip, ['!type:']), 'related item field not empty');
|
||||||
|
is(check_acl($dip, ['foobar:xyz']), 0, 'unknown property');
|
||||||
|
|
||||||
done_testing;
|
done_testing;
|
||||||
|
|||||||
Reference in New Issue
Block a user