diff --git a/Netdisco/Changes b/Netdisco/Changes index e4208ec8..9776caee 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -1,10 +1,11 @@ -2.017001_001 - +2.017001_002 - [NEW FEATURES] * Add VLAN Inventory Report * Add Wireless SSID Inventory Report * Add Device Inventory by Location Report + * Node DNS names resolved in their own job - see nodenames_no and nodenames_only [ENHANCEMENTS] diff --git a/Netdisco/lib/App/Netdisco/Core/Arpnip.pm b/Netdisco/lib/App/Netdisco/Core/Arpnip.pm index 22538ead..549169bc 100644 --- a/Netdisco/lib/App/Netdisco/Core/Arpnip.pm +++ b/Netdisco/lib/App/Netdisco/Core/Arpnip.pm @@ -10,7 +10,7 @@ use Time::HiRes 'gettimeofday'; use base 'Exporter'; our @EXPORT = (); -our @EXPORT_OK = qw/ do_arpnip store_arp /; +our @EXPORT_OK = qw/ do_arpnip store_arp resolve_node_names /; our %EXPORT_TAGS = (all => \@EXPORT_OK); =head1 NAME @@ -82,16 +82,16 @@ sub _get_arps { my $ip = $netaddr->{$arp}; next unless defined $ip; next unless check_mac($device, $node); - push @arps, [$node, $ip, hostname_from_ip($ip)]; + push @arps, [$node, $ip]; } return @arps; } -=head2 store_arp( $mac, $ip, $name, $now? ) +=head2 store_arp( $mac, $ip, $now? ) -Stores a new entry to the C table with the given MAC, IP (v4 or v6) -and DNS host name. +Stores a new entry to the C table with the given MAC, and IP (v4 or +v6). Will mark old entries for this IP as no longer C. @@ -101,7 +101,7 @@ C timestamp, otherwise the current timestamp (C) is used. =cut sub store_arp { - my ($mac, $ip, $name, $now) = @_; + my ($mac, $ip, $now) = @_; $now ||= 'now()'; schema('netdisco')->txn_do(sub { @@ -119,7 +119,6 @@ sub store_arp { ->search({'me.mac' => $mac, 'me.ip' => $ip}) ->update_or_create( { - dns => $name, active => \'true', time_last => \$now, }, @@ -172,4 +171,39 @@ sub _store_subnet { }); } +=head2 resolve_node_names( $device ) + +Given a Device database object, resolve Node IP (ARP) entries belonging to +this device into DNS names, and store them in the C database table. + +This action is usually queued following C so that it may run +asynchronously, and/or on another daemon worker node. + +=cut + +sub resolve_node_names { + my ($device) = @_; + + schema('netdisco')->txn_do(sub { + my $nodeips = schema('netdisco') + ->resultset('NodeIp')->search( + { + -and => [ + -bool => 'me.active', + -bool => 'nodes.active', + ], + 'nodes.switch' => $device->ip, + }, + { + join => 'nodes', + for => 'update', + } + ); + + while (my $nodeip = $nodeips->next) { + $nodeip->update({dns => hostname_from_ip($nodeip->ip)}); + } + }); +} + 1; diff --git a/Netdisco/lib/App/Netdisco/Daemon/Queue.pm b/Netdisco/lib/App/Netdisco/Daemon/Queue.pm index f89e14fb..336f65a4 100644 --- a/Netdisco/lib/App/Netdisco/Daemon/Queue.pm +++ b/Netdisco/lib/App/Netdisco/Daemon/Queue.pm @@ -22,7 +22,7 @@ sub capacity_for { debug "checking local capacity for action $action"; my $action_map = { - Poller => [qw/discoverall discover arpwalk arpnip macwalk macsuck/], + Poller => [qw/discoverall discover arpwalk arpnip nodenames macwalk macsuck/], Interactive => [qw/location contact portcontrol portname vlan power/], }; diff --git a/Netdisco/lib/App/Netdisco/Daemon/Worker/Manager.pm b/Netdisco/lib/App/Netdisco/Daemon/Worker/Manager.pm index 047196f2..0087d149 100644 --- a/Netdisco/lib/App/Netdisco/Daemon/Worker/Manager.pm +++ b/Netdisco/lib/App/Netdisco/Daemon/Worker/Manager.pm @@ -13,7 +13,7 @@ my $fqdn = hostfqdn || 'localhost'; my $role_map = { (map {$_ => 'Poller'} - qw/discoverall discover arpwalk arpnip macwalk macsuck/), + qw/discoverall discover arpwalk arpnip nodenames macwalk macsuck/), (map {$_ => 'Interactive'} qw/location contact portcontrol portname vlan power/) }; diff --git a/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Arpnip.pm b/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Arpnip.pm index d511c1b4..26e47be2 100644 --- a/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Arpnip.pm +++ b/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Arpnip.pm @@ -1,9 +1,17 @@ package App::Netdisco::Daemon::Worker::Poller::Arpnip; +use Dancer::Plugin::DBIC 'schema'; + use App::Netdisco::Core::Arpnip 'do_arpnip'; -use App::Netdisco::Util::Device 'is_arpnipable'; +use App::Netdisco::Util::Device qw/get_device is_arpnipable can_nodenames/; + +use App::Netdisco::Core::Arpnip 'resolve_node_names'; +use App::Netdisco::Daemon::Util ':all'; + +use NetAddr::IP::Lite ':lower'; use Role::Tiny; +use Class::Method::Modifiers; use namespace::clean; with 'App::Netdisco::Daemon::Worker::Poller::Common'; @@ -15,4 +23,43 @@ sub arpnip_layer { 3 } sub arpwalk { (shift)->_walk_body('arpnip', @_) } sub arpnip { (shift)->_single_body('arpnip', @_) } +after 'arpnip' => sub { + my ($self, $job) = @_; + + my $host = NetAddr::IP::Lite->new($job->device); + my $device = get_device($host->addr); + my $jobqueue = schema('netdisco')->resultset('Admin'); + + schema('netdisco')->txn_do(sub { + $jobqueue->create({ + device => $device->ip, + action => 'nodenames', + status => 'queued', + username => $job->username, + userip => $job->userip, + }); + }); +}; + +# run a nodenames job for one device +sub nodenames { + my ($self, $job) = @_; + + my $host = NetAddr::IP::Lite->new($job->device); + my $device = get_device($host->addr); + my $jobqueue = schema('netdisco')->resultset('Admin'); + + if ($device->ip eq '0.0.0.0') { + return job_error("nodenames failed: no device param (need -d ?)"); + } + + unless (can_nodenames($device->ip)) { + return job_defer("nodenames deferred: cannot run for $host"); + } + + resolve_node_names($device); + + return job_done("Ended nodenames for ". $host->addr); +} + 1; diff --git a/Netdisco/lib/App/Netdisco/Manual/Configuration.pod b/Netdisco/lib/App/Netdisco/Manual/Configuration.pod index 591e19bb..906f0aa2 100644 --- a/Netdisco/lib/App/Netdisco/Manual/Configuration.pod +++ b/Netdisco/lib/App/Netdisco/Manual/Configuration.pod @@ -444,6 +444,22 @@ Value: Number. Default: 0. Sets the minimum amount of time in seconds which must elapse between any two arpnip jobs for a device. +=head3 C + +Value: List of Network Identifiers or Device Properties. Default: Empty List. + +Devices in the list will not have their Node IPs resolved to names using the +DNS. You can include hostnames, IP addresses and subnets (IPv4 or IPv6) in the +list. + +=head3 C + +Value: List of Network Identifiers or Device Properties. Default: Empty List. + +Only thos devices in the list will have their Node IPs resolved to names using +the DNS. You can include hostnames, IP addresses and subnets (IPv4 or IPv6) in +the list. + =head3 C Value: Boolean. Default: C. diff --git a/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod b/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod index 641723e4..41fe1254 100644 --- a/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod +++ b/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod @@ -35,15 +35,20 @@ but they are backwards compatible. =back -=head1 2.017001_001 +=head1 2.017001_002 =head2 General Notices The previous mentioned bug in Macsuck is now fixed. During Arpnip, Node IPs are no longer resolved to DNS hostnames in real-time. -In the next release, another job will be queued to perform this action for the -device. +Another job is queued to perform this action for the device. You can therefore +control using the new C and C config parameters +which daemons run this job. + +The idea here is to support sites where the SNMP polling node has no useful +DNS, but another system can update the DNS entries for nodes (yet do no +polling). =head1 2.017000 diff --git a/Netdisco/lib/App/Netdisco/Util/Device.pm b/Netdisco/lib/App/Netdisco/Util/Device.pm index 720aa783..b3d01b65 100644 --- a/Netdisco/lib/App/Netdisco/Util/Device.pm +++ b/Netdisco/lib/App/Netdisco/Util/Device.pm @@ -12,6 +12,7 @@ our @EXPORT_OK = qw/ check_no is_discoverable is_arpnipable + can_nodenames is_macsuckable /; our %EXPORT_TAGS = (all => \@EXPORT_OK); @@ -195,6 +196,32 @@ sub is_arpnipable { return 1; } +=head2 can_nodenames( $ip ) + +Given an IP address, returns C if Netdisco on this host is permitted by +the local configuration to resolve Node IPs to DNS names for the device. + +The configuration items C and C are checked +against the given IP. + +Returns false if the host is not permitted to do this job for the target +device. + +=cut + +sub can_nodenames { + my $ip = shift; + my $device = get_device($ip) or return 0; + + return _bail_msg("can_nodenames device matched nodenames_no") + if check_no($device, 'nodenames_no'); + + return _bail_msg("can_nodenames: device failed to match nodenames_only") + if check_no($device, 'nodenames_only'); + + return 1; +} + =head2 is_macsuckable( $ip ) Given an IP address, returns C if Netdisco on this host is permitted by diff --git a/Netdisco/share/config.yml b/Netdisco/share/config.yml index 3b753507..f8a366e8 100644 --- a/Netdisco/share/config.yml +++ b/Netdisco/share/config.yml @@ -86,6 +86,8 @@ macsuck_min_age: 0 arpnip_no: [] arpnip_only: [] arpnip_min_age: 0 +nodenames_no: [] +nodenames_only: [] store_wireless_clients: true store_modules: true ignore_interfaces: