avoid use of DNS when looking up devices in DB by IP

This commit is contained in:
Oliver Gorwits
2013-02-24 23:15:49 +00:00
parent 8a0311d4c5
commit a94b5a913d
11 changed files with 78 additions and 54 deletions

View File

@@ -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 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 C<$name>, C<$ip> or C<$prefix>.
automatic case-insensitive partial-match search is performed.
The search is across all aliases of the device, as well as its "root IP" The search is across all aliases of the device, as well as its "root IP"
identity. Note that this search will try B<not> to use DNS, in case the current identity. Note that this search will try B<not> to use DNS, in case the current
name for an IP does not correspond to the data within Netdisco. name for an IP does not correspond to the data within Netdisco.
Passing a zero value to the C<partial> key of the C<options> 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 =cut
sub search_aliases { sub search_aliases {
my ($rs, $q) = @_; my ($rs, $q, $options) = @_;
$q ||= '255.255.255.255'; # hack to return empty resultset on error $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). # rough approximation of IP addresses (v4 in v6 not supported).
# this helps us avoid triggering any DNS. # this helps us avoid triggering any DNS.
@@ -72,8 +77,9 @@ sub search_aliases {
]; ];
} }
else { else {
$q = "\%$q\%" if $q !~ m/\%/; $q = "\%$q\%" if ($options->{partial} and $q !~ m/\%/);
$clause = [ $clause = [
'me.name' => { '-ilike' => $q },
'me.dns' => { '-ilike' => $q }, 'me.dns' => { '-ilike' => $q },
'device_ips.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<search_aliases> 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<undef> 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? ) =head2 search_by_field( \%cond, \%attrs? )
This variant of the standard C<search()> method returns a ResultSet of Device This variant of the standard C<search()> method returns a ResultSet of Device

View File

@@ -27,8 +27,8 @@ NodeIp table.
The C<cond> parameter must be a hashref containing a key C<ip> with the value The C<cond> parameter must be a hashref containing a key C<ip> with the value
to search for. Value can either be a simple string of IPv4 or IPv6, or a 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 L<NetAddr::IP::Lite> object in which case all results within the CIDR/Prefix
retrieved. will be retrieved.
=item * =item *

View File

@@ -3,7 +3,7 @@ package App::Netdisco::Util::DeviceProperties;
use Dancer qw/:syntax :script/; use Dancer qw/:syntax :script/;
use Dancer::Plugin::DBIC 'schema'; use Dancer::Plugin::DBIC 'schema';
use NetAddr::IP::Lite; use NetAddr::IP::Lite ':lower';
use base 'Exporter'; use base 'Exporter';
our @EXPORT = (); our @EXPORT = ();
@@ -38,16 +38,19 @@ Returns false if the host is not permitted to discover the target device.
=cut =cut
sub is_discoverable { 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_no = setting('discover_no') || [];
my $discover_only = setting('discover_only') || []; my $discover_only = setting('discover_only') || [];
if (scalar @$discover_no) { if (scalar @$discover_no) {
foreach my $item (@$discover_no) { foreach my $item (@$discover_no) {
my $ip = NetAddr::IP::Lite->new($item) or return 0; 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; my $okay = 0;
foreach my $item (@$discover_only) { foreach my $item (@$discover_only) {
my $ip = NetAddr::IP::Lite->new($item) or return 0; 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; return 0 if not $okay;
} }

View File

@@ -4,8 +4,6 @@ use Dancer ':syntax';
use Dancer::Plugin::Ajax; use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC; use Dancer::Plugin::DBIC;
use NetAddr::IP::Lite ':lower';
hook 'before' => sub { hook 'before' => sub {
# list of port detail columns # list of port detail columns
var('port_columns' => [ var('port_columns' => [

View File

@@ -4,19 +4,18 @@ use Dancer ':syntax';
use Dancer::Plugin::Ajax; use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC; use Dancer::Plugin::DBIC;
use NetAddr::IP::Lite ':lower';
use App::Netdisco::Web::Plugin; use App::Netdisco::Web::Plugin;
register_device_tab({ id => 'addresses', label => 'Addresses' }); register_device_tab({ id => 'addresses', label => 'Addresses' });
# device interface addresses # device interface addresses
ajax '/ajax/content/device/addresses' => sub { ajax '/ajax/content/device/addresses' => sub {
my $ip = NetAddr::IP::Lite->new(param('q')); my $q = param('q');
return unless $ip;
my $set = schema('netdisco')->resultset('DeviceIp') my $device = schema('netdisco')->resultset('Device')
->search({ip => $ip->addr}, {order_by => 'alias'}); ->search_for_device($q) or return;
my $set = $device->device_ips->search({}, {order_by => 'alias'});
return unless $set->count; return unless $set->count;
content_type('text/html'); content_type('text/html');

View File

@@ -4,20 +4,15 @@ use Dancer ':syntax';
use Dancer::Plugin::Ajax; use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC; use Dancer::Plugin::DBIC;
use NetAddr::IP::Lite ':lower';
use App::Netdisco::Web::Plugin; use App::Netdisco::Web::Plugin;
register_device_tab({ id => 'details', label => 'Details' }); register_device_tab({ id => 'details', label => 'Details' });
# device details table # device details table
ajax '/ajax/content/device/details' => sub { ajax '/ajax/content/device/details' => sub {
my $ip = NetAddr::IP::Lite->new(param('q')); my $q = param('q');
return unless $ip;
my $device = schema('netdisco')->resultset('Device') my $device = schema('netdisco')->resultset('Device')
->with_times()->find($ip->addr); ->with_times()->search_for_device($q) or return;
return unless $device;
content_type('text/html'); content_type('text/html');
template 'ajax/device/details.tt', { template 'ajax/device/details.tt', {

View File

@@ -4,8 +4,6 @@ use Dancer ':syntax';
use Dancer::Plugin::Ajax; use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC; use Dancer::Plugin::DBIC;
use NetAddr::IP::Lite ':lower';
use App::Netdisco::Web::Plugin; use App::Netdisco::Web::Plugin;
register_device_tab({ id => 'netmap', label => 'Neighbors' }); 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 # d3 seems not to use proper ajax semantics, so get instead of ajax
get '/ajax/data/device/netmap' => sub { get '/ajax/data/device/netmap' => sub {
my $ip = NetAddr::IP::Lite->new(param('q')); my $q = param('q');
return unless $ip;
my $start = $ip->addr; my $device = schema('netdisco')->resultset('Device')
->search_for_device($q) or return;
my $start = $device->ip;
my @devices = schema('netdisco')->resultset('Device')->search({}, { my @devices = schema('netdisco')->resultset('Device')->search({}, {
result_class => 'DBIx::Class::ResultClass::HashRefInflator', result_class => 'DBIx::Class::ResultClass::HashRefInflator',

View File

@@ -4,43 +4,41 @@ use Dancer ':syntax';
use Dancer::Plugin::Ajax; use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC; use Dancer::Plugin::DBIC;
use NetAddr::IP::Lite ':lower';
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;
register_device_tab({ id => 'ports', label => 'Ports' }); register_device_tab({ id => 'ports', label => 'Ports' });
# device ports with a description (er, name) matching # device ports with a description (er, name) matching
ajax '/ajax/content/device/ports' => sub { ajax '/ajax/content/device/ports' => sub {
my $ip = NetAddr::IP::Lite->new(param('q')); my $q = param('q');
return unless $ip;
my $set = schema('netdisco')->resultset('DevicePort') my $device = schema('netdisco')->resultset('Device')
->search({'me.ip' => $ip->addr}); ->search_for_device($q) or return;
my $set = $device->ports;
# refine by ports if requested # refine by ports if requested
my $q = param('f'); my $f = param('f');
if ($q) { if ($f) {
if ($q =~ m/^\d+$/) { if ($f =~ m/^\d+$/) {
$set = $set->search({ $set = $set->search({
-or => { -or => {
'me.vlan' => $q, 'me.vlan' => $f,
'port_vlans_tagged.vlan' => $q, 'port_vlans_tagged.vlan' => $f,
}, },
}, { join => 'port_vlans_tagged' }); }, { join => 'port_vlans_tagged' });
return unless $set->count; return unless $set->count;
} }
else { else {
$q =~ s/\*/%/g if index($q, '*') >= 0; $f =~ s/\*/%/g if index($f, '*') >= 0;
$q =~ s/\?/_/g if index($q, '?') >= 0; $f =~ s/\?/_/g if index($f, '?') >= 0;
$q = { '-ilike' => $q }; $f = { '-ilike' => $f };
if ($set->search({'me.port' => $q})->count) { if ($set->search({'me.port' => $f})->count) {
$set = $set->search({'me.port' => $q}); $set = $set->search({'me.port' => $f});
} }
else { else {
$set = $set->search({'me.name' => $q}); $set = $set->search({'me.name' => $f});
return unless $set->count; return unless $set->count;
} }
} }
@@ -79,7 +77,7 @@ ajax '/ajax/content/device/ports' => sub {
template 'ajax/device/ports.tt', { template 'ajax/device/ports.tt', {
results => $results, results => $results,
nodes => $nodes_name, nodes => $nodes_name,
device => $ip->addr, device => $device->ip,
}, { layout => undef }; }, { layout => undef };
}; };

View File

@@ -4,8 +4,6 @@ use Dancer ':syntax';
use Dancer::Plugin::Ajax; use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC; use Dancer::Plugin::DBIC;
use NetAddr::IP::Lite ':lower';
hook 'before' => sub { hook 'before' => sub {
# view settings for node options # view settings for node options
var('node_options' => [ var('node_options' => [

View File

@@ -30,7 +30,7 @@ var svg = d3.select("#netmap_pane").append("svg")
.attr("transform", "translate(" + winHeight / 2 + "," + winHeight / 2 + ")"); .attr("transform", "translate(" + winHeight / 2 + "," + winHeight / 2 + ")");
// this is the image background // 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') svg.append('rect')
.attr("x", (0 - (winHeight * 2))) .attr("x", (0 - (winHeight * 2)))
.attr('width', "400%") .attr('width', "400%")

View File

@@ -122,7 +122,7 @@
'<a href="' _ uri_for('/search') _ '?tab=vlan&q=' _ vlan.vlan _ '">' _ vlan.vlan _ '</a>' %] '<a href="' _ uri_for('/search') _ '?tab=vlan&q=' _ vlan.vlan _ '">' _ vlan.vlan _ '</a>' %]
[% SET output = output _ ', ' IF NOT loop.last %] [% SET output = output _ ', ' IF NOT loop.last %]
[% END %] [% 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 = '<div class="vlan_total">(' _ row.tagged_vlans_count [% SET output = '<div class="vlan_total">(' _ row.tagged_vlans_count
_ ')</div><span class="nd_linkcell nd_collapse_vlans"> _ ')</div><span class="nd_linkcell nd_collapse_vlans">
<i class="cell-arrow-up-down icon-chevron-up icon-large"> <i class="cell-arrow-up-down icon-chevron-up icon-large">