Refactored ACL support with multi-object compare
Squashed commit of the following:
commit 4081e22202693bd7c4ea00e95daad8e628c6fd5a
Author: Oliver Gorwits <oliver@cpan.org>
Date: Mon May 29 21:02:07 2023 +0100
large rename of check_acl* to acl_matches*
commit 3cfa284ddd24d68765c255578cc5c184afbdcd83
Author: Oliver Gorwits <oliver@cpan.org>
Date: Fri May 19 20:39:03 2023 +0100
update permission doc
commit 8c7bb93cc5e9fafb770f98f446e45cbd94b14894
Author: Oliver Gorwits <oliver@cpan.org>
Date: Wed May 17 21:50:07 2023 +0100
migrate most check_acl_only to acl_matches_only
commit c47f699f2a22f08f2f3e093ed0f24c891e6f9a82
Author: Oliver Gorwits <oliver@cpan.org>
Date: Wed May 17 21:39:19 2023 +0100
rename check_acl* to be acl_matches*
commit a884a22c3ab1f3262118c3a47ed8e25b0b0a7336
Author: Oliver Gorwits <oliver@cpan.org>
Date: Sun May 14 16:50:42 2023 +0100
update macsuck_no_deviceports to use acl_matches
commit 8c256af728721329b64d071fa529dfc844073ac6
Author: Oliver Gorwits <oliver@cpan.org>
Date: Sun May 7 22:54:33 2023 +0100
update hide_deviceports to use acl_matches multi @things
commit cd5d9978aba1da459be4fed4500f395df13f7784
Author: Oliver Gorwits <oliver@cpan.org>
Date: Sun May 7 22:53:38 2023 +0100
check_acl fix to allow all @things to offer a property before fallback to missing as empty string
commit 1a3ab9a7646e9f994f03126d45fc36e9e5a13ed5
Author: Oliver Gorwits <oliver@cpan.org>
Date: Tue May 2 15:31:17 2023 +0100
add ignore_deviceports to portproperties discover; improve comments
commit 51385ce89458dc939587dae902fda431719c22c9
Merge: b97c07d2 3f8ffe78
Author: Oliver Gorwits <oliver@cpan.org>
Date: Tue May 2 15:21:48 2023 +0100
Merge branch 'master' into og-acl_multidict
commit b97c07d237d750c1d9eb3095d8ff3908512eac2a
Author: Oliver Gorwits <oliver@cpan.org>
Date: Sat Mar 25 14:37:53 2023 +0000
add support for arrayref of items, and unblessed hash, to check_acl
This commit is contained in:
1
Build.PL
1
Build.PL
@@ -90,7 +90,6 @@ Module::Build->new(
|
|||||||
'SNMP::Info' => '3.92',
|
'SNMP::Info' => '3.92',
|
||||||
'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',
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ use App::Netdisco;
|
|||||||
use Dancer ':script';
|
use Dancer ':script';
|
||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
|
|
||||||
use App::Netdisco::Util::Permission ':all';
|
use App::Netdisco::Util::Permission 'acl_matches';
|
||||||
|
|
||||||
# silent exit unless explicitly requested
|
# silent exit unless explicitly requested
|
||||||
exit(0) unless setting('use_legacy_rancidexport');
|
exit(0) unless setting('use_legacy_rancidexport');
|
||||||
@@ -76,7 +76,7 @@ foreach my $d (@devices) {
|
|||||||
my $old = $d->get_column( 'old' );
|
my $old = $d->get_column( 'old' );
|
||||||
my $devgroup = 'other';
|
my $devgroup = 'other';
|
||||||
foreach my $g (keys %$groups) {
|
foreach my $g (keys %$groups) {
|
||||||
if (check_acl_only( $d, $groups->{$g} )) {
|
if (acl_matches( $d, $groups->{$g} )) {
|
||||||
$devgroup = $g;
|
$devgroup = $g;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ 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(
|
||||||
@@ -52,38 +51,4 @@ routed port or virtual interface).
|
|||||||
__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;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use Dancer::Plugin::DBIC 'schema';
|
|||||||
|
|
||||||
use App::Netdisco::Util::SNMP 'get_communities';
|
use App::Netdisco::Util::SNMP 'get_communities';
|
||||||
use App::Netdisco::Util::Device 'get_device';
|
use App::Netdisco::Util::Device 'get_device';
|
||||||
use App::Netdisco::Util::Permission ':all';
|
use App::Netdisco::Util::Permission 'acl_matches';
|
||||||
|
|
||||||
use SNMP::Info;
|
use SNMP::Info;
|
||||||
use Try::Tiny;
|
use Try::Tiny;
|
||||||
@@ -97,7 +97,7 @@ sub test_connection {
|
|||||||
|
|
||||||
# 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:__LOOPBACK_ADDRESSES__');
|
or acl_matches($addr->addr, 'group:__LOOPBACK_ADDRESSES__');
|
||||||
|
|
||||||
my $device = schema(vars->{'tenant'})->resultset('Device')
|
my $device = schema(vars->{'tenant'})->resultset('Device')
|
||||||
->new_result({ ip => $addr->addr }) or return undef;
|
->new_result({ ip => $addr->addr }) or return undef;
|
||||||
@@ -154,11 +154,11 @@ sub _snmp_connect_generic {
|
|||||||
|
|
||||||
# an override for RemotePort
|
# an override for RemotePort
|
||||||
($snmp_args{RemotePort}) =
|
($snmp_args{RemotePort}) =
|
||||||
(pairkeys pairfirst { check_acl_no($device, $b) }
|
(pairkeys pairfirst { acl_matches($device, $b) }
|
||||||
%{setting('snmp_remoteport') || {}}) || 161;
|
%{setting('snmp_remoteport') || {}}) || 161;
|
||||||
|
|
||||||
# an override for bulkwalk
|
# an override for bulkwalk
|
||||||
$snmp_args{BulkWalk} = 0 if check_acl_no($device, 'bulkwalk_no');
|
$snmp_args{BulkWalk} = 0 if acl_matches($device, 'bulkwalk_no');
|
||||||
|
|
||||||
# further protect against buggy Net-SNMP, and disable bulkwalk
|
# further protect against buggy Net-SNMP, and disable bulkwalk
|
||||||
if ($snmp_args{BulkWalk}
|
if ($snmp_args{BulkWalk}
|
||||||
@@ -197,9 +197,9 @@ sub _snmp_connect_generic {
|
|||||||
|
|
||||||
# which SNMP versions to try and in what order
|
# which SNMP versions to try and in what order
|
||||||
my @versions =
|
my @versions =
|
||||||
( check_acl_no($device->ip, 'snmpforce_v3') ? (3)
|
( acl_matches($device->ip, 'snmpforce_v3') ? (3)
|
||||||
: check_acl_no($device->ip, 'snmpforce_v2') ? (2)
|
: acl_matches($device->ip, 'snmpforce_v2') ? (2)
|
||||||
: check_acl_no($device->ip, 'snmpforce_v1') ? (1)
|
: acl_matches($device->ip, 'snmpforce_v1') ? (1)
|
||||||
: (reverse (1 .. (setting('snmpver') || 3))) );
|
: (reverse (1 .. (setting('snmpver') || 3))) );
|
||||||
|
|
||||||
# use existing or new device class
|
# use existing or new device class
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package App::Netdisco::Util::Device;
|
|||||||
|
|
||||||
use Dancer qw/:syntax :script/;
|
use Dancer qw/:syntax :script/;
|
||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
|
use App::Netdisco::Util::Permission qw/acl_matches acl_matches_only/;
|
||||||
|
|
||||||
use File::Spec::Functions qw(catdir catfile);
|
use File::Spec::Functions qw(catdir catfile);
|
||||||
use File::Path 'make_path';
|
use File::Path 'make_path';
|
||||||
@@ -184,10 +184,10 @@ sub is_discoverable {
|
|||||||
if (match_to_setting($remote_type, 'discover_no_type'));
|
if (match_to_setting($remote_type, 'discover_no_type'));
|
||||||
|
|
||||||
return _bail_msg("is_discoverable: $device matched discover_no")
|
return _bail_msg("is_discoverable: $device matched discover_no")
|
||||||
if check_acl_no($device, 'discover_no');
|
if acl_matches($device, 'discover_no');
|
||||||
|
|
||||||
return _bail_msg("is_discoverable: $device failed to match discover_only")
|
return _bail_msg("is_discoverable: $device failed to match discover_only")
|
||||||
unless check_acl_only($device, 'discover_only');
|
unless acl_matches_only($device, 'discover_only');
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -236,14 +236,14 @@ sub is_arpnipable {
|
|||||||
|
|
||||||
return _bail_msg("is_arpnipable: $device has no layer 3 capability")
|
return _bail_msg("is_arpnipable: $device has no layer 3 capability")
|
||||||
if ($device->in_storage() and not ($device->has_layer(3)
|
if ($device->in_storage() and not ($device->has_layer(3)
|
||||||
or check_acl_no($device, 'force_arpnip')
|
or acl_matches($device, 'force_arpnip')
|
||||||
or check_acl_no($device, 'ignore_layers')));
|
or acl_matches($device, 'ignore_layers')));
|
||||||
|
|
||||||
return _bail_msg("is_arpnipable: $device matched arpnip_no")
|
return _bail_msg("is_arpnipable: $device matched arpnip_no")
|
||||||
if check_acl_no($device, 'arpnip_no');
|
if acl_matches($device, 'arpnip_no');
|
||||||
|
|
||||||
return _bail_msg("is_arpnipable: $device failed to match arpnip_only")
|
return _bail_msg("is_arpnipable: $device failed to match arpnip_only")
|
||||||
unless check_acl_only($device, 'arpnip_only');
|
unless acl_matches_only($device, 'arpnip_only');
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -292,17 +292,17 @@ sub is_macsuckable {
|
|||||||
|
|
||||||
return _bail_msg("is_macsuckable: $device has no layer 2 capability")
|
return _bail_msg("is_macsuckable: $device has no layer 2 capability")
|
||||||
if ($device->in_storage() and not ($device->has_layer(2)
|
if ($device->in_storage() and not ($device->has_layer(2)
|
||||||
or check_acl_no($device, 'force_macsuck')
|
or acl_matches($device, 'force_macsuck')
|
||||||
or check_acl_no($device, 'ignore_layers')));
|
or acl_matches($device, 'ignore_layers')));
|
||||||
|
|
||||||
return _bail_msg("is_macsuckable: $device matched macsuck_no")
|
return _bail_msg("is_macsuckable: $device matched macsuck_no")
|
||||||
if check_acl_no($device, 'macsuck_no');
|
if acl_matches($device, 'macsuck_no');
|
||||||
|
|
||||||
return _bail_msg("is_macsuckable: $device matched macsuck_unsupported")
|
return _bail_msg("is_macsuckable: $device matched macsuck_unsupported")
|
||||||
if check_acl_no($device, 'macsuck_unsupported');
|
if acl_matches($device, 'macsuck_unsupported');
|
||||||
|
|
||||||
return _bail_msg("is_macsuckable: $device failed to match macsuck_only")
|
return _bail_msg("is_macsuckable: $device failed to match macsuck_only")
|
||||||
unless check_acl_only($device, 'macsuck_only');
|
unless acl_matches_only($device, 'macsuck_only');
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use warnings;
|
|||||||
use Dancer ':script';
|
use Dancer ':script';
|
||||||
|
|
||||||
use AnyEvent::DNS;
|
use AnyEvent::DNS;
|
||||||
use App::Netdisco::Util::Permission 'check_acl_no';
|
use App::Netdisco::Util::Permission 'acl_matches';
|
||||||
|
|
||||||
use base 'Exporter';
|
use base 'Exporter';
|
||||||
our @EXPORT = ();
|
our @EXPORT = ();
|
||||||
@@ -58,7 +58,7 @@ sub hostnames_resolve_async {
|
|||||||
|
|
||||||
IP: foreach my $hash_ref (@$ips) {
|
IP: foreach my $hash_ref (@$ips) {
|
||||||
my $ip = $hash_ref->{'ip'} || $hash_ref->{'alias'} || $hash_ref->{'device'};
|
my $ip = $hash_ref->{'ip'} || $hash_ref->{'alias'} || $hash_ref->{'device'};
|
||||||
next IP if check_acl_no($ip, $skip);
|
next IP if acl_matches($ip, $skip);
|
||||||
|
|
||||||
# check /etc/hosts file and short-circuit if found
|
# check /etc/hosts file and short-circuit if found
|
||||||
foreach my $name (reverse sort keys %$ETCHOSTS) {
|
foreach my $name (reverse sort keys %$ETCHOSTS) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use Dancer qw/:syntax :script/;
|
|||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
|
|
||||||
use NetAddr::MAC;
|
use NetAddr::MAC;
|
||||||
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
|
use App::Netdisco::Util::Permission qw/acl_matches acl_matches_only/;
|
||||||
|
|
||||||
use base 'Exporter';
|
use base 'Exporter';
|
||||||
our @EXPORT = ();
|
our @EXPORT = ();
|
||||||
@@ -138,9 +138,9 @@ Returns false if the host is not permitted to nbtstat the target node.
|
|||||||
sub is_nbtstatable {
|
sub is_nbtstatable {
|
||||||
my $ip = shift;
|
my $ip = shift;
|
||||||
|
|
||||||
return if check_acl_no($ip, 'nbtstat_no');
|
return if acl_matches($ip, 'nbtstat_no');
|
||||||
|
|
||||||
return unless check_acl_only($ip, 'nbtstat_only');
|
return unless acl_matches_only($ip, 'nbtstat_only');
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use App::Netdisco::Util::DNS 'hostname_from_ip';
|
|||||||
|
|
||||||
use base 'Exporter';
|
use base 'Exporter';
|
||||||
our @EXPORT = ();
|
our @EXPORT = ();
|
||||||
our @EXPORT_OK = qw/check_acl check_acl_no check_acl_only/;
|
our @EXPORT_OK = qw/acl_matches acl_matches_only/;
|
||||||
our %EXPORT_TAGS = (all => \@EXPORT_OK);
|
our %EXPORT_TAGS = (all => \@EXPORT_OK);
|
||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
@@ -26,11 +26,17 @@ subroutines.
|
|||||||
|
|
||||||
=head1 EXPORT_OK
|
=head1 EXPORT_OK
|
||||||
|
|
||||||
=head2 check_acl_no( $ip | $instance, $setting_name | $acl_entry | \@acl )
|
=head2 acl_matches( $ip | $object | \%hash | \@item_list, $setting_name | $acl_entry | \@acl )
|
||||||
|
|
||||||
Given an IP address or object instance, returns true if the configuration
|
Given an IP address, object instance, or hash, returns true if the
|
||||||
setting C<$setting_name> matches, else returns false. If the content of the
|
configuration setting C<$setting_name> matches, else returns false.
|
||||||
setting is undefined or empty, then C<check_acl_no> also returns false.
|
|
||||||
|
Usage of this function is strongly advised to be of the form:
|
||||||
|
|
||||||
|
QUIT/SKIP IF acl_matches
|
||||||
|
|
||||||
|
The function fails safe, so if the content of the setting or ACL is undefined
|
||||||
|
or an empty string, then C<acl_matches> also returns true.
|
||||||
|
|
||||||
If C<$setting_name> is a valid setting, then it will be resolved to the access
|
If C<$setting_name> is a valid setting, then it will be resolved to the access
|
||||||
control list, else we assume you passed an ACL entry or ACL.
|
control list, else we assume you passed an ACL entry or ACL.
|
||||||
@@ -40,19 +46,37 @@ for details of what C<$acl> may contain.
|
|||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub check_acl_no {
|
sub acl_matches {
|
||||||
my ($thing, $setting_name) = @_;
|
my ($thing, $setting_name) = @_;
|
||||||
return 1 unless $thing and $setting_name;
|
# fail-safe so undef config should return true
|
||||||
|
return true unless $thing and $setting_name;
|
||||||
my $config = (exists config->{"$setting_name"} ? setting($setting_name)
|
my $config = (exists config->{"$setting_name"} ? setting($setting_name)
|
||||||
: $setting_name);
|
: $setting_name);
|
||||||
return check_acl($thing, $config);
|
return check_acl($thing, $config);
|
||||||
}
|
}
|
||||||
|
|
||||||
=head2 check_acl_only( $ip | $instance, $setting_name | $acl_entry | \@acl )
|
=head2 check_acl_no( $ip | $object | \%hash | \@item_list, $setting_name | $acl_entry | \@acl )
|
||||||
|
|
||||||
Given an IP address or object instance, returns true if the configuration
|
This is an alias for L<acl_matches>.
|
||||||
setting C<$setting_name> matches, else returns false. If the content of the
|
|
||||||
setting is undefined or empty, then C<check_acl_only> also returns true.
|
=cut
|
||||||
|
|
||||||
|
sub check_acl_no { goto &acl_matches }
|
||||||
|
|
||||||
|
=head2 acl_matches_only( $ip | $object | \%hash | \@item_list, $setting_name | $acl_entry | \@acl )
|
||||||
|
|
||||||
|
Given an IP address, object instance, or hash, returns true if the
|
||||||
|
configuration setting C<$setting_name> matches, else returns false.
|
||||||
|
|
||||||
|
Usage of this function is strongly advised to be of the form:
|
||||||
|
|
||||||
|
QUIT/SKIP UNLESS acl_matches_only
|
||||||
|
|
||||||
|
The function fails safe, so if the content of the setting or ACL is undefined
|
||||||
|
or an empty string, then C<acl_matches_only> also returns false.
|
||||||
|
|
||||||
|
Further, if the setting or ACL resolves to a list but the list has no items,
|
||||||
|
then C<acl_matches_only> returns true (as if there is a successful match).
|
||||||
|
|
||||||
If C<$setting_name> is a valid setting, then it will be resolved to the access
|
If C<$setting_name> is a valid setting, then it will be resolved to the access
|
||||||
control list, else we assume you passed an ACL entry or ACL.
|
control list, else we assume you passed an ACL entry or ACL.
|
||||||
@@ -62,25 +86,40 @@ for details of what C<$acl> may contain.
|
|||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub check_acl_only {
|
sub acl_matches_only {
|
||||||
my ($thing, $setting_name) = @_;
|
my ($thing, $setting_name) = @_;
|
||||||
return 0 unless $thing and $setting_name;
|
# fail-safe so undef config should return false
|
||||||
# logic to make an empty config be equivalent to 'any' (i.e. a match)
|
return false unless $thing and $setting_name;
|
||||||
my $config = (exists config->{"$setting_name"} ? setting($setting_name)
|
my $config = (exists config->{"$setting_name"} ? setting($setting_name)
|
||||||
: $setting_name);
|
: $setting_name);
|
||||||
return 1 if not $config # undef or empty string
|
# logic to make an empty config be equivalent to 'any' (i.e. a match)
|
||||||
|
# empty list check means truth check passes for match or empty list
|
||||||
|
return true if not $config # undef or empty string
|
||||||
or ((ref [] eq ref $config) and not scalar @$config);
|
or ((ref [] eq ref $config) and not scalar @$config);
|
||||||
return check_acl($thing, $config);
|
return check_acl($thing, $config);
|
||||||
}
|
}
|
||||||
|
|
||||||
=head2 check_acl( $ip | $instance, $acl_entry | \@acl )
|
=head2 check_acl_only( $ip | $object | \%hash | \@item_list, $setting_name | $acl_entry | \@acl )
|
||||||
|
|
||||||
Given an IP address or object instance, compares it to the items in C<< \@acl
|
This is an alias for L<acl_matches_only>.
|
||||||
>> then returns true or false. You can control whether any item must match or
|
|
||||||
all must match, and items can be negated to invert the match logic.
|
|
||||||
|
|
||||||
Accepts instances of classes representing Netdisco Devices, Netdisco Device
|
=cut
|
||||||
IPs, and L<NetAddr::IP> family objects.
|
|
||||||
|
sub check_acl_only { goto &acl_matches_only }
|
||||||
|
|
||||||
|
=head2 check_acl( $ip | $object | \%hash | \@item_list, $acl_entry | \@acl )
|
||||||
|
|
||||||
|
Given an IP address, object instance, or hash, compares it to the items in
|
||||||
|
C<< \@acl >> then returns true or false. You can control whether any item must
|
||||||
|
match or all must match, and items can be negated to invert the match logic.
|
||||||
|
|
||||||
|
Also accepts an array reference of multiple IP addresses, object instances,
|
||||||
|
and hashes, and will test against each in turn, for each ACL rule.
|
||||||
|
|
||||||
|
The slots C<alias>, C<ip>, C<switch>, and C<addr> are looked for in the
|
||||||
|
instance or hash and used to compare a bare IP address (so it works with most
|
||||||
|
Netdisco database classes, and the L<NetAddr::IP> class). Any instance or hash
|
||||||
|
slot can be used as an ACL named property.
|
||||||
|
|
||||||
There are several options for what C<< \@acl >> may contain. See
|
There are several options for what C<< \@acl >> may contain. See
|
||||||
L<the Netdisco wiki|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
L<the Netdisco wiki|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
||||||
@@ -89,156 +128,199 @@ for the details.
|
|||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub check_acl {
|
sub check_acl {
|
||||||
my ($thing, $config) = @_;
|
my ($things, $config) = @_;
|
||||||
return 0 unless defined $thing and defined $config;
|
return false unless defined $things and defined $config;
|
||||||
|
return false if ref [] eq ref $things and not scalar @$things;
|
||||||
|
$things = [$things] if ref [] ne ref $things;
|
||||||
|
|
||||||
my $real_ip = $thing;
|
my $real_ip = ''; # valid to be empty
|
||||||
if (blessed $thing) {
|
ITEM: foreach my $item (@$things) {
|
||||||
$real_ip = (
|
foreach my $slot (qw/alias ip switch addr/) {
|
||||||
$thing->can('alias') ? $thing->alias : (
|
if (blessed $item) {
|
||||||
$thing->can('ip') ? $thing->ip : (
|
$real_ip = $item->$slot if $item->can($slot)
|
||||||
$thing->can('addr') ? $thing->addr : $thing )));
|
and eval { $item->$slot };
|
||||||
|
}
|
||||||
|
elsif (ref {} eq ref $item) {
|
||||||
|
$real_ip = $item->{$slot} if exists $item->{$slot}
|
||||||
|
and $item->{$slot};
|
||||||
|
}
|
||||||
|
last ITEM if $real_ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ITEM: foreach my $item (@$things) {
|
||||||
|
last ITEM if $real_ip;
|
||||||
|
$real_ip = $item if (ref $item eq q{}) and $item;
|
||||||
}
|
}
|
||||||
return 0 if blessed $real_ip; # class we do not understand
|
|
||||||
$real_ip ||= ''; # valid to be empty
|
|
||||||
|
|
||||||
$config = [$config] if ref q{} eq ref $config;
|
$config = [$config] if ref $config eq q{};
|
||||||
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 false;
|
||||||
}
|
}
|
||||||
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 $real_ip and $find and not $all;
|
return true if $real_ip and $find and not $all;
|
||||||
|
|
||||||
my $addr = NetAddr::IP::Lite->new($real_ip);
|
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//;
|
||||||
|
|
||||||
INLIST: foreach (@$config) {
|
RULE: foreach (@$config) {
|
||||||
my $item = $_; # must copy so that we can modify safely
|
my $rule = $_; # must copy so that we can modify safely
|
||||||
next INLIST if !defined $item or $item eq 'op:and';
|
next RULE if !defined $rule or $rule eq 'op:and';
|
||||||
|
|
||||||
if ($qref eq ref $item) {
|
if ($qref eq ref $rule) {
|
||||||
# if no IP addr, cannot match its dns
|
# if no IP addr, cannot match its dns
|
||||||
next INLIST unless $addr;
|
next RULE 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 =~ $rule) {
|
||||||
return 1 if not $all;
|
return true if not $all;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return 0 if $all;
|
return false if $all;
|
||||||
}
|
}
|
||||||
next INLIST;
|
next RULE;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $neg = ($item =~ s/^!//);
|
my $neg = ($rule =~ s/^!//);
|
||||||
|
|
||||||
if ($item =~ m/^group:(.+)$/) {
|
if ($rule =~ m/^group:(.+)$/) {
|
||||||
my $group = $1;
|
my $group = $1;
|
||||||
setting('host_groups')->{$group} ||= [];
|
setting('host_groups')->{$group} ||= [];
|
||||||
|
|
||||||
if ($neg xor check_acl($thing, setting('host_groups')->{$group})) {
|
if ($neg xor check_acl($things, setting('host_groups')->{$group})) {
|
||||||
return 1 if not $all;
|
return true if not $all;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return 0 if $all;
|
return false if $all;
|
||||||
}
|
}
|
||||||
next INLIST;
|
next RULE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($item =~ m/^([^:]+):([^:]*)$/) {
|
|
||||||
my $prop = $1;
|
|
||||||
my $match = $2 || '';
|
|
||||||
|
|
||||||
# if not an object, we can't do much with properties
|
|
||||||
next INLIST unless blessed $thing;
|
|
||||||
|
|
||||||
# prop:val
|
# prop:val
|
||||||
if ($neg xor ($thing->can($prop) and
|
if ($rule =~ m/^([^:]+):([^:]*)$/) {
|
||||||
defined eval { $thing->$prop } and
|
my $prop = $1;
|
||||||
ref $thing->$prop eq q{}
|
my $match = $2 || '';
|
||||||
and $thing->$prop =~ m/^$match$/) ) {
|
my $found = false;
|
||||||
return 1 if not $all;
|
|
||||||
|
# property exists, undef is allowed to match empty string
|
||||||
|
ITEM: foreach my $item (@$things) {
|
||||||
|
if (blessed $item) {
|
||||||
|
if ($neg xor ($item->can($prop) and
|
||||||
|
((!defined eval { $item->$prop } and $match eq q{})
|
||||||
|
or
|
||||||
|
(defined eval { $item->$prop } and ref $item->$prop eq q{} and $item->$prop =~ m/^$match$/)) )) {
|
||||||
|
return true if not $all;
|
||||||
|
$found = true;
|
||||||
|
last ITEM;
|
||||||
}
|
}
|
||||||
# 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 {
|
elsif (ref {} eq ref $item) {
|
||||||
return 0 if $all;
|
if ($neg xor (exists $item->{$prop} and
|
||||||
|
((!defined $item->{$prop} and $match eq q{})
|
||||||
|
or
|
||||||
|
(defined $item->{$prop} and ref $item->{$prop} eq q{} and $item->{$prop} =~ m/^$match$/)) )) {
|
||||||
|
return true if not $all;
|
||||||
|
$found = true;
|
||||||
|
last ITEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
next INLIST;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($item =~ m/[:.]([a-f0-9]+)-([a-f0-9]+)$/i) {
|
# missing property matches empty string
|
||||||
|
# (which is done in a second pass to allow all @$things to be
|
||||||
|
# inspected for existing properties)
|
||||||
|
ITEM: foreach my $item (@$things) {
|
||||||
|
last ITEM if $found;
|
||||||
|
|
||||||
|
if (blessed $item) {
|
||||||
|
if ($neg xor ($match eq q{} and ! $item->can($prop))) {
|
||||||
|
return true if not $all;
|
||||||
|
$found = true;
|
||||||
|
last ITEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif (ref {} eq ref $item) {
|
||||||
|
# empty or missing property
|
||||||
|
if ($neg xor ($match eq q{} and ! exists $item->{$prop})) {
|
||||||
|
return true if not $all;
|
||||||
|
$found = true;
|
||||||
|
last ITEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false if $all;
|
||||||
|
next RULE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($rule =~ m/[:.]([a-f0-9]+)-([a-f0-9]+)$/i) {
|
||||||
my $first = $1;
|
my $first = $1;
|
||||||
my $last = $2;
|
my $last = $2;
|
||||||
|
|
||||||
# if no IP addr, cannot match IP range
|
# if no IP addr, cannot match IP range
|
||||||
next INLIST unless $addr;
|
next RULE unless $addr;
|
||||||
|
|
||||||
if ($item =~ m/:/) {
|
if ($rule =~ m/:/) {
|
||||||
next INLIST if $addr->bits != 128 and not $all;
|
next RULE if $addr->bits != 128 and not $all;
|
||||||
|
|
||||||
$first = hex $first;
|
$first = hex $first;
|
||||||
$last = hex $last;
|
$last = hex $last;
|
||||||
|
|
||||||
(my $header = $item) =~ s/:[^:]+$/:/;
|
(my $header = $rule) =~ s/:[^:]+$/:/;
|
||||||
foreach my $part ($first .. $last) {
|
foreach my $part ($first .. $last) {
|
||||||
my $ip = NetAddr::IP::Lite->new($header . sprintf('%x',$part) . '/128')
|
my $ip = NetAddr::IP::Lite->new($header . sprintf('%x',$part) . '/128')
|
||||||
or next;
|
or next;
|
||||||
if ($neg xor ($ip == $addr)) {
|
if ($neg xor ($ip == $addr)) {
|
||||||
return 1 if not $all;
|
return true if not $all;
|
||||||
next INLIST;
|
next RULE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0 if (not $neg and $all);
|
return false if (not $neg and $all);
|
||||||
return 1 if ($neg and not $all);
|
return true if ($neg and not $all);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
next INLIST if $addr->bits != 32 and not $all;
|
next RULE if $addr->bits != 32 and not $all;
|
||||||
|
|
||||||
(my $header = $item) =~ s/\.[^.]+$/./;
|
(my $header = $rule) =~ s/\.[^.]+$/./;
|
||||||
foreach my $part ($first .. $last) {
|
foreach my $part ($first .. $last) {
|
||||||
my $ip = NetAddr::IP::Lite->new($header . $part . '/32')
|
my $ip = NetAddr::IP::Lite->new($header . $part . '/32')
|
||||||
or next;
|
or next;
|
||||||
if ($neg xor ($ip == $addr)) {
|
if ($neg xor ($ip == $addr)) {
|
||||||
return 1 if not $all;
|
return true if not $all;
|
||||||
next INLIST;
|
next RULE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0 if (not $neg and $all);
|
return false if (not $neg and $all);
|
||||||
return 1 if ($neg and not $all);
|
return true if ($neg and not $all);
|
||||||
}
|
}
|
||||||
next INLIST;
|
next RULE;
|
||||||
}
|
}
|
||||||
|
|
||||||
# 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 RULE if ref $rule;
|
||||||
|
|
||||||
# if no IP addr, cannot match IP prefix
|
# if no IP addr, cannot match IP prefix
|
||||||
next INLIST unless $addr;
|
next RULE unless $addr;
|
||||||
|
|
||||||
my $ip = NetAddr::IP::Lite->new($item)
|
my $ip = NetAddr::IP::Lite->new($rule)
|
||||||
or next INLIST;
|
or next RULE;
|
||||||
next INLIST if $ip->bits != $addr->bits and not $all;
|
next RULE if $ip->bits != $addr->bits and not $all;
|
||||||
|
|
||||||
if ($neg xor ($ip->contains($addr))) {
|
if ($neg xor ($ip->contains($addr))) {
|
||||||
return 1 if not $all;
|
return true if not $all;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return 0 if $all;
|
return false if $all;
|
||||||
}
|
}
|
||||||
next INLIST;
|
next RULE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ($all ? 1 : 0);
|
return ($all ? true : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
true;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use Dancer qw/:syntax :script/;
|
|||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
|
|
||||||
use App::Netdisco::Util::Device 'get_device';
|
use App::Netdisco::Util::Device 'get_device';
|
||||||
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
|
use App::Netdisco::Util::Permission qw/acl_matches acl_matches_only/;
|
||||||
|
|
||||||
use base 'Exporter';
|
use base 'Exporter';
|
||||||
our @EXPORT = ();
|
our @EXPORT = ();
|
||||||
@@ -107,9 +107,9 @@ sub port_reconfig_check {
|
|||||||
|
|
||||||
# check for limits on devices
|
# check for limits on devices
|
||||||
return "forbidden: device [$ip] is in denied ACL"
|
return "forbidden: device [$ip] is in denied ACL"
|
||||||
if check_acl_no($ip, 'portctl_no');
|
if acl_matches($ip, 'portctl_no');
|
||||||
return "forbidden: device [$ip] is not in permitted ACL"
|
return "forbidden: device [$ip] is not in permitted ACL"
|
||||||
unless check_acl_only($ip, 'portctl_only');
|
unless acl_matches_only($ip, 'portctl_only');
|
||||||
|
|
||||||
# only permitted to change interface name
|
# only permitted to change interface name
|
||||||
return "forbidden: not permitted to change port configuration"
|
return "forbidden: not permitted to change port configuration"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use Dancer::Plugin::Auth::Extensible;
|
|||||||
|
|
||||||
use List::Util 'first';
|
use List::Util 'first';
|
||||||
use List::MoreUtils ();
|
use List::MoreUtils ();
|
||||||
use App::Netdisco::Util::Permission 'check_acl_only';
|
use App::Netdisco::Util::Permission 'acl_matches';
|
||||||
use App::Netdisco::Web::Plugin;
|
use App::Netdisco::Web::Plugin;
|
||||||
|
|
||||||
register_device_tab({ tag => 'netmap', label => 'Neighbors' });
|
register_device_tab({ tag => 'netmap', label => 'Neighbors' });
|
||||||
@@ -228,11 +228,11 @@ ajax '/ajax/data/device/netmap' => require_login sub {
|
|||||||
|
|
||||||
# if host groups picked then use ACLs to filter
|
# if host groups picked then use ACLs to filter
|
||||||
my $first_hgrp =
|
my $first_hgrp =
|
||||||
first { check_acl_only($device, setting('host_groups')->{$_}) } @hgrplist;
|
first { acl_matches($device, setting('host_groups')->{$_}) } @hgrplist;
|
||||||
next DEVICE if ((scalar @hgrplist) and (not $first_hgrp));
|
next DEVICE if ((scalar @hgrplist) and (not $first_hgrp));
|
||||||
|
|
||||||
# now reset first_hgroup to be the group matching the device, if any
|
# now reset first_hgroup to be the group matching the device, if any
|
||||||
$first_hgrp = first { check_acl_only($device, setting('host_groups')->{$_}) }
|
$first_hgrp = first { acl_matches($device, setting('host_groups')->{$_}) }
|
||||||
keys %{ setting('host_group_displaynames') || {} };
|
keys %{ setting('host_group_displaynames') || {} };
|
||||||
|
|
||||||
++$logvals{ $device->get_column('log') || 1 };
|
++$logvals{ $device->get_column('log') || 1 };
|
||||||
|
|||||||
@@ -4,7 +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::Permission 'acl_matches';
|
||||||
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;
|
||||||
@@ -217,31 +217,33 @@ get '/ajax/content/device/ports' => require_login sub {
|
|||||||
|
|
||||||
# filter out hidden ones
|
# filter out hidden ones
|
||||||
if (not param('p_include_hidden')) {
|
if (not param('p_include_hidden')) {
|
||||||
my $device_ips = {};
|
my $port_map = {};
|
||||||
map { push @{ $device_ips->{$_->port} }, $_ }
|
my %to_hide = ();
|
||||||
$device->device_ips(undef, {prefetch => 'device_port'})->all;
|
|
||||||
|
|
||||||
map { push @{ $device_ips->{$_->port} }, $_ }
|
map { push @{ $port_map->{$_->port} }, $_ }
|
||||||
grep { ! exists $device_ips->{$_->port} }
|
grep { $_->port }
|
||||||
@results;
|
@results;
|
||||||
|
|
||||||
|
map { push @{ $port_map->{$_->port} }, $_ }
|
||||||
|
grep { $_->port }
|
||||||
|
$device->device_ips()->all;
|
||||||
|
|
||||||
foreach my $map (@{ setting('hide_deviceports')}) {
|
foreach my $map (@{ setting('hide_deviceports')}) {
|
||||||
next unless ref {} eq ref $map;
|
next unless ref {} eq ref $map;
|
||||||
|
|
||||||
foreach my $key (sort keys %$map) {
|
foreach my $key (sort keys %$map) {
|
||||||
# lhs matches device, rhs matches port
|
# lhs matches device, rhs matches port
|
||||||
next unless check_acl_no($device, $key);
|
next unless $key and $map->{$key};
|
||||||
|
next unless acl_matches($device, $key);
|
||||||
|
|
||||||
PORT: foreach my $port (sort keys %$device_ips) {
|
foreach my $port (sort keys %$port_map) {
|
||||||
foreach my $thing (@{ $device_ips->{$port} }) {
|
next unless acl_matches($port_map->{$port}, $map->{$key});
|
||||||
next unless check_acl_no($thing, $map->{$key});
|
++$to_hide{$port};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@results = grep { $_->port ne $port } @results;
|
@results = grep { ! exists $to_hide{$_->port} } @results;
|
||||||
next PORT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# sort ports
|
# sort ports
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package App::Netdisco::Worker::Plugin;
|
|||||||
use Dancer ':syntax';
|
use Dancer ':syntax';
|
||||||
use Dancer::Plugin;
|
use Dancer::Plugin;
|
||||||
|
|
||||||
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
|
use App::Netdisco::Util::Permission qw/acl_matches acl_matches_only/;
|
||||||
use aliased 'App::Netdisco::Worker::Status';
|
use aliased 'App::Netdisco::Worker::Status';
|
||||||
use Scope::Guard 'guard';
|
use Scope::Guard 'guard';
|
||||||
use Storable 'dclone';
|
use Storable 'dclone';
|
||||||
@@ -73,8 +73,8 @@ register 'register_worker' => sub {
|
|||||||
my $only = (exists $workerconf->{only} ? $workerconf->{only} : undef);
|
my $only = (exists $workerconf->{only} ? $workerconf->{only} : undef);
|
||||||
|
|
||||||
return $job->add_status( Status->info('skip: acls restricted') )
|
return $job->add_status( Status->info('skip: acls restricted') )
|
||||||
if ($no and check_acl_no($job->device, $no))
|
if ($no and acl_matches($job->device, $no))
|
||||||
or ($only and not check_acl_only($job->device, $only));
|
or ($only and not acl_matches_only($job->device, $only));
|
||||||
|
|
||||||
# reduce device_auth by driver and action filters
|
# reduce device_auth by driver and action filters
|
||||||
foreach my $stanza (@userconf) {
|
foreach my $stanza (@userconf) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use App::Netdisco::Worker::Plugin;
|
|||||||
use aliased 'App::Netdisco::Worker::Status';
|
use aliased 'App::Netdisco::Worker::Status';
|
||||||
|
|
||||||
use App::Netdisco::Util::Worker;
|
use App::Netdisco::Util::Worker;
|
||||||
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
|
use App::Netdisco::Util::Permission qw/acl_matches acl_matches_only/;
|
||||||
|
|
||||||
register_worker({ phase => 'late' }, sub {
|
register_worker({ phase => 'late' }, sub {
|
||||||
my ($job, $workerconf) = @_;
|
my ($job, $workerconf) = @_;
|
||||||
@@ -21,8 +21,8 @@ register_worker({ phase => 'late' }, sub {
|
|||||||
my $no = ($conf->{'filter'}->{'no'} || []);
|
my $no = ($conf->{'filter'}->{'no'} || []);
|
||||||
my $only = ($conf->{'filter'}->{'only'} || []);
|
my $only = ($conf->{'filter'}->{'only'} || []);
|
||||||
|
|
||||||
next if check_acl_no( $job->device, $no );
|
next if acl_matches( $job->device, $no );
|
||||||
next unless check_acl_only( $job->device, $only);
|
next unless acl_matches_only( $job->device, $only);
|
||||||
|
|
||||||
if ($conf->{'event'} eq 'arpnip') {
|
if ($conf->{'event'} eq 'arpnip') {
|
||||||
$count += queue_hook('arpnip', $conf);
|
$count += queue_hook('arpnip', $conf);
|
||||||
|
|||||||
@@ -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_no';
|
use App::Netdisco::Util::Permission 'acl_matches';
|
||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
use NetAddr::IP::Lite ':lower';
|
use NetAddr::IP::Lite ':lower';
|
||||||
use Time::HiRes 'gettimeofday';
|
use Time::HiRes 'gettimeofday';
|
||||||
@@ -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:__LOOPBACK_ADDRESSES__');
|
next if acl_matches($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::Util::Worker;
|
use App::Netdisco::Util::Worker;
|
||||||
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
|
use App::Netdisco::Util::Permission qw/acl_matches acl_matches_only/;
|
||||||
|
|
||||||
register_worker({ phase => 'late' }, sub {
|
register_worker({ phase => 'late' }, sub {
|
||||||
my ($job, $workerconf) = @_;
|
my ($job, $workerconf) = @_;
|
||||||
@@ -21,8 +21,8 @@ register_worker({ phase => 'late' }, sub {
|
|||||||
my $no = ($conf->{'filter'}->{'no'} || []);
|
my $no = ($conf->{'filter'}->{'no'} || []);
|
||||||
my $only = ($conf->{'filter'}->{'only'} || []);
|
my $only = ($conf->{'filter'}->{'only'} || []);
|
||||||
|
|
||||||
next if check_acl_no( $job->device, $no );
|
next if acl_matches( $job->device, $no );
|
||||||
next unless check_acl_only( $job->device, $only);
|
next unless acl_matches_only( $job->device, $only);
|
||||||
|
|
||||||
if ($conf->{'event'} eq 'delete') {
|
if ($conf->{'event'} eq 'delete') {
|
||||||
$count += queue_hook('delete', $conf);
|
$count += queue_hook('delete', $conf);
|
||||||
|
|||||||
@@ -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_no';
|
use App::Netdisco::Util::Permission 'acl_matches';
|
||||||
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';
|
||||||
@@ -34,18 +34,21 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
|
|
||||||
if (scalar @{ setting('device_identity') }) {
|
if (scalar @{ setting('device_identity') }) {
|
||||||
my @idmaps = @{ setting('device_identity') };
|
my @idmaps = @{ setting('device_identity') };
|
||||||
my $devips = $device->device_ips->order_by('alias');
|
my @devips = $device->device_ips->order_by('alias')->all;
|
||||||
|
|
||||||
ALIAS: while (my $alias = $devips->next) {
|
# using ALIASMAP break so that we stop after first successful renumber
|
||||||
next if $alias->alias eq $old_ip;
|
|
||||||
|
|
||||||
foreach my $map (@idmaps) {
|
ALIASMAP: foreach my $map (@idmaps) {
|
||||||
next unless ref {} eq ref $map;
|
next unless ref {} eq ref $map;
|
||||||
|
|
||||||
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_no($device, $key)
|
next unless $key and $map->{$key};
|
||||||
and check_acl_no($alias, $map->{$key})) {
|
next unless acl_matches($device, $key);
|
||||||
|
|
||||||
|
foreach my $alias (@devips) {
|
||||||
|
next if $alias->alias eq $old_ip;
|
||||||
|
next unless acl_matches($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',
|
||||||
@@ -55,7 +58,7 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
|
|
||||||
if (App::Netdisco::Transport::SNMP->test_connection( $alias->alias )) {
|
if (App::Netdisco::Transport::SNMP->test_connection( $alias->alias )) {
|
||||||
$new_ip = $alias->alias;
|
$new_ip = $alias->alias;
|
||||||
last ALIAS;
|
last ALIASMAP;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
debug sprintf ' [%s] device - cannot renumber to %s - SNMP connect failed',
|
debug sprintf ' [%s] device - cannot renumber to %s - SNMP connect failed',
|
||||||
@@ -64,7 +67,6 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} # ALIAS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return if $new_ip eq $old_ip;
|
return if $new_ip eq $old_ip;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use App::Netdisco::Worker::Plugin;
|
|||||||
use aliased 'App::Netdisco::Worker::Status';
|
use aliased 'App::Netdisco::Worker::Status';
|
||||||
|
|
||||||
use App::Netdisco::Util::Worker;
|
use App::Netdisco::Util::Worker;
|
||||||
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
|
use App::Netdisco::Util::Permission qw/acl_matches acl_matches_only/;
|
||||||
|
|
||||||
register_worker({ phase => 'late' }, sub {
|
register_worker({ phase => 'late' }, sub {
|
||||||
my ($job, $workerconf) = @_;
|
my ($job, $workerconf) = @_;
|
||||||
@@ -21,8 +21,8 @@ register_worker({ phase => 'late' }, sub {
|
|||||||
my $no = ($conf->{'filter'}->{'no'} || []);
|
my $no = ($conf->{'filter'}->{'no'} || []);
|
||||||
my $only = ($conf->{'filter'}->{'only'} || []);
|
my $only = ($conf->{'filter'}->{'only'} || []);
|
||||||
|
|
||||||
next if check_acl_no( $job->device, $no );
|
next if acl_matches( $job->device, $no );
|
||||||
next unless check_acl_only( $job->device, $only);
|
next unless acl_matches_only( $job->device, $only);
|
||||||
|
|
||||||
if (vars->{'new_device'} and $conf->{'event'} eq 'new_device') {
|
if (vars->{'new_device'} and $conf->{'event'} eq 'new_device') {
|
||||||
$count += queue_hook('new_device', $conf);
|
$count += queue_hook('new_device', $conf);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use aliased 'App::Netdisco::Worker::Status';
|
|||||||
|
|
||||||
use App::Netdisco::Transport::SNMP ();
|
use App::Netdisco::Transport::SNMP ();
|
||||||
use App::Netdisco::Util::Device qw/get_device is_discoverable/;
|
use App::Netdisco::Util::Device qw/get_device is_discoverable/;
|
||||||
use App::Netdisco::Util::Permission 'check_acl_no';
|
use App::Netdisco::Util::Permission 'acl_matches';
|
||||||
use App::Netdisco::JobQueue 'jq_insert';
|
use App::Netdisco::JobQueue 'jq_insert';
|
||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
use List::MoreUtils ();
|
use List::MoreUtils ();
|
||||||
@@ -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:__LOOPBACK_ADDRESSES__')) {
|
acl_matches($remote_ip, 'group:__LOOPBACK_ADDRESSES__')) {
|
||||||
|
|
||||||
if ($remote_id) {
|
if ($remote_id) {
|
||||||
my $devices = schema('netdisco')->resultset('Device');
|
my $devices = schema('netdisco')->resultset('Device');
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use App::Netdisco::Transport::SNMP;
|
|||||||
use aliased 'App::Netdisco::Worker::Status';
|
use aliased 'App::Netdisco::Worker::Status';
|
||||||
|
|
||||||
use App::Netdisco::Util::Device qw/get_device is_discoverable/;
|
use App::Netdisco::Util::Device qw/get_device is_discoverable/;
|
||||||
use App::Netdisco::Util::Permission 'check_acl_no';
|
use App::Netdisco::Util::Permission 'acl_matches';
|
||||||
use App::Netdisco::JobQueue 'jq_insert';
|
use App::Netdisco::JobQueue 'jq_insert';
|
||||||
|
|
||||||
register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
||||||
@@ -15,8 +15,8 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
|
|
||||||
my $device = $job->device;
|
my $device = $job->device;
|
||||||
return unless $device->in_storage and ($device->has_layer(3)
|
return unless $device->in_storage and ($device->has_layer(3)
|
||||||
or check_acl_no($device, 'force_macsuck')
|
or acl_matches($device, 'force_arpnip')
|
||||||
or check_acl_no($device, 'ignore_layers'));
|
or acl_matches($device, 'ignore_layers'));
|
||||||
|
|
||||||
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");
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ use App::Netdisco::Transport::SNMP ();
|
|||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
|
|
||||||
use Encode;
|
use Encode;
|
||||||
|
use App::Netdisco::Util::Web 'sort_port';
|
||||||
|
use App::Netdisco::Util::Permission 'acl_matches';
|
||||||
use App::Netdisco::Util::FastResolver 'hostnames_resolve_async';
|
use App::Netdisco::Util::FastResolver 'hostnames_resolve_async';
|
||||||
use App::Netdisco::Util::Device qw/is_discoverable match_to_setting/;
|
use App::Netdisco::Util::Device qw/is_discoverable match_to_setting/;
|
||||||
|
|
||||||
@@ -131,6 +133,28 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
$properties{ $port }->{remote_serial} = $rem_serial->{ $idx };
|
$properties{ $port }->{remote_serial} = $rem_serial->{ $idx };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scalar @{ setting('ignore_deviceports') }) {
|
||||||
|
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 $key and $map->{$key};
|
||||||
|
next unless acl_matches($device, $key);
|
||||||
|
|
||||||
|
foreach my $port (sort { sort_port($a, $b) } keys %properties) {
|
||||||
|
next unless acl_matches([$properties{$port}, $device_ports->{$port}],
|
||||||
|
$map->{$key});
|
||||||
|
|
||||||
|
debug sprintf ' [%s] properties - removing %s (config:ignore_deviceports)',
|
||||||
|
$device->ip, $port;
|
||||||
|
$device_ports->{$port}->delete; # like, for real, in the DB
|
||||||
|
delete $properties{$port};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach my $idx (keys %$interfaces) {
|
foreach my $idx (keys %$interfaces) {
|
||||||
next unless defined $idx;
|
next unless defined $idx;
|
||||||
my $port = $interfaces->{$idx} or next;
|
my $port = $interfaces->{$idx} or next;
|
||||||
@@ -155,7 +179,7 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
|
|
||||||
schema('netdisco')->txn_do(sub {
|
schema('netdisco')->txn_do(sub {
|
||||||
my $gone = $device->properties_ports->delete;
|
my $gone = $device->properties_ports->delete;
|
||||||
debug sprintf ' [%s] properties - removed %d ports with properties',
|
debug sprintf ' [%s] properties - removed %d port properties',
|
||||||
$device->ip, $gone;
|
$device->ip, $gone;
|
||||||
$device->properties_ports->populate(
|
$device->properties_ports->populate(
|
||||||
[map {{ port => $_, %{ $properties{$_} } }} keys %properties] );
|
[map {{ port => $_, %{ $properties{$_} } }} keys %properties] );
|
||||||
|
|||||||
@@ -5,14 +5,16 @@ 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 qw/acl_matches acl_matches_only/;
|
||||||
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';
|
||||||
use App::Netdisco::Util::SNMP 'snmp_comm_reindex';
|
use App::Netdisco::Util::SNMP 'snmp_comm_reindex';
|
||||||
|
use App::Netdisco::Util::Web 'sort_port';
|
||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
use Scope::Guard 'guard';
|
use Scope::Guard 'guard';
|
||||||
use NetAddr::IP::Lite ':lower';
|
use NetAddr::IP::Lite ':lower';
|
||||||
|
use Storable 'dclone';
|
||||||
use Encode;
|
use Encode;
|
||||||
|
|
||||||
register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
||||||
@@ -66,7 +68,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 acl_matches_only($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");
|
||||||
}
|
}
|
||||||
@@ -182,13 +184,6 @@ 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;
|
||||||
@@ -272,38 +267,29 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (scalar @{ setting('ignore_deviceports') }) {
|
if (scalar @{ setting('ignore_deviceports') }) {
|
||||||
foreach my $port (keys %$device_ips) {
|
my $port_map = {};
|
||||||
if (!exists $deviceports{$port}) {
|
|
||||||
delete $device_ips->{$port};
|
map { push @{ $port_map->{ $_->port } }, $_ }
|
||||||
next;
|
grep { $_->port }
|
||||||
}
|
$device->device_ips()->all;
|
||||||
foreach my $dip (@{ $device_ips->{$port} }) {
|
|
||||||
$dip->set_inflated_columns({ device_port => $deviceports{$port} });
|
map { push @{ $port_map->{ $_->{port} } }, $_ }
|
||||||
}
|
values %{ dclone (\%deviceports || {}) };
|
||||||
}
|
|
||||||
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')}) {
|
foreach my $map (@{ setting('ignore_deviceports')}) {
|
||||||
next unless ref {} eq ref $map;
|
next unless ref {} eq ref $map;
|
||||||
|
|
||||||
foreach my $key (sort keys %$map) {
|
foreach my $key (sort keys %$map) {
|
||||||
# lhs matches device, rhs matches port
|
# lhs matches device, rhs matches port
|
||||||
next unless check_acl_no($device, $key);
|
next unless $key and $map->{$key};
|
||||||
|
next unless acl_matches($device, $key);
|
||||||
|
|
||||||
PORT: foreach my $port (sort keys %$device_ips) {
|
foreach my $port (sort { sort_port( $a, $b) } keys %$port_map) {
|
||||||
foreach my $thing (@{ $device_ips->{$port} }) {
|
next unless acl_matches($port_map->{$port}, $map->{$key});
|
||||||
next unless check_acl_no($thing, $map->{$key});
|
|
||||||
|
|
||||||
debug sprintf ' [%s] interfaces - ignoring %s (config:ignore_deviceports)',
|
debug sprintf ' [%s] interfaces - ignoring %s (config:ignore_deviceports)',
|
||||||
$device->ip, $port;
|
$device->ip, $port;
|
||||||
delete $deviceports{$port};
|
delete $deviceports{$port};
|
||||||
next PORT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -446,7 +432,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:__LOOPBACK_ADDRESSES__');
|
next if acl_matches($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};
|
||||||
@@ -499,7 +485,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:__LOOPBACK_ADDRESSES__');
|
next if acl_matches($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}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use App::Netdisco::Worker::Plugin;
|
|||||||
use aliased 'App::Netdisco::Worker::Status';
|
use aliased 'App::Netdisco::Worker::Status';
|
||||||
|
|
||||||
use App::Netdisco::JobQueue 'jq_insert';
|
use App::Netdisco::JobQueue 'jq_insert';
|
||||||
use App::Netdisco::Util::Permission 'check_acl_no';
|
use App::Netdisco::Util::Permission 'acl_matches';
|
||||||
|
|
||||||
register_worker({ phase => 'main' }, sub {
|
register_worker({ phase => 'main' }, sub {
|
||||||
my ($job, $workerconf) = @_;
|
my ($job, $workerconf) = @_;
|
||||||
@@ -16,8 +16,8 @@ register_worker({ phase => 'main' }, sub {
|
|||||||
return unless $device->in_storage and $job->subaction eq 'with-nodes';
|
return unless $device->in_storage and $job->subaction eq 'with-nodes';
|
||||||
|
|
||||||
if (!defined $device->last_macsuck and ($device->has_layer(2)
|
if (!defined $device->last_macsuck and ($device->has_layer(2)
|
||||||
or check_acl_no($device, 'force_macsuck')
|
or acl_matches($device, 'force_macsuck')
|
||||||
or check_acl_no($device, 'ignore_layers'))) {
|
or acl_matches($device, 'ignore_layers'))) {
|
||||||
jq_insert({
|
jq_insert({
|
||||||
device => $device->ip,
|
device => $device->ip,
|
||||||
action => 'macsuck',
|
action => 'macsuck',
|
||||||
@@ -28,8 +28,8 @@ register_worker({ phase => 'main' }, sub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!defined $device->last_arpnip and ($device->has_layer(3)
|
if (!defined $device->last_arpnip and ($device->has_layer(3)
|
||||||
or check_acl_no($device, 'force_arpnip')
|
or acl_matches($device, 'force_arpnip')
|
||||||
or check_acl_no($device, 'ignore_layers'))) {
|
or acl_matches($device, 'ignore_layers'))) {
|
||||||
jq_insert({
|
jq_insert({
|
||||||
device => $device->ip,
|
device => $device->ip,
|
||||||
action => 'arpnip',
|
action => 'arpnip',
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use App::Netdisco::Worker::Plugin;
|
|||||||
use aliased 'App::Netdisco::Worker::Status';
|
use aliased 'App::Netdisco::Worker::Status';
|
||||||
|
|
||||||
use App::Netdisco::Util::Worker;
|
use App::Netdisco::Util::Worker;
|
||||||
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
|
use App::Netdisco::Util::Permission qw/acl_matches acl_matches_only/;
|
||||||
|
|
||||||
register_worker({ phase => 'late' }, sub {
|
register_worker({ phase => 'late' }, sub {
|
||||||
my ($job, $workerconf) = @_;
|
my ($job, $workerconf) = @_;
|
||||||
@@ -21,8 +21,8 @@ register_worker({ phase => 'late' }, sub {
|
|||||||
my $no = ($conf->{'filter'}->{'no'} || []);
|
my $no = ($conf->{'filter'}->{'no'} || []);
|
||||||
my $only = ($conf->{'filter'}->{'only'} || []);
|
my $only = ($conf->{'filter'}->{'only'} || []);
|
||||||
|
|
||||||
next if check_acl_no( $job->device, $no );
|
next if acl_matches( $job->device, $no );
|
||||||
next unless check_acl_only( $job->device, $only);
|
next unless acl_matches_only( $job->device, $only);
|
||||||
|
|
||||||
if ($conf->{'event'} eq 'macsuck') {
|
if ($conf->{'event'} eq 'macsuck') {
|
||||||
$count += queue_hook('macsuck', $conf);
|
$count += queue_hook('macsuck', $conf);
|
||||||
|
|||||||
@@ -5,11 +5,12 @@ 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 'acl_matches';
|
||||||
use App::Netdisco::Util::PortMAC 'get_port_macs';
|
use App::Netdisco::Util::PortMAC 'get_port_macs';
|
||||||
use App::Netdisco::Util::Device 'match_to_setting';
|
use App::Netdisco::Util::Device 'match_to_setting';
|
||||||
use App::Netdisco::Util::Node 'check_mac';
|
use App::Netdisco::Util::Node 'check_mac';
|
||||||
use App::Netdisco::Util::SNMP 'snmp_comm_reindex';
|
use App::Netdisco::Util::SNMP 'snmp_comm_reindex';
|
||||||
|
use App::Netdisco::Util::Web 'sort_port';
|
||||||
|
|
||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
use Time::HiRes 'gettimeofday';
|
use Time::HiRes 'gettimeofday';
|
||||||
@@ -37,7 +38,8 @@ register_worker({ phase => 'early',
|
|||||||
|
|
||||||
# cache the device ports to save hitting the database for many single rows
|
# cache the device ports to save hitting the database for many single rows
|
||||||
vars->{'device_ports'} = {map {($_->port => $_)}
|
vars->{'device_ports'} = {map {($_->port => $_)}
|
||||||
$device->ports(undef, {prefetch => {neighbor_alias => 'device'}})->all};
|
$device->ports(undef, {prefetch => ['properties',
|
||||||
|
{neighbor_alias => 'device'}]})->all};
|
||||||
});
|
});
|
||||||
|
|
||||||
register_worker({ phase => 'main', driver => 'direct',
|
register_worker({ phase => 'main', driver => 'direct',
|
||||||
@@ -488,14 +490,15 @@ sub sanity_macs {
|
|||||||
|
|
||||||
foreach my $key (sort keys %$map) {
|
foreach my $key (sort keys %$map) {
|
||||||
# lhs matches device, rhs matches port
|
# lhs matches device, rhs matches port
|
||||||
next unless check_acl_only($device, $key);
|
next unless $key and $map->{$key};
|
||||||
|
next unless acl_matches($device, $key);
|
||||||
|
|
||||||
foreach my $port (keys %{ $device_ports }) {
|
foreach my $port (sort { sort_port($a, $b) } keys %{ $device_ports }) {
|
||||||
next unless check_acl_only($device_ports->{$port}, $map->{$key});
|
next unless acl_matches($device_ports->{$port}, $map->{$key});
|
||||||
|
|
||||||
++$ignoreport->{$port};
|
|
||||||
debug sprintf ' [%s] macsuck %s - port suppressed by macsuck_no_deviceports',
|
debug sprintf ' [%s] macsuck %s - port suppressed by macsuck_no_deviceports',
|
||||||
$device->ip, $port;
|
$device->ip, $port;
|
||||||
|
++$ignoreport->{$port};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -559,7 +562,7 @@ sub sanity_macs {
|
|||||||
# with device lookups.
|
# with device lookups.
|
||||||
|
|
||||||
my $neigh_cannot_macsuck = eval { # can fail
|
my $neigh_cannot_macsuck = eval { # can fail
|
||||||
check_acl_no(($device_port->neighbor || "0 but true"), 'macsuck_unsupported') ||
|
acl_matches(($device_port->neighbor || "0 but true"), 'macsuck_unsupported') ||
|
||||||
match_to_setting($device_port->remote_type, 'macsuck_unsupported_type') };
|
match_to_setting($device_port->remote_type, 'macsuck_unsupported_type') };
|
||||||
|
|
||||||
# here, is_uplink comes from Discover::Neighbors finding LLDP remnants
|
# here, is_uplink comes from Discover::Neighbors finding LLDP remnants
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use aliased 'App::Netdisco::Worker::Status';
|
|||||||
use Path::Class;
|
use Path::Class;
|
||||||
use List::Util qw/pairkeys pairfirst/;
|
use List::Util qw/pairkeys pairfirst/;
|
||||||
use File::Slurper qw/read_lines write_text/;
|
use File::Slurper qw/read_lines write_text/;
|
||||||
use App::Netdisco::Util::Permission 'check_acl_no';
|
use App::Netdisco::Util::Permission 'acl_matches';
|
||||||
|
|
||||||
register_worker({ phase => 'main' }, sub {
|
register_worker({ phase => 'main' }, sub {
|
||||||
my ($job, $workerconf) = @_;
|
my ($job, $workerconf) = @_;
|
||||||
@@ -65,16 +65,16 @@ register_worker({ phase => 'main' }, sub {
|
|||||||
my $routerunicity = {};
|
my $routerunicity = {};
|
||||||
while (my $d = $devices->next) {
|
while (my $d = $devices->next) {
|
||||||
|
|
||||||
if (check_acl_no($d, $config->{excluded})) {
|
if (acl_matches($d, $config->{excluded})) {
|
||||||
debug " skipping $d: device excluded of export";
|
debug " skipping $d: device excluded of export";
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
|
||||||
my $name = check_acl_no($d, $config->{by_ip}) ? $d->ip : ($d->dns || $d->name);
|
my $name = acl_matches($d, $config->{by_ip}) ? $d->ip : ($d->dns || $d->name);
|
||||||
$name =~ s/$domain_suffix$// if check_acl_no($d, $config->{by_hostname});
|
$name =~ s/$domain_suffix$// if acl_matches($d, $config->{by_hostname});
|
||||||
|
|
||||||
my ($group) =
|
my ($group) =
|
||||||
(pairkeys pairfirst { check_acl_no($d, $b) } %{ $config->{groups} }) || $default_group;
|
(pairkeys pairfirst { acl_matches($d, $b) } %{ $config->{groups} }) || $default_group;
|
||||||
|
|
||||||
if (exists($routerunicity->{$group}->{$name})) {
|
if (exists($routerunicity->{$group}->{$name})) {
|
||||||
debug " skipping $d: device excluded because already present in export list";
|
debug " skipping $d: device excluded because already present in export list";
|
||||||
@@ -82,7 +82,7 @@ register_worker({ phase => 'main' }, sub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
my ($vendor) =
|
my ($vendor) =
|
||||||
(pairkeys pairfirst { check_acl_no($d, $b) } %{ $config->{vendormap} })
|
(pairkeys pairfirst { acl_matches($d, $b) } %{ $config->{vendormap} })
|
||||||
|| $d->vendor;
|
|| $d->vendor;
|
||||||
|
|
||||||
if (not ($name and $vendor)) {
|
if (not ($name and $vendor)) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package App::Netdisco::Worker::Runner;
|
|||||||
use Dancer qw/:moose :syntax/;
|
use Dancer qw/:moose :syntax/;
|
||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
use App::Netdisco::Util::Device 'get_device';
|
use App::Netdisco::Util::Device 'get_device';
|
||||||
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
|
use App::Netdisco::Util::Permission qw/acl_matches acl_matches_only/;
|
||||||
use aliased 'App::Netdisco::Worker::Status';
|
use aliased 'App::Netdisco::Worker::Status';
|
||||||
|
|
||||||
use Try::Tiny;
|
use Try::Tiny;
|
||||||
@@ -43,8 +43,8 @@ sub run {
|
|||||||
my $no = (exists $stanza->{no} ? $stanza->{no} : undef);
|
my $no = (exists $stanza->{no} ? $stanza->{no} : undef);
|
||||||
my $only = (exists $stanza->{only} ? $stanza->{only} : undef);
|
my $only = (exists $stanza->{only} ? $stanza->{only} : undef);
|
||||||
|
|
||||||
next if $no and check_acl_no($job->device, $no);
|
next if $no and acl_matches($job->device, $no);
|
||||||
next if $only and not check_acl_only($job->device, $only);
|
next if $only and not acl_matches_only($job->device, $only);
|
||||||
|
|
||||||
push @newuserconf, dclone $stanza;
|
push @newuserconf, dclone $stanza;
|
||||||
}
|
}
|
||||||
|
|||||||
179
xt/20-checkacl.t
179
xt/20-checkacl.t
@@ -8,8 +8,8 @@ use Test::More 1.302083;
|
|||||||
use Test::File::ShareDir::Dist { 'App-Netdisco' => 'share/' };
|
use Test::File::ShareDir::Dist { 'App-Netdisco' => 'share/' };
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
use_ok( 'App::Netdisco::Configuration', 'check_acl' );
|
use_ok( 'App::Netdisco::Configuration', 'acl_matches' );
|
||||||
use_ok( 'App::Netdisco::Util::Permission', 'check_acl' );
|
use_ok( 'App::Netdisco::Util::Permission', 'acl_matches' );
|
||||||
}
|
}
|
||||||
|
|
||||||
use Dancer qw/:script !pass/;
|
use Dancer qw/:script !pass/;
|
||||||
@@ -37,79 +37,79 @@ my @conf = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
# name, ipv4, ipv6, v4 prefix, v6 prefix
|
# name, ipv4, ipv6, v4 prefix, v6 prefix
|
||||||
ok(check_acl('localhost',[$conf[0]]), 'same name');
|
ok(acl_matches('localhost',[$conf[0]]), 'same name');
|
||||||
ok(check_acl('127.0.0.1',[$conf[2]]), 'same ipv4');
|
ok(acl_matches('127.0.0.1',[$conf[2]]), 'same ipv4');
|
||||||
ok(check_acl('::1',[$conf[4]]), 'same ipv6');
|
ok(acl_matches('::1',[$conf[4]]), 'same ipv6');
|
||||||
ok(check_acl('127.0.0.0/29',[$conf[6]]), 'same v4 prefix');
|
ok(acl_matches('127.0.0.0/29',[$conf[6]]), 'same v4 prefix');
|
||||||
ok(check_acl('::1/128',[$conf[8]]), 'same v6 prefix');
|
ok(acl_matches('::1/128',[$conf[8]]), 'same v6 prefix');
|
||||||
|
|
||||||
# failed name, ipv4, ipv6, v4 prefix, v6 prefix
|
# failed name, ipv4, ipv6, v4 prefix, v6 prefix
|
||||||
is(check_acl('www.microsoft.com',[$conf[0]]), 0, 'failed name');
|
is(acl_matches('www.microsoft.com',[$conf[0]]), 0, 'failed name');
|
||||||
is(check_acl('172.20.0.1',[$conf[2]]), 0, 'failed ipv4');
|
is(acl_matches('172.20.0.1',[$conf[2]]), 0, 'failed ipv4');
|
||||||
is(check_acl('2001:db8::5',[$conf[4]]), 0, 'failed ipv6');
|
is(acl_matches('2001:db8::5',[$conf[4]]), 0, 'failed ipv6');
|
||||||
is(check_acl('172.16.1.3/29',[$conf[6]]), 0, 'failed v4 prefix');
|
is(acl_matches('172.16.1.3/29',[$conf[6]]), 0, 'failed v4 prefix');
|
||||||
is(check_acl('2001:db8:f00d::/64',[$conf[8]]), 0, 'failed v6 prefix');
|
is(acl_matches('2001:db8:f00d::/64',[$conf[8]]), 0, 'failed v6 prefix');
|
||||||
|
|
||||||
# negated name, ipv4, ipv6, v4 prefix, v6 prefix
|
# negated name, ipv4, ipv6, v4 prefix, v6 prefix
|
||||||
ok(check_acl('localhost',[$conf[1]]), 'not same name');
|
ok(acl_matches('localhost',[$conf[1]]), 'not same name');
|
||||||
ok(check_acl('127.0.0.1',[$conf[3]]), 'not same ipv4');
|
ok(acl_matches('127.0.0.1',[$conf[3]]), 'not same ipv4');
|
||||||
ok(check_acl('::1',[$conf[5]]), 'not same ipv6');
|
ok(acl_matches('::1',[$conf[5]]), 'not same ipv6');
|
||||||
ok(check_acl('127.0.0.0/29',[$conf[7]]), 'not same v4 prefix');
|
ok(acl_matches('127.0.0.0/29',[$conf[7]]), 'not same v4 prefix');
|
||||||
ok(check_acl('::1/128',[$conf[9]]), 'not same v6 prefix');
|
ok(acl_matches('::1/128',[$conf[9]]), 'not same v6 prefix');
|
||||||
|
|
||||||
# v4 range, v6 range
|
# v4 range, v6 range
|
||||||
ok(check_acl('127.0.0.1',[$conf[10]]), 'in v4 range');
|
ok(acl_matches('127.0.0.1',[$conf[10]]), 'in v4 range');
|
||||||
ok(check_acl('::1',[$conf[12]]), 'in v6 range');
|
ok(acl_matches('::1',[$conf[12]]), 'in v6 range');
|
||||||
|
|
||||||
# failed v4 range, v6 range
|
# failed v4 range, v6 range
|
||||||
is(check_acl('172.20.0.1',[$conf[10]]), 0, 'failed v4 range');
|
is(acl_matches('172.20.0.1',[$conf[10]]), 0, 'failed v4 range');
|
||||||
is(check_acl('2001:db8::5',[$conf[12]]), 0, 'failed v6 range');
|
is(acl_matches('2001:db8::5',[$conf[12]]), 0, 'failed v6 range');
|
||||||
|
|
||||||
# negated v4 range, v6 range
|
# negated v4 range, v6 range
|
||||||
ok(check_acl('127.0.0.1',[$conf[11]]), 'not in v4 range');
|
ok(acl_matches('127.0.0.1',[$conf[11]]), 'not in v4 range');
|
||||||
ok(check_acl('::1',[$conf[13]]), 'not in v6 range');
|
ok(acl_matches('::1',[$conf[13]]), 'not in v6 range');
|
||||||
|
|
||||||
# hostname regexp
|
# hostname regexp
|
||||||
# FIXME ok(check_acl('localhost',[$conf[14]]), 'name regexp');
|
# FIXME ok(acl_matches('localhost',[$conf[14]]), 'name regexp');
|
||||||
# FIXME ok(check_acl('127.0.0.1',[$conf[14]]), 'IP regexp');
|
# FIXME ok(acl_matches('127.0.0.1',[$conf[14]]), 'IP regexp');
|
||||||
is(check_acl('www.google.com',[$conf[14]]), 0, 'failed regexp');
|
is(acl_matches('www.google.com',[$conf[14]]), 0, 'failed regexp');
|
||||||
|
|
||||||
# OR of prefix, range, regexp, property (2 of, 3 of, 4 of)
|
# OR of prefix, range, regexp, property (2 of, 3 of, 4 of)
|
||||||
ok(check_acl('127.0.0.1',[@conf[8,0]]), 'OR: prefix, name');
|
ok(acl_matches('127.0.0.1',[@conf[8,0]]), 'OR: prefix, name');
|
||||||
ok(check_acl('127.0.0.1',[@conf[8,12,0]]), 'OR: prefix, range, name');
|
ok(acl_matches('127.0.0.1',[@conf[8,12,0]]), 'OR: prefix, range, name');
|
||||||
ok(check_acl('127.0.0.1',[@conf[8,12,15,0]]), 'OR: prefix, range, regexp, name');
|
ok(acl_matches('127.0.0.1',[@conf[8,12,15,0]]), 'OR: prefix, range, regexp, name');
|
||||||
|
|
||||||
# OR of negated prefix, range, regexp, property (2 of, 3 of, 4 of)
|
# OR of negated prefix, range, regexp, property (2 of, 3 of, 4 of)
|
||||||
ok(check_acl('127.0.0.1',[@conf[17,0]]), 'OR: !prefix, name');
|
ok(acl_matches('127.0.0.1',[@conf[17,0]]), 'OR: !prefix, name');
|
||||||
ok(check_acl('127.0.0.1',[@conf[17,18,0]]), 'OR: !prefix, !range, name');
|
ok(acl_matches('127.0.0.1',[@conf[17,18,0]]), 'OR: !prefix, !range, name');
|
||||||
ok(check_acl('127.0.0.1',[@conf[17,18,19,0]]), 'OR: !prefix, !range, !regexp, name');
|
ok(acl_matches('127.0.0.1',[@conf[17,18,19,0]]), 'OR: !prefix, !range, !regexp, name');
|
||||||
|
|
||||||
# AND of prefix, range, regexp, property (2 of, 3 of, 4 of)
|
# AND of prefix, range, regexp, property (2 of, 3 of, 4 of)
|
||||||
ok(check_acl('127.0.0.1',[@conf[6,0,20]]), 'AND: prefix, name');
|
ok(acl_matches('127.0.0.1',[@conf[6,0,20]]), 'AND: prefix, name');
|
||||||
ok(check_acl('127.0.0.1',[@conf[6,10,0,20]]), 'AND: prefix, range, name');
|
ok(acl_matches('127.0.0.1',[@conf[6,10,0,20]]), 'AND: prefix, range, name');
|
||||||
# FIXME ok(check_acl('127.0.0.1',[@conf[6,10,14,0,20]]), 'AND: prefix, range, regexp, name');
|
# FIXME ok(acl_matches('127.0.0.1',[@conf[6,10,14,0,20]]), 'AND: prefix, range, regexp, name');
|
||||||
|
|
||||||
# failed AND on prefix, range, regexp
|
# failed AND on prefix, range, regexp
|
||||||
is(check_acl('127.0.0.1',[@conf[8,10,14,0,20]]), 0, 'failed AND: prefix!, range, regexp, name');
|
is(acl_matches('127.0.0.1',[@conf[8,10,14,0,20]]), 0, 'failed AND: prefix!, range, regexp, name');
|
||||||
is(check_acl('127.0.0.1',[@conf[6,12,14,0,20]]), 0, 'failed AND: prefix, range!, regexp, name');
|
is(acl_matches('127.0.0.1',[@conf[6,12,14,0,20]]), 0, 'failed AND: prefix, range!, regexp, name');
|
||||||
is(check_acl('127.0.0.1',[@conf[6,10,15,0,20]]), 0, 'failed AND: prefix, range, regexp!, name');
|
is(acl_matches('127.0.0.1',[@conf[6,10,15,0,20]]), 0, 'failed AND: prefix, range, regexp!, name');
|
||||||
|
|
||||||
# AND of negated prefix, range, regexp, property (2 of, 3 of, 4 of)
|
# AND of negated prefix, range, regexp, property (2 of, 3 of, 4 of)
|
||||||
ok(check_acl('127.0.0.1',[@conf[9,0,20]]), 'AND: !prefix, name');
|
ok(acl_matches('127.0.0.1',[@conf[9,0,20]]), 'AND: !prefix, name');
|
||||||
ok(check_acl('127.0.0.1',[@conf[7,11,0,20]]), 'AND: !prefix, !range, name');
|
ok(acl_matches('127.0.0.1',[@conf[7,11,0,20]]), 'AND: !prefix, !range, name');
|
||||||
ok(check_acl('127.0.0.1',[@conf[9,13,16,0,20]]), 'AND: !prefix, !range, !regexp, name');
|
ok(acl_matches('127.0.0.1',[@conf[9,13,16,0,20]]), 'AND: !prefix, !range, !regexp, name');
|
||||||
|
|
||||||
# group ref
|
# group ref
|
||||||
is(check_acl('192.0.2.1',[$conf[22]]), 1, '!missing group ref');
|
is(acl_matches('192.0.2.1',[$conf[22]]), 1, '!missing group ref');
|
||||||
is(check_acl('192.0.2.1',[$conf[21]]), 0, 'failed missing group ref');
|
is(acl_matches('192.0.2.1',[$conf[21]]), 0, 'failed missing group ref');
|
||||||
setting('host_groups')->{'groupreftest'} = ['192.0.2.1'];
|
setting('host_groups')->{'groupreftest'} = ['192.0.2.1'];
|
||||||
is(check_acl('192.0.2.1',[$conf[21]]), 1, 'group ref');
|
is(acl_matches('192.0.2.1',[$conf[21]]), 1, 'group ref');
|
||||||
is(check_acl('192.0.2.1',[$conf[22]]), 0, 'failed !missing group ref');
|
is(acl_matches('192.0.2.1',[$conf[22]]), 0, 'failed !missing group ref');
|
||||||
|
|
||||||
# scalar promoted to list
|
# scalar promoted to list
|
||||||
ok(check_acl('localhost',$conf[0]), 'scalar promoted');
|
ok(acl_matches('localhost',$conf[0]), 'scalar promoted');
|
||||||
ok(check_acl('localhost',$conf[1]), 'not scalar promoted');
|
ok(acl_matches('localhost',$conf[1]), 'not scalar promoted');
|
||||||
is(check_acl('www.microsoft.com',$conf[0]), 0, 'failed scalar promoted');
|
is(acl_matches('www.microsoft.com',$conf[0]), 0, 'failed scalar promoted');
|
||||||
|
|
||||||
use App::Netdisco::DB;
|
use App::Netdisco::DB;
|
||||||
my $dip = App::Netdisco::DB->resultset('DeviceIp')->new_result({
|
my $dip = App::Netdisco::DB->resultset('DeviceIp')->new_result({
|
||||||
@@ -125,15 +125,80 @@ my $dip = App::Netdisco::DB->resultset('DeviceIp')->new_result({
|
|||||||
});
|
});
|
||||||
|
|
||||||
# device properties
|
# device properties
|
||||||
ok(check_acl($dip, [$conf[23]]), 'instance anon property deviceport:alias');
|
ok(acl_matches($dip, [$conf[23]]), '1obj instance anon property deviceport:alias');
|
||||||
ok(check_acl($dip, ['ip:'.$conf[2]]), 'instance named property deviceport:ip');
|
ok(acl_matches($dip, ['ip:'.$conf[2]]), '1obj instance named property deviceport:ip');
|
||||||
ok(check_acl($dip, ['!ip:'. $conf[23]]), 'negated instance named property deviceport:ip');
|
ok(acl_matches($dip, ['!ip:'. $conf[23]]), '1obj negated instance named property deviceport:ip');
|
||||||
is(check_acl($dip, ['port:'.$conf[2]]), 0, 'failed instance named property deviceport:ip');
|
is(acl_matches($dip, ['port:'.$conf[2]]), 0, '1obj failed instance named property deviceport:ip');
|
||||||
ok(check_acl($dip, ['port:.*GigabitEthernet.*']), 'instance named property regexp deviceport:port');
|
ok(acl_matches($dip, ['port:.*GigabitEthernet.*']), '1obj instance named property regexp deviceport:port');
|
||||||
|
|
||||||
ok(check_acl($dip, ['type:l3ipvlan']), 'related item field match');
|
# DeviceIp no longer has DevicePort slot accessors
|
||||||
ok(check_acl($dip, ['remote_ip:']), 'related item field empty');
|
#ok(acl_matches($dip, ['type:l3ipvlan']), '1obj related item field match');
|
||||||
ok(check_acl($dip, ['!type:']), 'related item field not empty');
|
#ok(acl_matches($dip, ['remote_ip:']), '1obj related item field empty');
|
||||||
is(check_acl($dip, ['foobar:xyz']), 0, 'unknown property');
|
#ok(acl_matches($dip, ['!type:']), '1obj related item field not empty');
|
||||||
|
#is(acl_matches($dip, ['foobar:xyz']), 0, '1obj unknown property');
|
||||||
|
|
||||||
|
my $dip2 = App::Netdisco::DB->resultset('DeviceIp')->new_result({
|
||||||
|
ip => '127.0.0.1',
|
||||||
|
port => 'TenGigabitEthernet1/10',
|
||||||
|
alias => '192.0.2.1',
|
||||||
|
});
|
||||||
|
|
||||||
|
my $dp = App::Netdisco::DB->resultset('DevicePort')->new_result({
|
||||||
|
ip => '127.0.0.1',
|
||||||
|
port => 'TenGigabitEthernet1/10',
|
||||||
|
type => 'l3ipvlan',
|
||||||
|
});
|
||||||
|
|
||||||
|
# device properties
|
||||||
|
ok(acl_matches([$dip2, $dp], [$conf[23]]), '2obj instance anon property deviceport:alias');
|
||||||
|
ok(acl_matches([$dip2, $dp], ['ip:'.$conf[2]]), '2obj instance named property deviceport:ip');
|
||||||
|
ok(acl_matches([undef, $dip2, $dp], ['ip:'.$conf[2]]), '2obj instance named property after undef');
|
||||||
|
ok(acl_matches([$dip2, $dp], ['!ip:'. $conf[23]]), '2obj negated instance named property deviceport:ip');
|
||||||
|
is(acl_matches([$dip2, $dp], ['port:'.$conf[2]]), 0, '2obj failed instance named property deviceport:ip');
|
||||||
|
ok(acl_matches([$dip2, $dp], ['port:.*GigabitEthernet.*']), '2obj instance named property regexp deviceport:port');
|
||||||
|
|
||||||
|
ok(acl_matches([$dip2, $dp], ['type:l3ipvlan']), '2obj related item field match');
|
||||||
|
ok(acl_matches([$dip2, $dp], ['remote_ip:']), '2obj related item field empty');
|
||||||
|
ok(acl_matches([$dip2, $dp], ['!type:']), '2obj related item field not empty');
|
||||||
|
is(acl_matches([$dip2, $dp], ['foobar:xyz']), 0, '2obj unknown property');
|
||||||
|
|
||||||
|
my $dip2c = { $dip2->get_inflated_columns };
|
||||||
|
my $dpc = { $dp->get_inflated_columns };
|
||||||
|
|
||||||
|
# device properties
|
||||||
|
ok(acl_matches([$dip2c, $dpc], [$conf[23]]), 'hh instance anon property deviceport:alias');
|
||||||
|
ok(acl_matches([$dip2c, $dpc], ['ip:'.$conf[2]]), 'hh instance named property deviceport:ip');
|
||||||
|
ok(acl_matches([$dip2c, $dpc], ['!ip:'. $conf[23]]), 'hh negated instance named property deviceport:ip');
|
||||||
|
is(acl_matches([$dip2c, $dpc], ['port:'.$conf[2]]), 0, 'hh failed instance named property deviceport:ip');
|
||||||
|
ok(acl_matches([$dip2c, $dpc], ['port:.*GigabitEthernet.*']), 'hh instance named property regexp deviceport:port');
|
||||||
|
|
||||||
|
ok(acl_matches([$dip2c, $dpc], ['type:l3ipvlan']), 'hh related item field match');
|
||||||
|
ok(acl_matches([$dip2c, $dpc], ['remote_ip:']), 'hh related item field empty');
|
||||||
|
ok(acl_matches([$dip2c, $dpc], ['!type:']), 'hh related item field not empty');
|
||||||
|
is(acl_matches([$dip2c, $dpc], ['foobar:xyz']), 0, 'hh unknown property');
|
||||||
|
|
||||||
|
# device properties
|
||||||
|
ok(acl_matches([$dip2, $dpc], [$conf[23]]), 'oh instance anon property deviceport:alias');
|
||||||
|
ok(acl_matches([$dip2, $dpc], ['ip:'.$conf[2]]), 'oh instance named property deviceport:ip');
|
||||||
|
ok(acl_matches([$dip2, $dpc], ['!ip:'. $conf[23]]), 'oh negated instance named property deviceport:ip');
|
||||||
|
is(acl_matches([$dip2, $dpc], ['port:'.$conf[2]]), 0, 'oh failed instance named property deviceport:ip');
|
||||||
|
ok(acl_matches([$dip2, $dpc], ['port:.*GigabitEthernet.*']), 'oh instance named property regexp deviceport:port');
|
||||||
|
|
||||||
|
ok(acl_matches([$dip2, $dpc], ['type:l3ipvlan']), 'oh related item field match');
|
||||||
|
ok(acl_matches([$dip2, $dpc], ['remote_ip:']), 'oh related item field empty');
|
||||||
|
ok(acl_matches([$dip2, $dpc], ['!type:']), 'oh related item field not empty');
|
||||||
|
is(acl_matches([$dip2, $dpc], ['foobar:xyz']), 0, 'oh unknown property');
|
||||||
|
|
||||||
|
# device properties
|
||||||
|
ok(acl_matches([$dip2c, $dp], [$conf[23]]), 'ho instance anon property deviceport:alias');
|
||||||
|
ok(acl_matches([$dip2c, $dp], ['ip:'.$conf[2]]), 'ho instance named property deviceport:ip');
|
||||||
|
ok(acl_matches([$dip2c, $dp], ['!ip:'. $conf[23]]), 'ho negated instance named property deviceport:ip');
|
||||||
|
is(acl_matches([$dip2c, $dp], ['port:'.$conf[2]]), 0, 'ho failed instance named property deviceport:ip');
|
||||||
|
ok(acl_matches([$dip2c, $dp], ['port:.*GigabitEthernet.*']), 'ho instance named property regexp deviceport:port');
|
||||||
|
|
||||||
|
ok(acl_matches([$dip2c, $dp], ['type:l3ipvlan']), 'ho related item field match');
|
||||||
|
ok(acl_matches([$dip2c, $dp], ['remote_ip:']), 'ho related item field empty');
|
||||||
|
ok(acl_matches([$dip2c, $dp], ['!type:']), 'ho related item field not empty');
|
||||||
|
is(acl_matches([$dip2c, $dp], ['foobar:xyz']), 0, 'ho unknown property');
|
||||||
|
|
||||||
done_testing;
|
done_testing;
|
||||||
|
|||||||
Reference in New Issue
Block a user