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
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<not> 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<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
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<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? )
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
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<NetAddr::IP::Lite> object in which case all results within the CIDR/Prefix
will be retrieved.
=item *

View File

@@ -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;
}

View File

@@ -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' => [

View File

@@ -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');

View File

@@ -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', {

View File

@@ -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',

View File

@@ -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 };
};

View File

@@ -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' => [

View File

@@ -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%")

View File

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