update Node and NodeIp Result/ResultSet to have smarter value-add subs
This commit is contained in:
@@ -50,10 +50,20 @@ __PACKAGE__->set_primary_key("mac", "switch", "port");
|
|||||||
|
|
||||||
__PACKAGE__->belongs_to( device => 'Netdisco::DB::Result::Device',
|
__PACKAGE__->belongs_to( device => 'Netdisco::DB::Result::Device',
|
||||||
{ 'foreign.ip' => 'self.switch' }, { join_type => 'LEFT' } );
|
{ 'foreign.ip' => 'self.switch' }, { join_type => 'LEFT' } );
|
||||||
|
|
||||||
|
# device port may have been deleted (reconfigured modules?) but node remains
|
||||||
__PACKAGE__->belongs_to( device_port => 'Netdisco::DB::Result::DevicePort',
|
__PACKAGE__->belongs_to( device_port => 'Netdisco::DB::Result::DevicePort',
|
||||||
{ 'foreign.ip' => 'self.switch', 'foreign.port' => 'self.port' }, { join_type => 'LEFT' } );
|
{ 'foreign.ip' => 'self.switch', 'foreign.port' => 'self.port' },
|
||||||
|
{ join_type => 'LEFT' }
|
||||||
|
);
|
||||||
|
|
||||||
__PACKAGE__->has_many( ips => 'Netdisco::DB::Result::NodeIp',
|
__PACKAGE__->has_many( ips => 'Netdisco::DB::Result::NodeIp',
|
||||||
{ 'foreign.mac' => 'self.mac', 'foreign.active' => 'self.active' } );
|
{ 'foreign.mac' => 'self.mac', 'foreign.active' => 'self.active' } );
|
||||||
|
|
||||||
__PACKAGE__->belongs_to( oui => 'Netdisco::DB::Result::Oui', 'oui' );
|
__PACKAGE__->belongs_to( oui => 'Netdisco::DB::Result::Oui', 'oui' );
|
||||||
|
|
||||||
|
# accessors for custom formatted columns
|
||||||
|
sub time_first_stamp { return (shift)->get_column('time_first_stamp') }
|
||||||
|
sub time_last_stamp { return (shift)->get_column('time_last_stamp') }
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -4,25 +4,62 @@ use base 'DBIx::Class::ResultSet';
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings FATAL => 'all';
|
use warnings FATAL => 'all';
|
||||||
|
|
||||||
sub by_mac {
|
=head1 search_by_mac( \%cond, \%attrs? )
|
||||||
my ($set, $archive, $mac) = @_;
|
|
||||||
return $set unless $mac;
|
|
||||||
|
|
||||||
return $set->search(
|
my $set = $rs->search_by_mac({mac => '00:11:22:33:44:55', active => 1});
|
||||||
{
|
|
||||||
'me.mac' => $mac,
|
Like C<search()>, this returns a C<$resultset> of matching rows from the Node
|
||||||
($archive ? () : (active => 1)),
|
table.
|
||||||
},
|
|
||||||
{
|
=over 4
|
||||||
order_by => {'-desc' => 'time_last'},
|
|
||||||
columns => [qw/ mac switch port oui active device.dns /],
|
=item *
|
||||||
'+select' => [
|
|
||||||
\"to_char(time_first, 'YYYY-MM-DD HH24:MI')",
|
The C<cond> parameter must be a hashref containing a key C<mac> with
|
||||||
\"to_char(time_last, 'YYYY-MM-DD HH24:MI')",
|
the value to search for.
|
||||||
],
|
|
||||||
'+as' => [qw/ time_first time_last /],
|
=item *
|
||||||
join => 'device',
|
|
||||||
},
|
Results are ordered by time last seen.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Additional columns C<time_first_stamp> and C<time_last_stamp> provide
|
||||||
|
preformatted timestamps of the C<time_first> and C<time_last> fields.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
A JOIN is performed on the Device table and the Device C<dns> column
|
||||||
|
prefetched.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
To limit results only to active nodes, set C<< {active => 1} >> in C<cond>.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub search_by_mac {
|
||||||
|
my ($rs, $cond, $attrs) = @_;
|
||||||
|
|
||||||
|
die "mac address required for search_by_mac\n"
|
||||||
|
if ref {} ne ref $cond or !exists $cond->{mac};
|
||||||
|
|
||||||
|
$cond->{'me.mac'} = delete $cond->{mac};
|
||||||
|
$attrs ||= {};
|
||||||
|
|
||||||
|
return $rs
|
||||||
|
->search_rs($cond, %$attrs)
|
||||||
|
->search({},
|
||||||
|
{
|
||||||
|
order_by => {'-desc' => 'time_last'},
|
||||||
|
'+columns' => [qw/ device.dns /],
|
||||||
|
'+select' => [
|
||||||
|
\"to_char(time_first, 'YYYY-MM-DD HH24:MI')",
|
||||||
|
\"to_char(time_last, 'YYYY-MM-DD HH24:MI')",
|
||||||
|
],
|
||||||
|
'+as' => [qw/ time_first_stamp time_last_stamp /],
|
||||||
|
join => 'device',
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,69 +13,176 @@ sub has_dns_col {
|
|||||||
|
|
||||||
my $search_attr = {
|
my $search_attr = {
|
||||||
order_by => {'-desc' => 'time_last'},
|
order_by => {'-desc' => 'time_last'},
|
||||||
columns => [qw/ mac ip active oui.company /],
|
'+columns' => [qw/ oui.company /],
|
||||||
'+select' => [
|
'+select' => [
|
||||||
\"to_char(time_first, 'YYYY-MM-DD HH24:MI')",
|
\"to_char(time_first, 'YYYY-MM-DD HH24:MI')",
|
||||||
\"to_char(time_last, 'YYYY-MM-DD HH24:MI')",
|
\"to_char(time_last, 'YYYY-MM-DD HH24:MI')",
|
||||||
],
|
],
|
||||||
'+as' => [qw/ time_first time_last /],
|
'+as' => [qw/ time_first_stamp time_last_stamp /],
|
||||||
join => 'oui'
|
join => 'oui'
|
||||||
};
|
};
|
||||||
|
|
||||||
sub by_ip {
|
=head1 search_by_ip( \%cond, \%attrs? )
|
||||||
my ($set, $archive, $ip) = @_;
|
|
||||||
return $set unless $ip;
|
|
||||||
|
|
||||||
my $op = '=';
|
my $set = $rs->search_by_ip({ip => '123.123.123.123', active => 1});
|
||||||
if ('NetAddr::IP::Lite' eq ref $ip) {
|
|
||||||
$op = '<<=' if $ip->num > 1;
|
Like C<search()>, this returns a C<$resultset> of matching rows from the
|
||||||
|
NodeIp table.
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Results are ordered by time last seen.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Additional columns C<time_first_stamp> and C<time_last_stamp> provide
|
||||||
|
preformatted timestamps of the C<time_first> and C<time_last> fields.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
A JOIN is performed on the OUI table and the OUI C<company> column prefetched.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
To limit results only to active IPs, set C<< {active => 1} >> in C<cond>.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub search_by_ip {
|
||||||
|
my ($rs, $cond, $attrs) = @_;
|
||||||
|
|
||||||
|
die "ip address required for search_by_ip\n"
|
||||||
|
if ref {} ne ref $cond or !exists $cond->{ip};
|
||||||
|
$attrs ||= {};
|
||||||
|
|
||||||
|
# handle either plain text IP or NetAddr::IP (/32 or CIDR)
|
||||||
|
my ($op, $ip) = ('=', delete $cond->{ip});
|
||||||
|
|
||||||
|
if ('NetAddr::IP::Lite' eq ref $ip and $ip->num > 1) {
|
||||||
|
$op = '<<=';
|
||||||
$ip = $ip->cidr;
|
$ip = $ip->cidr;
|
||||||
}
|
}
|
||||||
|
$cond->{ip} = { $op => $ip };
|
||||||
|
|
||||||
return $set->search(
|
$rs = $rs->search_rs({}, {'+columns' => 'dns'})
|
||||||
{
|
if $rs->has_dns_col;
|
||||||
ip => { $op => $ip },
|
|
||||||
($archive ? () : (active => 1)),
|
return $rs
|
||||||
},
|
->search_rs($cond, %$attrs)
|
||||||
{
|
->search({}, $search_attr);
|
||||||
%$search_attr,
|
|
||||||
( $set->has_dns_col ? ('+columns' => 'dns') : () ),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub by_name {
|
=head1 search_by_name( \%cond, \%attrs? )
|
||||||
my ($set, $archive, $name) = @_;
|
|
||||||
return $set unless $name;
|
|
||||||
die "do not call by_name unless you have a dns col on the node_ip table."
|
|
||||||
if not $set->has_dns_col;
|
|
||||||
|
|
||||||
return $set->search(
|
my $set = $rs->search_by_name({dns => 'foo.example.com', active => 1});
|
||||||
{
|
|
||||||
dns => { '-ilike' => $name },
|
Like C<search()>, this returns a C<$resultset> of matching rows from the
|
||||||
($archive ? () : (active => 1)),
|
NodeIp table.
|
||||||
},
|
|
||||||
{
|
=over 4
|
||||||
%$search_attr,
|
|
||||||
'+columns' => 'dns',
|
=item *
|
||||||
}
|
|
||||||
);
|
The NodeIp table must have a C<dns> column for this search to work. Typically
|
||||||
|
this column is the IP's DNS PTR record, cached at the time of Netdisco Arpnip.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
The C<cond> parameter must be a hashref containing a key C<dns> with the value
|
||||||
|
to search for. The value may optionally include SQL wildcard characters.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Results are ordered by time last seen.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Additional columns C<time_first_stamp> and C<time_last_stamp> provide
|
||||||
|
preformatted timestamps of the C<time_first> and C<time_last> fields.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
A JOIN is performed on the OUI table and the OUI C<company> column prefetched.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
To limit results only to active IPs, set C<< {active => 1} >> in C<cond>.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub search_by_dns {
|
||||||
|
my ($rs, $cond, $attrs) = @_;
|
||||||
|
|
||||||
|
die "search_by_dns requires a dns col on the node_ip table.\n"
|
||||||
|
if not $rs->has_dns_col;
|
||||||
|
|
||||||
|
die "dns field required for search_by_dns\n"
|
||||||
|
if ref {} ne ref $cond or !exists $cond->{dns};
|
||||||
|
|
||||||
|
$cond->{dns} = { '-ilike' => delete $cond->{dns} };
|
||||||
|
$attrs ||= {};
|
||||||
|
|
||||||
|
return $rs
|
||||||
|
->search_rs($cond, %$attrs)
|
||||||
|
->search_rs({}, {'+columns' => 'dns'})
|
||||||
|
->search({}, $search_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub by_mac {
|
=head1 search_by_mac( \%cond, \%attrs? )
|
||||||
my ($set, $archive, $mac) = @_;
|
|
||||||
return $set unless $mac;
|
|
||||||
|
|
||||||
return $set->search(
|
my $set = $rs->search_by_mac({mac => '00:11:22:33:44:55', active => 1});
|
||||||
{
|
|
||||||
mac => $mac,
|
Like C<search()>, this returns a C<$resultset> of matching rows from the
|
||||||
($archive ? () : (active => 1)),
|
NodeIp table.
|
||||||
},
|
|
||||||
{
|
=over 4
|
||||||
%$search_attr,
|
|
||||||
( $set->has_dns_col ? ('+columns' => 'dns') : () ),
|
=item *
|
||||||
}
|
|
||||||
);
|
The C<cond> parameter must be a hashref containing a key C<mac> with the value
|
||||||
|
to search for.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Results are ordered by time last seen.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Additional columns C<time_first_stamp> and C<time_last_stamp> provide
|
||||||
|
preformatted timestamps of the C<time_first> and C<time_last> fields.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
A JOIN is performed on the OUI table and the OUI C<company> column prefetched.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
To limit results only to active IPs, set C<< {active => 1} >> in C<cond>.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub search_by_mac {
|
||||||
|
my ($rs, $cond, $attrs) = @_;
|
||||||
|
|
||||||
|
die "mac address required for search_by_mac\n"
|
||||||
|
if ref {} ne ref $cond or !exists $cond->{mac};
|
||||||
|
$attrs ||= {};
|
||||||
|
|
||||||
|
$rs = $rs->search_rs({}, {'+columns' => 'dns'})
|
||||||
|
if $rs->has_dns_col;
|
||||||
|
|
||||||
|
return $rs
|
||||||
|
->search_rs($cond, %$attrs)
|
||||||
|
->search({}, $search_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -65,13 +65,15 @@ ajax '/ajax/content/search/node' => sub {
|
|||||||
content_type('text/html');
|
content_type('text/html');
|
||||||
|
|
||||||
my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0);
|
my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0);
|
||||||
|
my @active = (param('archived') ? () : (active => 1));
|
||||||
|
|
||||||
if (eval { $mac->as_IEEE }) {
|
if (eval { $mac->as_IEEE }) {
|
||||||
|
|
||||||
my $sightings = schema('netdisco')->resultset('Node')
|
my $sightings = schema('netdisco')->resultset('Node')
|
||||||
->by_mac(param('archived'), $mac->as_IEEE);
|
->search_by_mac({mac => $mac->as_IEEE, @active});
|
||||||
|
|
||||||
my $ips = schema('netdisco')->resultset('NodeIp')
|
my $ips = schema('netdisco')->resultset('NodeIp')
|
||||||
->by_mac(param('archived'), $mac->as_IEEE);
|
->search_by_mac({mac => $mac->as_IEEE, @active});
|
||||||
|
|
||||||
my $ports = schema('netdisco')->resultset('DevicePort')
|
my $ports = schema('netdisco')->resultset('DevicePort')
|
||||||
->by_mac($mac->as_IEEE);
|
->by_mac($mac->as_IEEE);
|
||||||
@@ -90,9 +92,9 @@ ajax '/ajax/content/search/node' => sub {
|
|||||||
my $set;
|
my $set;
|
||||||
|
|
||||||
if (my $ip = NetAddr::IP::Lite->new($node)) {
|
if (my $ip = NetAddr::IP::Lite->new($node)) {
|
||||||
# by_ip() will extract cidr notation if necessary
|
# search_by_ip() will extract cidr notation if necessary
|
||||||
$set = schema('netdisco')->resultset('NodeIp')
|
$set = schema('netdisco')->resultset('NodeIp')
|
||||||
->by_ip(param('archived'), $ip);
|
->search_by_ip({ip => $ip, @active});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (schema('netdisco')->resultset('NodeIp')->has_dns_col) {
|
if (schema('netdisco')->resultset('NodeIp')->has_dns_col) {
|
||||||
@@ -104,7 +106,7 @@ ajax '/ajax/content/search/node' => sub {
|
|||||||
if index($node, setting('domain_suffix')) == -1;
|
if index($node, setting('domain_suffix')) == -1;
|
||||||
}
|
}
|
||||||
$set = schema('netdisco')->resultset('NodeIp')
|
$set = schema('netdisco')->resultset('NodeIp')
|
||||||
->by_name(param('archived'), $node);
|
->search_by_dns({dns => $node, @active});
|
||||||
}
|
}
|
||||||
elsif (setting('domain_suffix')) {
|
elsif (setting('domain_suffix')) {
|
||||||
$node .= setting('domain_suffix')
|
$node .= setting('domain_suffix')
|
||||||
@@ -120,13 +122,16 @@ ajax '/ajax/content/search/node' => sub {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$set = schema('netdisco')->resultset('NodeIp')
|
$set = schema('netdisco')->resultset('NodeIp')
|
||||||
->by_ip(param('archived'), $node);
|
->search_by_ip({ip => $node, @active});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return unless $set and $set->count;
|
return unless $set and $set->count;
|
||||||
|
|
||||||
template 'ajax/search/node_by_ip.tt', {
|
template 'ajax/search/node_by_ip.tt', {
|
||||||
results => $set,
|
macs => $set,
|
||||||
|
# a callback for the templates, which
|
||||||
|
# allows modification of the DB query before execution
|
||||||
|
archive_filter => sub { (shift)->search({@active}) },
|
||||||
}, { layout => undef };
|
}, { layout => undef };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
</tbody>
|
</tbody>
|
||||||
[% WHILE (row = results.next) %]
|
[% WHILE (row = macs.next) %]
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="nd_linkcell"
|
<td><a class="nd_linkcell"
|
||||||
href="[% uri_for('/search') %]?[% vars.query_defaults.node %]&q=[% row.mac | uri %]">[% row.mac %]</a></td>
|
href="[% uri_for('/search') %]?[% vars.query_defaults.node %]&q=[% row.mac | uri %]">[% row.mac %]</a></td>
|
||||||
@@ -27,11 +27,11 @@
|
|||||||
[% ' <span class="label warning">a</span>' IF NOT row.active %]
|
[% ' <span class="label warning">a</span>' IF NOT row.active %]
|
||||||
</td>
|
</td>
|
||||||
[% IF params.stamps %]
|
[% IF params.stamps %]
|
||||||
<td>[% row.time_first %]</td>
|
<td>[% row.time_first_stamp %]</td>
|
||||||
<td>[% row.time_last %]</td>
|
<td>[% row.time_last_stamp %]</td>
|
||||||
[% END %]
|
[% END %]
|
||||||
</tr>
|
</tr>
|
||||||
[% FOREACH node IN row.node_sightings(params.archived) %]
|
[% FOREACH node IN archive_filter(row.node_sightings) %]
|
||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
[% IF params.vendor %]
|
[% IF params.vendor %]
|
||||||
@@ -43,12 +43,12 @@
|
|||||||
[% ' <span class="label warning">a</span>' IF NOT node.active %]
|
[% ' <span class="label warning">a</span>' IF NOT node.active %]
|
||||||
</td>
|
</td>
|
||||||
[% IF params.stamps %]
|
[% IF params.stamps %]
|
||||||
<td>[% node.time_first %]</td>
|
<td>[% node.time_first_stamp %]</td>
|
||||||
<td>[% node.time_last %]</td>
|
<td>[% node.time_last_stamp %]</td>
|
||||||
[% END %]
|
[% END %]
|
||||||
</tr>
|
</tr>
|
||||||
[% END %]
|
[% END %]
|
||||||
[% FOREACH nodeip IN row.ip_aliases(params.archived) %]
|
[% FOREACH nodeip IN archive_filter(row.ip_aliases) %]
|
||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
[% IF params.vendor %]
|
[% IF params.vendor %]
|
||||||
@@ -60,8 +60,8 @@
|
|||||||
[% ' <span class="label warning">a</span>' IF NOT nodeip.active %]
|
[% ' <span class="label warning">a</span>' IF NOT nodeip.active %]
|
||||||
</td>
|
</td>
|
||||||
[% IF params.stamps %]
|
[% IF params.stamps %]
|
||||||
<td>[% nodeip.time_first %]</td>
|
<td>[% nodeip.time_first_stamp %]</td>
|
||||||
<td>[% nodeip.time_last %]</td>
|
<td>[% nodeip.time_last_stamp %]</td>
|
||||||
[% END %]
|
[% END %]
|
||||||
</tr>
|
</tr>
|
||||||
[% END %]
|
[% END %]
|
||||||
|
|||||||
@@ -40,8 +40,8 @@
|
|||||||
[% ' <span class="label warning">a</span>' IF NOT row.active %]
|
[% ' <span class="label warning">a</span>' IF NOT row.active %]
|
||||||
</td>
|
</td>
|
||||||
[% IF params.stamps %]
|
[% IF params.stamps %]
|
||||||
<td>[% row.time_first %]</td>
|
<td>[% row.time_first_stamp %]</td>
|
||||||
<td>[% rw.time_last %]</td>
|
<td>[% rw.time_last_stamp %]</td>
|
||||||
[% END %]
|
[% END %]
|
||||||
</tr>
|
</tr>
|
||||||
[% SET first_row = 0 %]
|
[% SET first_row = 0 %]
|
||||||
@@ -71,8 +71,8 @@
|
|||||||
[% ' <span class="label warning">a</span>' IF NOT node.active %]
|
[% ' <span class="label warning">a</span>' IF NOT node.active %]
|
||||||
</td>
|
</td>
|
||||||
[% IF params.stamps %]
|
[% IF params.stamps %]
|
||||||
<td>[% node.time_first %]</td>
|
<td>[% node.time_first_stamp %]</td>
|
||||||
<td>[% node.time_last %]</td>
|
<td>[% node.time_last_stamp %]</td>
|
||||||
[% END %]
|
[% END %]
|
||||||
</tr>
|
</tr>
|
||||||
[% SET first_row = 0 %]
|
[% SET first_row = 0 %]
|
||||||
|
|||||||
Reference in New Issue
Block a user