Files
netdisco/lib/App/Netdisco/DB/ResultSet/NodeIp.pm

261 lines
5.9 KiB
Perl

package App::Netdisco::DB::ResultSet::NodeIp;
use base 'App::Netdisco::DB::ResultSet';
use strict;
use warnings;
__PACKAGE__->load_components(qw/
+App::Netdisco::DB::ExplicitLocking
/);
my $order_by_time_last_and_join_oui = {
order_by => {'-desc' => 'time_last'},
'+columns' => [
'oui.company',
'oui.abbrev',
{ time_first_stamp => \"to_char(time_first, 'YYYY-MM-DD HH24:MI')" },
{ time_last_stamp => \"to_char(time_last, 'YYYY-MM-DD HH24:MI')" },
],
join => 'oui'
};
=head1 with_times
This is a modifier for any C<search()> (including the helpers below) which
will add the following additional synthesized columns to the result set:
=over 4
=item time_first_stamp
=item time_last_stamp
=back
=cut
sub with_times {
my ($rs, $cond, $attrs) = @_;
return $rs
->search_rs({}, $order_by_time_last_and_join_oui)
->search($cond, $attrs);
}
=head1 search_by_ip( \%cond, \%attrs? )
my $set = $rs->search_by_ip({ip => '192.0.2.1', active => 1});
Like C<search()>, this returns a 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
L<NetAddr::IP::Lite> 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};
# 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;
}
$cond->{ip} = { $op => $ip };
return $rs
->search_rs({}, $order_by_time_last_and_join_oui)
->search($cond, $attrs);
}
=head1 search_by_dns( \%cond, \%attrs? )
my $set = $rs->search_by_dns({
dns => 'foo.example.com',
suffix => qr/(?:\.example\..com|\.local)$/,
active => 1
});
Like C<search()>, this returns a ResultSet of matching rows from the
NodeIp table.
=over 4
=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 *
If C<dns> is a plain string, then the C<cond> parameter may optionally have a
C<suffix> parameter which is a regular expression of domain names - one of
which must match the results.
=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 "dns field required for search_by_dns\n"
if ref {} ne ref $cond or !exists $cond->{dns};
my $dns_field = delete $cond->{dns};
(my $suffix = ($cond->{suffix} || ''))
=~ s|\Q(?^\E[-xismu]*|(?|g;
if (q{} eq ref $dns_field and exists $cond->{suffix}) {
(my $stripped_dns_field = $dns_field) =~ s/\.\%$//;
(my $fqdn_field = $stripped_dns_field) .= '%';
$stripped_dns_field =~ s/$cond->{suffix}$// if $cond->{suffix};
$stripped_dns_field .= '.%';
$cond->{dns} = [ -or =>
[ -and =>
{ '-ilike' => $stripped_dns_field },
{ '~*' => "***:$suffix" },
],
[ -and =>
{ '-ilike' => $dns_field },
{ '~*' => "***:$suffix" },
],
{ '-ilike' => $fqdn_field },
];
}
elsif (q{} ne ref $dns_field) {
$cond->{dns} = $dns_field;
}
else {
$cond->{dns} = { '-ilike' => $dns_field };
}
delete $cond->{suffix};
return $rs
->search_rs({}, $order_by_time_last_and_join_oui)
->search($cond, $attrs);
}
=head1 search_by_mac( \%cond, \%attrs? )
my $set = $rs->search_by_mac({mac => '00:11:22:33:44:55', active => 1});
Like C<search()>, this returns a ResultSet of matching rows from the
NodeIp table.
=over 4
=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};
return $rs
->search_rs({}, $order_by_time_last_and_join_oui)
->search($cond, $attrs);
}
=head2 ip_version( $version )
my $rset = $rs->ip_version(4);
This predefined C<search()> returns a ResultSet of matching rows from the
NodeIp table of nodes with addresses of the supplied IP version.
=over 4
=item *
The C<version> parameter must be an integer either 4 or 6.
=back
=cut
sub ip_version {
my ( $rs, $version ) = @_;
die "ip_version input must be either 4 or 6\n"
unless $version && ( $version == 4 || $version == 6 );
return $rs->search_rs( \[ 'family(me.ip) = ?', $version ] );
}
1;