From a94b5a913df4f1762bf57cb26d9edd6a7028fccf Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Sun, 24 Feb 2013 23:15:49 +0000 Subject: [PATCH] avoid use of DNS when looking up devices in DB by IP --- .../lib/App/Netdisco/DB/ResultSet/Device.pm | 43 ++++++++++++++++--- .../lib/App/Netdisco/DB/ResultSet/NodeIp.pm | 4 +- .../lib/App/Netdisco/Util/DeviceProperties.pm | 13 +++--- Netdisco/lib/App/Netdisco/Web/Device.pm | 2 - .../Netdisco/Web/Plugin/Device/Addresses.pm | 11 +++-- .../App/Netdisco/Web/Plugin/Device/Details.pm | 9 +--- .../Netdisco/Web/Plugin/Device/Neighbors.pm | 10 ++--- .../App/Netdisco/Web/Plugin/Device/Ports.pm | 34 +++++++-------- Netdisco/lib/App/Netdisco/Web/Search.pm | 2 - Netdisco/share/views/ajax/device/netmap.tt | 2 +- Netdisco/share/views/ajax/device/ports.tt | 2 +- 11 files changed, 78 insertions(+), 54 deletions(-) diff --git a/Netdisco/lib/App/Netdisco/DB/ResultSet/Device.pm b/Netdisco/lib/App/Netdisco/DB/ResultSet/Device.pm index fdd2f022..8841f172 100644 --- a/Netdisco/lib/App/Netdisco/DB/ResultSet/Device.pm +++ b/Netdisco/lib/App/Netdisco/DB/ResultSet/Device.pm @@ -43,21 +43,26 @@ sub with_times { }); } -=head2 search_aliases( $name or $ip or $prefix ) +=head2 search_aliases( {$name or $ip or $prefix}, \%options? ) Tries to find devices in Netdisco which have an identity corresponding to -C<$name>, C<$ip> or C<$prefix>. The name can be partial, in which case an -automatic case-insensitive partial-match search is performed. +C<$name>, C<$ip> or C<$prefix>. The search is across all aliases of the device, as well as its "root IP" identity. Note that this search will try B to use DNS, in case the current name for an IP does not correspond to the data within Netdisco. +Passing a zero value to the C key of the C hashref will +prevent partial matching of a host name. Otherwise the default is to perform +a partial, case-insensitive search on the host name fields. + =cut sub search_aliases { - my ($rs, $q) = @_; + my ($rs, $q, $options) = @_; $q ||= '255.255.255.255'; # hack to return empty resultset on error + $options ||= {}; + $options->{partial} = 1 if !defined $options->{partial}; # rough approximation of IP addresses (v4 in v6 not supported). # this helps us avoid triggering any DNS. @@ -72,8 +77,9 @@ sub search_aliases { ]; } else { - $q = "\%$q\%" if $q !~ m/\%/; + $q = "\%$q\%" if ($options->{partial} and $q !~ m/\%/); $clause = [ + 'me.name' => { '-ilike' => $q }, 'me.dns' => { '-ilike' => $q }, 'device_ips.dns' => { '-ilike' => $q }, ]; @@ -91,6 +97,33 @@ sub search_aliases { ); } +=head2 search_for_device( $name or $ip or $prefix ) + +This is a wrapper for C which: + +=over 4 + +=item * + +Disables partial matching on host names + +=item * + +Returns only the first result of any found devices + +=back + +If not matching devices are found, C is returned. + +=cut + +sub search_for_device { + my ($rs, $q, $options) = @_; + $options ||= {}; + $options->{partial} = 0; + return $rs->search_aliases($q, $options)->first(); +} + =head2 search_by_field( \%cond, \%attrs? ) This variant of the standard C method returns a ResultSet of Device diff --git a/Netdisco/lib/App/Netdisco/DB/ResultSet/NodeIp.pm b/Netdisco/lib/App/Netdisco/DB/ResultSet/NodeIp.pm index 6f6cde14..4a652e72 100644 --- a/Netdisco/lib/App/Netdisco/DB/ResultSet/NodeIp.pm +++ b/Netdisco/lib/App/Netdisco/DB/ResultSet/NodeIp.pm @@ -27,8 +27,8 @@ NodeIp table. The C parameter must be a hashref containing a key C with the value to search for. Value can either be a simple string of IPv4 or IPv6, or a -NetAddr::IP object in which case all results within the CIDR/Prefix will be -retrieved. +L object in which case all results within the CIDR/Prefix +will be retrieved. =item * diff --git a/Netdisco/lib/App/Netdisco/Util/DeviceProperties.pm b/Netdisco/lib/App/Netdisco/Util/DeviceProperties.pm index 143d133e..b696dd17 100644 --- a/Netdisco/lib/App/Netdisco/Util/DeviceProperties.pm +++ b/Netdisco/lib/App/Netdisco/Util/DeviceProperties.pm @@ -3,7 +3,7 @@ package App::Netdisco::Util::DeviceProperties; use Dancer qw/:syntax :script/; use Dancer::Plugin::DBIC 'schema'; -use NetAddr::IP::Lite; +use NetAddr::IP::Lite ':lower'; use base 'Exporter'; our @EXPORT = (); @@ -38,16 +38,19 @@ Returns false if the host is not permitted to discover the target device. =cut sub is_discoverable { - my $ip = shift; + my $q = shift; + + my $device = schema('netdisco')->resultset('Device') + ->search_for_device($q) or return 0; + my $addr = NetAddr::IP::Lite->new($device->ip); - my $device = NetAddr::IP::Lite->new($ip) or return 0; my $discover_no = setting('discover_no') || []; my $discover_only = setting('discover_only') || []; if (scalar @$discover_no) { foreach my $item (@$discover_no) { my $ip = NetAddr::IP::Lite->new($item) or return 0; - return 0 if $ip->contains($device); + return 0 if $ip->contains($addr); } } @@ -55,7 +58,7 @@ sub is_discoverable { my $okay = 0; foreach my $item (@$discover_only) { my $ip = NetAddr::IP::Lite->new($item) or return 0; - ++$okay if $ip->contains($device); + ++$okay if $ip->contains($addr); } return 0 if not $okay; } diff --git a/Netdisco/lib/App/Netdisco/Web/Device.pm b/Netdisco/lib/App/Netdisco/Web/Device.pm index b784bcfe..3abf7281 100644 --- a/Netdisco/lib/App/Netdisco/Web/Device.pm +++ b/Netdisco/lib/App/Netdisco/Web/Device.pm @@ -4,8 +4,6 @@ use Dancer ':syntax'; use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; -use NetAddr::IP::Lite ':lower'; - hook 'before' => sub { # list of port detail columns var('port_columns' => [ diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Addresses.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Addresses.pm index c18a79af..e3a10cf8 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Addresses.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Addresses.pm @@ -4,19 +4,18 @@ use Dancer ':syntax'; use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; -use NetAddr::IP::Lite ':lower'; - use App::Netdisco::Web::Plugin; register_device_tab({ id => 'addresses', label => 'Addresses' }); # device interface addresses ajax '/ajax/content/device/addresses' => sub { - my $ip = NetAddr::IP::Lite->new(param('q')); - return unless $ip; + my $q = param('q'); - my $set = schema('netdisco')->resultset('DeviceIp') - ->search({ip => $ip->addr}, {order_by => 'alias'}); + my $device = schema('netdisco')->resultset('Device') + ->search_for_device($q) or return; + + my $set = $device->device_ips->search({}, {order_by => 'alias'}); return unless $set->count; content_type('text/html'); diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Details.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Details.pm index d2303b36..f9959274 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Details.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Details.pm @@ -4,20 +4,15 @@ use Dancer ':syntax'; use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; -use NetAddr::IP::Lite ':lower'; - use App::Netdisco::Web::Plugin; register_device_tab({ id => 'details', label => 'Details' }); # device details table ajax '/ajax/content/device/details' => sub { - my $ip = NetAddr::IP::Lite->new(param('q')); - return unless $ip; - + my $q = param('q'); my $device = schema('netdisco')->resultset('Device') - ->with_times()->find($ip->addr); - return unless $device; + ->with_times()->search_for_device($q) or return; content_type('text/html'); template 'ajax/device/details.tt', { diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm index 33a184b8..ea1d0d22 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm @@ -4,8 +4,6 @@ use Dancer ':syntax'; use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; -use NetAddr::IP::Lite ':lower'; - use App::Netdisco::Web::Plugin; register_device_tab({ id => 'netmap', label => 'Neighbors' }); @@ -42,9 +40,11 @@ sub _add_children { # d3 seems not to use proper ajax semantics, so get instead of ajax get '/ajax/data/device/netmap' => sub { - my $ip = NetAddr::IP::Lite->new(param('q')); - return unless $ip; - my $start = $ip->addr; + my $q = param('q'); + + my $device = schema('netdisco')->resultset('Device') + ->search_for_device($q) or return; + my $start = $device->ip; my @devices = schema('netdisco')->resultset('Device')->search({}, { result_class => 'DBIx::Class::ResultClass::HashRefInflator', diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Ports.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Ports.pm index 92baeb15..b04b6275 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Ports.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Ports.pm @@ -4,43 +4,41 @@ use Dancer ':syntax'; use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; -use NetAddr::IP::Lite ':lower'; use App::Netdisco::Util::Web (); # for sort_port - use App::Netdisco::Web::Plugin; register_device_tab({ id => 'ports', label => 'Ports' }); # device ports with a description (er, name) matching ajax '/ajax/content/device/ports' => sub { - my $ip = NetAddr::IP::Lite->new(param('q')); - return unless $ip; + my $q = param('q'); - my $set = schema('netdisco')->resultset('DevicePort') - ->search({'me.ip' => $ip->addr}); + my $device = schema('netdisco')->resultset('Device') + ->search_for_device($q) or return; + my $set = $device->ports; # refine by ports if requested - my $q = param('f'); - if ($q) { - if ($q =~ m/^\d+$/) { + my $f = param('f'); + if ($f) { + if ($f =~ m/^\d+$/) { $set = $set->search({ -or => { - 'me.vlan' => $q, - 'port_vlans_tagged.vlan' => $q, + 'me.vlan' => $f, + 'port_vlans_tagged.vlan' => $f, }, }, { join => 'port_vlans_tagged' }); return unless $set->count; } else { - $q =~ s/\*/%/g if index($q, '*') >= 0; - $q =~ s/\?/_/g if index($q, '?') >= 0; - $q = { '-ilike' => $q }; + $f =~ s/\*/%/g if index($f, '*') >= 0; + $f =~ s/\?/_/g if index($f, '?') >= 0; + $f = { '-ilike' => $f }; - if ($set->search({'me.port' => $q})->count) { - $set = $set->search({'me.port' => $q}); + if ($set->search({'me.port' => $f})->count) { + $set = $set->search({'me.port' => $f}); } else { - $set = $set->search({'me.name' => $q}); + $set = $set->search({'me.name' => $f}); return unless $set->count; } } @@ -79,7 +77,7 @@ ajax '/ajax/content/device/ports' => sub { template 'ajax/device/ports.tt', { results => $results, nodes => $nodes_name, - device => $ip->addr, + device => $device->ip, }, { layout => undef }; }; diff --git a/Netdisco/lib/App/Netdisco/Web/Search.pm b/Netdisco/lib/App/Netdisco/Web/Search.pm index 639b74e1..9976daa8 100644 --- a/Netdisco/lib/App/Netdisco/Web/Search.pm +++ b/Netdisco/lib/App/Netdisco/Web/Search.pm @@ -4,8 +4,6 @@ use Dancer ':syntax'; use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; -use NetAddr::IP::Lite ':lower'; - hook 'before' => sub { # view settings for node options var('node_options' => [ diff --git a/Netdisco/share/views/ajax/device/netmap.tt b/Netdisco/share/views/ajax/device/netmap.tt index c56b9c4b..82904250 100644 --- a/Netdisco/share/views/ajax/device/netmap.tt +++ b/Netdisco/share/views/ajax/device/netmap.tt @@ -30,7 +30,7 @@ var svg = d3.select("#netmap_pane").append("svg") .attr("transform", "translate(" + winHeight / 2 + "," + winHeight / 2 + ")"); // this is the image background -// FIXME there must be a way to discover the radial tree's size? +// XXX there must be a way to discover the radial tree's size? svg.append('rect') .attr("x", (0 - (winHeight * 2))) .attr('width', "400%") diff --git a/Netdisco/share/views/ajax/device/ports.tt b/Netdisco/share/views/ajax/device/ports.tt index 40941c09..fb6a27ee 100644 --- a/Netdisco/share/views/ajax/device/ports.tt +++ b/Netdisco/share/views/ajax/device/ports.tt @@ -122,7 +122,7 @@ '' _ vlan.vlan _ '' %] [% SET output = output _ ', ' IF NOT loop.last %] [% END %] - [% IF row.tagged_vlans_count > 10 %] [%# FIXME make this a settable variable %] + [% IF row.tagged_vlans_count > 10 %] [%# TODO make this a settable variable %] [% SET output = '
(' _ row.tagged_vlans_count _ ')