relocate repo files so ND2 is the only code
This commit is contained in:
45
lib/App/Netdisco/DB/ResultSet/Admin.pm
Normal file
45
lib/App/Netdisco/DB/ResultSet/Admin.pm
Normal file
@@ -0,0 +1,45 @@
|
||||
package App::Netdisco::DB::ResultSet::Admin;
|
||||
use base 'App::Netdisco::DB::ResultSet';
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
__PACKAGE__->load_components(qw/
|
||||
+App::Netdisco::DB::ExplicitLocking
|
||||
/);
|
||||
|
||||
=head1 ADDITIONAL METHODS
|
||||
|
||||
=head2 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 entered_stamp
|
||||
|
||||
=item started_stamp
|
||||
|
||||
=item finished_stamp
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub with_times {
|
||||
my ($rs, $cond, $attrs) = @_;
|
||||
|
||||
return $rs
|
||||
->search_rs($cond, $attrs)
|
||||
->search({},
|
||||
{
|
||||
'+columns' => {
|
||||
entered_stamp => \"to_char(entered, 'YYYY-MM-DD HH24:MI')",
|
||||
started_stamp => \"to_char(started, 'YYYY-MM-DD HH24:MI')",
|
||||
finished_stamp => \"to_char(finished, 'YYYY-MM-DD HH24:MI')",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
612
lib/App/Netdisco/DB/ResultSet/Device.pm
Normal file
612
lib/App/Netdisco/DB/ResultSet/Device.pm
Normal file
@@ -0,0 +1,612 @@
|
||||
package App::Netdisco::DB::ResultSet::Device;
|
||||
use base 'App::Netdisco::DB::ResultSet';
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use NetAddr::IP::Lite ':lower';
|
||||
|
||||
=head1 ADDITIONAL METHODS
|
||||
|
||||
=head2 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 uptime_age
|
||||
|
||||
=item last_discover_stamp
|
||||
|
||||
=item last_macsuck_stamp
|
||||
|
||||
=item last_arpnip_stamp
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub with_times {
|
||||
my ($rs, $cond, $attrs) = @_;
|
||||
|
||||
return $rs
|
||||
->search_rs($cond, $attrs)
|
||||
->search({},
|
||||
{
|
||||
'+columns' => {
|
||||
uptime_age => \("replace(age(timestamp 'epoch' + uptime / 100 * interval '1 second', "
|
||||
."timestamp '1970-01-01 00:00:00-00')::text, 'mon', 'month')"),
|
||||
last_discover_stamp => \"to_char(last_discover, 'YYYY-MM-DD HH24:MI')",
|
||||
last_macsuck_stamp => \"to_char(last_macsuck, 'YYYY-MM-DD HH24:MI')",
|
||||
last_arpnip_stamp => \"to_char(last_arpnip, 'YYYY-MM-DD HH24:MI')",
|
||||
since_last_discover => \"extract(epoch from (age(now(), last_discover)))",
|
||||
since_last_macsuck => \"extract(epoch from (age(now(), last_macsuck)))",
|
||||
since_last_arpnip => \"extract(epoch from (age(now(), last_arpnip)))",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
=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 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, $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.
|
||||
my $by_ip = ($q =~ m{^(?:[.0-9/]+|[:0-9a-f/]+)$}i) ? 1 : 0;
|
||||
|
||||
my $clause;
|
||||
if ($by_ip) {
|
||||
my $ip = NetAddr::IP::Lite->new($q)
|
||||
or return undef; # could be a MAC address!
|
||||
$clause = [
|
||||
'me.ip' => { '<<=' => $ip->cidr },
|
||||
'device_ips.alias' => { '<<=' => $ip->cidr },
|
||||
];
|
||||
}
|
||||
else {
|
||||
$q = "\%$q\%" if ($options->{partial} and $q !~ m/\%/);
|
||||
$clause = [
|
||||
'me.name' => { '-ilike' => $q },
|
||||
'me.dns' => { '-ilike' => $q },
|
||||
'device_ips.dns' => { '-ilike' => $q },
|
||||
];
|
||||
}
|
||||
|
||||
return $rs->search(
|
||||
{
|
||||
-or => $clause,
|
||||
},
|
||||
{
|
||||
order_by => [qw/ me.dns me.ip /],
|
||||
join => 'device_ips',
|
||||
distinct => 1,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
=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
|
||||
entries. It is written to support web forms which accept fields that match and
|
||||
locate Devices in the database.
|
||||
|
||||
The hashref parameter should contain fields from the Device table which will
|
||||
be intelligently used in a search query.
|
||||
|
||||
In addition, you can provide the key C<matchall> which, given a True or False
|
||||
value, controls whether fields must all match or whether any can match, to
|
||||
select a row.
|
||||
|
||||
Supported keys:
|
||||
|
||||
=over 4
|
||||
|
||||
=item matchall
|
||||
|
||||
If a True value, fields must all match to return a given row of the Device
|
||||
table, otherwise any field matching will cause the row to be included in
|
||||
results.
|
||||
|
||||
=item name
|
||||
|
||||
Can match the C<name> field as a substring.
|
||||
|
||||
=item location
|
||||
|
||||
Can match the C<location> field as a substring.
|
||||
|
||||
=item description
|
||||
|
||||
Can match the C<description> field as a substring (usually this field contains
|
||||
a description of the vendor operating system).
|
||||
|
||||
=item model
|
||||
|
||||
Will match exactly the C<model> field.
|
||||
|
||||
=item os
|
||||
|
||||
Will match exactly the C<os> field, which is the operating sytem.
|
||||
|
||||
=item os_ver
|
||||
|
||||
Will match exactly the C<os_ver> field, which is the operating sytem software version.
|
||||
|
||||
=item vendor
|
||||
|
||||
Will match exactly the C<vendor> (manufacturer).
|
||||
|
||||
=item dns
|
||||
|
||||
Can match any of the Device IP address aliases as a substring.
|
||||
|
||||
=item ip
|
||||
|
||||
Can be a string IP or a NetAddr::IP object, either way being treated as an
|
||||
IPv4 or IPv6 prefix within which the device must have one IP address alias.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub search_by_field {
|
||||
my ($rs, $p, $attrs) = @_;
|
||||
|
||||
die "condition parameter to search_by_field must be hashref\n"
|
||||
if ref {} ne ref $p or 0 == scalar keys %$p;
|
||||
|
||||
my $op = $p->{matchall} ? '-and' : '-or';
|
||||
|
||||
# this is a bit of an inelegant trick to catch junk data entry,
|
||||
# whilst avoiding returning *all* entries in the table
|
||||
if ($p->{ip} and 'NetAddr::IP::Lite' ne ref $p->{ip}) {
|
||||
$p->{ip} = ( NetAddr::IP::Lite->new($p->{ip})
|
||||
|| NetAddr::IP::Lite->new('255.255.255.255') );
|
||||
}
|
||||
|
||||
# For Search on Layers
|
||||
my @layer_search = ( '_', '_', '_', '_', '_', '_', '_' );
|
||||
# @layer_search is computer indexed, left->right
|
||||
my $layers = $p->{layers};
|
||||
if ( defined $layers && ref $layers ) {
|
||||
foreach my $layer (@$layers) {
|
||||
next unless defined $layer and length($layer);
|
||||
next if ( $layer < 1 || $layer > 7 );
|
||||
$layer_search[ $layer - 1 ] = 1;
|
||||
}
|
||||
}
|
||||
elsif ( defined $layers ) {
|
||||
$layer_search[ $layers - 1 ] = 1;
|
||||
}
|
||||
# the database field is in order 87654321
|
||||
my $layer_string = join( '', reverse @layer_search );
|
||||
|
||||
return $rs
|
||||
->search_rs({}, $attrs)
|
||||
->search({
|
||||
$op => [
|
||||
($p->{name} ? ('me.name' =>
|
||||
{ '-ilike' => "\%$p->{name}\%" }) : ()),
|
||||
($p->{location} ? ('me.location' =>
|
||||
{ '-ilike' => "\%$p->{location}\%" }) : ()),
|
||||
($p->{description} ? ('me.description' =>
|
||||
{ '-ilike' => "\%$p->{description}\%" }) : ()),
|
||||
($p->{layers} ? ('me.layers' =>
|
||||
{ '-ilike' => "\%$layer_string" }) : ()),
|
||||
|
||||
($p->{model} ? ('me.model' =>
|
||||
{ '-in' => $p->{model} }) : ()),
|
||||
($p->{os} ? ('me.os' =>
|
||||
{ '-in' => $p->{os} }) : ()),
|
||||
($p->{os_ver} ? ('me.os_ver' =>
|
||||
{ '-in' => $p->{os_ver} }) : ()),
|
||||
($p->{vendor} ? ('me.vendor' =>
|
||||
{ '-in' => $p->{vendor} }) : ()),
|
||||
|
||||
($p->{dns} ? (
|
||||
-or => [
|
||||
'me.dns' => { '-ilike' => "\%$p->{dns}\%" },
|
||||
'device_ips.dns' => { '-ilike' => "\%$p->{dns}\%" },
|
||||
]) : ()),
|
||||
|
||||
($p->{ip} ? (
|
||||
-or => [
|
||||
'me.ip' => { '<<=' => $p->{ip}->cidr },
|
||||
'device_ips.alias' => { '<<=' => $p->{ip}->cidr },
|
||||
]) : ()),
|
||||
],
|
||||
},
|
||||
{
|
||||
order_by => [qw/ me.dns me.ip /],
|
||||
(($p->{dns} or $p->{ip}) ? (
|
||||
join => 'device_ips',
|
||||
distinct => 1,
|
||||
) : ()),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
=head2 search_fuzzy( $value )
|
||||
|
||||
This method accepts a single parameter only and returns a ResultSet of rows
|
||||
from the Device table where one field matches the passed parameter.
|
||||
|
||||
The following fields are inspected for a match:
|
||||
|
||||
=over 4
|
||||
|
||||
=item contact
|
||||
|
||||
=item serial
|
||||
|
||||
=item location
|
||||
|
||||
=item name
|
||||
|
||||
=item description
|
||||
|
||||
=item dns
|
||||
|
||||
=item ip (including aliases)
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub search_fuzzy {
|
||||
my ($rs, $q) = @_;
|
||||
|
||||
die "missing param to search_fuzzy\n"
|
||||
unless $q;
|
||||
$q = "\%$q\%" if $q !~ m/\%/;
|
||||
|
||||
# basic IP check is a string match
|
||||
my $ip_clause = [
|
||||
'me.ip::text' => { '-ilike' => $q },
|
||||
'device_ips.alias::text' => { '-ilike' => $q },
|
||||
];
|
||||
|
||||
# but also allow prefix search
|
||||
(my $qc = $q) =~ s/\%//g;
|
||||
if (my $ip = NetAddr::IP::Lite->new($qc)) {
|
||||
$ip_clause = [
|
||||
'me.ip' => { '<<=' => $ip->cidr },
|
||||
'device_ips.alias' => { '<<=' => $ip->cidr },
|
||||
];
|
||||
}
|
||||
|
||||
return $rs->search(
|
||||
{
|
||||
-or => [
|
||||
'me.contact' => { '-ilike' => $q },
|
||||
'me.serial' => { '-ilike' => $q },
|
||||
'me.location' => { '-ilike' => $q },
|
||||
'me.name' => { '-ilike' => $q },
|
||||
'me.description' => { '-ilike' => $q },
|
||||
-or => [
|
||||
'me.dns' => { '-ilike' => $q },
|
||||
'device_ips.dns' => { '-ilike' => $q },
|
||||
],
|
||||
-or => $ip_clause,
|
||||
],
|
||||
},
|
||||
{
|
||||
order_by => [qw/ me.dns me.ip /],
|
||||
join => 'device_ips',
|
||||
distinct => 1,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
=head2 carrying_vlan( \%cond, \%attrs? )
|
||||
|
||||
my $set = $rs->carrying_vlan({ vlan => 123 });
|
||||
|
||||
Like C<search()>, this returns a ResultSet of matching rows from the Device
|
||||
table.
|
||||
|
||||
The returned devices each are aware of the given Vlan.
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
The C<cond> parameter must be a hashref containing a key C<vlan> with
|
||||
the value to search for.
|
||||
|
||||
=item *
|
||||
|
||||
Results are ordered by the Device DNS and IP fields.
|
||||
|
||||
=item *
|
||||
|
||||
Related rows from the C<device_vlan> table will be prefetched.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub carrying_vlan {
|
||||
my ($rs, $cond, $attrs) = @_;
|
||||
|
||||
die "vlan number required for carrying_vlan\n"
|
||||
if ref {} ne ref $cond or !exists $cond->{vlan};
|
||||
|
||||
return $rs
|
||||
->search_rs({ 'vlans.vlan' => $cond->{vlan} },
|
||||
{
|
||||
order_by => [qw/ me.dns me.ip /],
|
||||
columns => [
|
||||
'me.ip', 'me.dns',
|
||||
'me.model', 'me.os',
|
||||
'me.vendor', 'vlans.vlan',
|
||||
'vlans.description'
|
||||
],
|
||||
join => 'vlans'
|
||||
})
|
||||
->search({}, $attrs);
|
||||
}
|
||||
|
||||
=head2 carrying_vlan_name( \%cond, \%attrs? )
|
||||
|
||||
my $set = $rs->carrying_vlan_name({ name => 'Branch Office' });
|
||||
|
||||
Like C<search()>, this returns a ResultSet of matching rows from the Device
|
||||
table.
|
||||
|
||||
The returned devices each are aware of the named Vlan.
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
The C<cond> parameter must be a hashref containing a key C<name> with
|
||||
the value to search for. The value may optionally include SQL wildcard
|
||||
characters.
|
||||
|
||||
=item *
|
||||
|
||||
Results are ordered by the Device DNS and IP fields.
|
||||
|
||||
=item *
|
||||
|
||||
Related rows from the C<device_vlan> table will be prefetched.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub carrying_vlan_name {
|
||||
my ($rs, $cond, $attrs) = @_;
|
||||
|
||||
die "vlan name required for carrying_vlan_name\n"
|
||||
if ref {} ne ref $cond or !exists $cond->{name};
|
||||
|
||||
$cond->{'vlans.description'} = { '-ilike' => delete $cond->{name} };
|
||||
|
||||
return $rs
|
||||
->search_rs({}, {
|
||||
order_by => [qw/ me.dns me.ip /],
|
||||
columns => [
|
||||
'me.ip', 'me.dns',
|
||||
'me.model', 'me.os',
|
||||
'me.vendor', 'vlans.vlan',
|
||||
'vlans.description'
|
||||
],
|
||||
join => 'vlans'
|
||||
})
|
||||
->search($cond, $attrs);
|
||||
}
|
||||
|
||||
=head2 has_layer( $layer )
|
||||
|
||||
my $rset = $rs->has_layer(3);
|
||||
|
||||
This predefined C<search()> returns a ResultSet of matching rows from the
|
||||
Device table of devices advertising support of the supplied layer in the
|
||||
OSI Model.
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
The C<layer> parameter must be an integer between 1 and 7.
|
||||
|
||||
=cut
|
||||
|
||||
sub has_layer {
|
||||
my ( $rs, $layer ) = @_;
|
||||
|
||||
die "layer required and must be between 1 and 7\n"
|
||||
if !$layer || $layer < 1 || $layer > 7;
|
||||
|
||||
return $rs->search_rs( \[ 'substring(layers,9-?, 1)::int = 1', $layer ] );
|
||||
}
|
||||
|
||||
=back
|
||||
|
||||
=head2 get_models
|
||||
|
||||
Returns a sorted list of Device models with the following columns only:
|
||||
|
||||
=over 4
|
||||
|
||||
=item vendor
|
||||
|
||||
=item model
|
||||
|
||||
=item count
|
||||
|
||||
=back
|
||||
|
||||
Where C<count> is the number of instances of that Vendor's Model in the
|
||||
Netdisco database.
|
||||
|
||||
=cut
|
||||
|
||||
sub get_models {
|
||||
my $rs = shift;
|
||||
return $rs->search({}, {
|
||||
select => [ 'vendor', 'model', { count => 'ip' } ],
|
||||
as => [qw/vendor model count/],
|
||||
group_by => [qw/vendor model/],
|
||||
order_by => [{-asc => 'vendor'}, {-asc => 'model'}],
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
=head2 get_releases
|
||||
|
||||
Returns a sorted list of Device OS releases with the following columns only:
|
||||
|
||||
=over 4
|
||||
|
||||
=item os
|
||||
|
||||
=item os_ver
|
||||
|
||||
=item count
|
||||
|
||||
=back
|
||||
|
||||
Where C<count> is the number of devices running that OS release in the
|
||||
Netdisco database.
|
||||
|
||||
=cut
|
||||
|
||||
sub get_releases {
|
||||
my $rs = shift;
|
||||
return $rs->search({}, {
|
||||
select => [ 'os', 'os_ver', { count => 'ip' } ],
|
||||
as => [qw/os os_ver count/],
|
||||
group_by => [qw/os os_ver/],
|
||||
order_by => [{-asc => 'os'}, {-asc => 'os_ver'}],
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
=head2 with_port_count
|
||||
|
||||
This is a modifier for any C<search()> which
|
||||
will add the following additional synthesized column to the result set:
|
||||
|
||||
=over 4
|
||||
|
||||
=item port_count
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub with_port_count {
|
||||
my ($rs, $cond, $attrs) = @_;
|
||||
|
||||
return $rs
|
||||
->search_rs($cond, $attrs)
|
||||
->search({},
|
||||
{
|
||||
'+columns' => {
|
||||
port_count =>
|
||||
$rs->result_source->schema->resultset('DevicePort')
|
||||
->search(
|
||||
{
|
||||
'dp.ip' => { -ident => 'me.ip' },
|
||||
'dp.type' => { '!=' => 'propVirtual' },
|
||||
},
|
||||
{ alias => 'dp' }
|
||||
)->count_rs->as_query,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
=head1 SPECIAL METHODS
|
||||
|
||||
=head2 delete( \%options? )
|
||||
|
||||
Overrides the built-in L<DBIx::Class> delete method to more efficiently
|
||||
handle the removal or archiving of nodes.
|
||||
|
||||
=cut
|
||||
|
||||
sub delete {
|
||||
my $self = shift;
|
||||
|
||||
my $schema = $self->result_source->schema;
|
||||
my $devices = $self->search(undef, { columns => 'ip' });
|
||||
|
||||
foreach my $set (qw/
|
||||
DeviceIp
|
||||
DeviceVlan
|
||||
DevicePower
|
||||
DeviceModule
|
||||
Community
|
||||
/) {
|
||||
$schema->resultset($set)->search(
|
||||
{ ip => { '-in' => $devices->as_query } },
|
||||
)->delete;
|
||||
}
|
||||
|
||||
$schema->resultset('Admin')->search({
|
||||
device => { '-in' => $devices->as_query },
|
||||
})->delete;
|
||||
|
||||
$schema->resultset('Topology')->search({
|
||||
-or => [
|
||||
{ dev1 => { '-in' => $devices->as_query } },
|
||||
{ dev2 => { '-in' => $devices->as_query } },
|
||||
],
|
||||
})->delete;
|
||||
|
||||
$schema->resultset('DevicePort')->search(
|
||||
{ ip => { '-in' => $devices->as_query } },
|
||||
)->delete(@_);
|
||||
|
||||
# now let DBIC do its thing
|
||||
return $self->next::method();
|
||||
}
|
||||
|
||||
1;
|
||||
107
lib/App/Netdisco/DB/ResultSet/DeviceModule.pm
Normal file
107
lib/App/Netdisco/DB/ResultSet/DeviceModule.pm
Normal file
@@ -0,0 +1,107 @@
|
||||
package App::Netdisco::DB::ResultSet::DeviceModule;
|
||||
use base 'App::Netdisco::DB::ResultSet';
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
=head1 ADDITIONAL METHODS
|
||||
|
||||
=head2 search_by_field( \%cond, \%attrs? )
|
||||
|
||||
This variant of the standard C<search()> method returns a ResultSet of Device
|
||||
Module entries. It is written to support web forms which accept fields that
|
||||
match and locate Device Modules in the database.
|
||||
|
||||
The hashref parameter should contain fields from the Device Module table
|
||||
which will be intelligently used in a search query.
|
||||
|
||||
In addition, you can provide the key C<matchall> which, given a True or False
|
||||
value, controls whether fields must all match or whether any can match, to
|
||||
select a row.
|
||||
|
||||
Supported keys:
|
||||
|
||||
=over 4
|
||||
|
||||
=item matchall
|
||||
|
||||
If a True value, fields must all match to return a given row of the Device
|
||||
table, otherwise any field matching will cause the row to be included in
|
||||
results.
|
||||
|
||||
=item description
|
||||
|
||||
Can match the C<description> field as a substring.
|
||||
|
||||
=item name
|
||||
|
||||
Can match the C<name> field as a substring.
|
||||
|
||||
=item type
|
||||
|
||||
Can match the C<type> field as a substring.
|
||||
|
||||
=item model
|
||||
|
||||
Can match the C<model> field as a substring.
|
||||
|
||||
=item serial
|
||||
|
||||
Can match the C<serial> field as a substring.
|
||||
|
||||
=item class
|
||||
|
||||
Will match exactly the C<class> field.
|
||||
|
||||
=item ips
|
||||
|
||||
List of Device IPs containing modules.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub search_by_field {
|
||||
my ( $rs, $p, $attrs ) = @_;
|
||||
|
||||
die "condition parameter to search_by_field must be hashref\n"
|
||||
if ref {} ne ref $p
|
||||
or 0 == scalar keys %$p;
|
||||
|
||||
my $op = $p->{matchall} ? '-and' : '-or';
|
||||
|
||||
return $rs->search_rs( {}, $attrs )->search(
|
||||
{ $op => [
|
||||
( $p->{description}
|
||||
? ( 'me.description' =>
|
||||
{ '-ilike' => "\%$p->{description}\%" } )
|
||||
: ()
|
||||
),
|
||||
( $p->{name}
|
||||
? ( 'me.name' => { '-ilike' => "\%$p->{name}\%" } )
|
||||
: ()
|
||||
),
|
||||
( $p->{type}
|
||||
? ( 'me.type' => { '-ilike' => "\%$p->{type}\%" } )
|
||||
: ()
|
||||
),
|
||||
( $p->{model}
|
||||
? ( 'me.model' => { '-ilike' => "\%$p->{model}\%" } )
|
||||
: ()
|
||||
),
|
||||
( $p->{serial}
|
||||
? ( 'me.serial' => { '-ilike' => "\%$p->{serial}\%" } )
|
||||
: ()
|
||||
),
|
||||
|
||||
( $p->{class}
|
||||
? ( 'me.class' => { '-in' => $p->{class} } )
|
||||
: ()
|
||||
),
|
||||
( $p->{ips} ? ( 'me.ip' => { '-in' => $p->{ips} } ) : () ),
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
174
lib/App/Netdisco/DB/ResultSet/DevicePort.pm
Normal file
174
lib/App/Netdisco/DB/ResultSet/DevicePort.pm
Normal file
@@ -0,0 +1,174 @@
|
||||
package App::Netdisco::DB::ResultSet::DevicePort;
|
||||
use base 'App::Netdisco::DB::ResultSet';
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
__PACKAGE__->load_components(qw/
|
||||
+App::Netdisco::DB::ExplicitLocking
|
||||
/);
|
||||
|
||||
=head1 ADDITIONAL METHODS
|
||||
|
||||
=head2 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 lastchange_stamp
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub with_times {
|
||||
my ($rs, $cond, $attrs) = @_;
|
||||
|
||||
return $rs
|
||||
->search_rs($cond, $attrs)
|
||||
->search({},
|
||||
{
|
||||
'+columns' => { lastchange_stamp =>
|
||||
\("to_char(device.last_discover - (device.uptime - me.lastchange) / 100 * interval '1 second', "
|
||||
."'YYYY-MM-DD HH24:MI:SS')") },
|
||||
join => 'device',
|
||||
});
|
||||
}
|
||||
|
||||
=head2 with_free_ports
|
||||
|
||||
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 is_free
|
||||
|
||||
=back
|
||||
|
||||
In the C<$cond> hash (the first parameter) pass in the C<age_num> which must
|
||||
be an integer, and the C<age_unit> which must be a string of either C<days>,
|
||||
C<weeks>, C<months> or C<years>.
|
||||
|
||||
=cut
|
||||
|
||||
sub with_is_free {
|
||||
my ($rs, $cond, $attrs) = @_;
|
||||
|
||||
my $interval = (delete $cond->{age_num}) .' '. (delete $cond->{age_unit});
|
||||
|
||||
return $rs
|
||||
->search_rs($cond, $attrs)
|
||||
->search({},
|
||||
{
|
||||
'+columns' => { is_free =>
|
||||
\["me.up != 'up' and "
|
||||
."age(now(), to_timestamp(extract(epoch from device.last_discover) "
|
||||
."- (device.uptime - me.lastchange)/100)) "
|
||||
."> ?::interval",
|
||||
[{} => $interval]] },
|
||||
join => 'device',
|
||||
});
|
||||
}
|
||||
|
||||
=head2 only_free_ports
|
||||
|
||||
This is a modifier for any C<search()> (including the helpers below) which
|
||||
will restrict results based on whether the port is considered "free".
|
||||
|
||||
In the C<$cond> hash (the first parameter) pass in the C<age_num> which must
|
||||
be an integer, and the C<age_unit> which must be a string of either C<days>,
|
||||
C<weeks>, C<months> or C<years>.
|
||||
|
||||
=cut
|
||||
|
||||
sub only_free_ports {
|
||||
my ($rs, $cond, $attrs) = @_;
|
||||
|
||||
my $interval = (delete $cond->{age_num}) .' '. (delete $cond->{age_unit});
|
||||
|
||||
return $rs
|
||||
->search_rs($cond, $attrs)
|
||||
->search(
|
||||
{
|
||||
'me.up' => { '!=' => 'up' },
|
||||
},{
|
||||
where =>
|
||||
\["age(now(), to_timestamp(extract(epoch from device.last_discover) "
|
||||
."- (device.uptime - me.lastchange)/100)) "
|
||||
."> ?::interval",
|
||||
[{} => $interval]],
|
||||
join => 'device' },
|
||||
);
|
||||
}
|
||||
|
||||
=head2 with_vlan_count
|
||||
|
||||
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 vlan_count
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub with_vlan_count {
|
||||
my ($rs, $cond, $attrs) = @_;
|
||||
|
||||
return $rs
|
||||
->search_rs($cond, $attrs)
|
||||
->search({},
|
||||
{
|
||||
'+columns' => { vlan_count =>
|
||||
$rs->result_source->schema->resultset('DevicePortVlan')
|
||||
->search(
|
||||
{
|
||||
'dpv.ip' => { -ident => 'me.ip' },
|
||||
'dpv.port' => { -ident => 'me.port' },
|
||||
},
|
||||
{ alias => 'dpv' }
|
||||
)->count_rs->as_query
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
=head1 SPECIAL METHODS
|
||||
|
||||
=head2 delete( \%options? )
|
||||
|
||||
Overrides the built-in L<DBIx::Class> delete method to more efficiently
|
||||
handle the removal or archiving of nodes.
|
||||
|
||||
=cut
|
||||
|
||||
sub delete {
|
||||
my $self = shift;
|
||||
|
||||
my $schema = $self->result_source->schema;
|
||||
my $ports = $self->search(undef, { columns => 'ip' });
|
||||
|
||||
foreach my $set (qw/
|
||||
DevicePortPower
|
||||
DevicePortVlan
|
||||
DevicePortWireless
|
||||
DevicePortSsid
|
||||
/) {
|
||||
$schema->resultset($set)->search(
|
||||
{ ip => { '-in' => $ports->as_query }},
|
||||
)->delete;
|
||||
}
|
||||
|
||||
$schema->resultset('Node')->search(
|
||||
{ switch => { '-in' => $ports->as_query }},
|
||||
)->delete(@_);
|
||||
|
||||
# now let DBIC do its thing
|
||||
return $self->next::method();
|
||||
}
|
||||
|
||||
1;
|
||||
39
lib/App/Netdisco/DB/ResultSet/DevicePortLog.pm
Normal file
39
lib/App/Netdisco/DB/ResultSet/DevicePortLog.pm
Normal file
@@ -0,0 +1,39 @@
|
||||
package App::Netdisco::DB::ResultSet::DevicePortLog;
|
||||
use base 'App::Netdisco::DB::ResultSet';
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
__PACKAGE__->load_components(qw/
|
||||
+App::Netdisco::DB::ExplicitLocking
|
||||
/);
|
||||
|
||||
=head1 ADDITIONAL METHODS
|
||||
|
||||
=head2 with_times
|
||||
|
||||
This is a modifier for any C<search()> which will add the following additional
|
||||
synthesized column to the result set:
|
||||
|
||||
=over 4
|
||||
|
||||
=item creation_stamp
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub with_times {
|
||||
my ($rs, $cond, $attrs) = @_;
|
||||
|
||||
return $rs
|
||||
->search_rs($cond, $attrs)
|
||||
->search({},
|
||||
{
|
||||
'+columns' => {
|
||||
creation_stamp => \"to_char(creation, 'YYYY-MM-DD HH24:MI:SS')",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
48
lib/App/Netdisco/DB/ResultSet/DevicePortSsid.pm
Normal file
48
lib/App/Netdisco/DB/ResultSet/DevicePortSsid.pm
Normal file
@@ -0,0 +1,48 @@
|
||||
package App::Netdisco::DB::ResultSet::DevicePortSsid;
|
||||
use base 'App::Netdisco::DB::ResultSet';
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
__PACKAGE__->load_components(
|
||||
qw/
|
||||
+App::Netdisco::DB::ExplicitLocking
|
||||
/
|
||||
);
|
||||
|
||||
=head1 ADDITIONAL METHODS
|
||||
|
||||
=head2 get_ssids
|
||||
|
||||
Returns a sorted list of SSIDs with the following columns only:
|
||||
|
||||
=over 4
|
||||
|
||||
=item ssid
|
||||
|
||||
=item broadcast
|
||||
|
||||
=item count
|
||||
|
||||
=back
|
||||
|
||||
Where C<count> is the number of instances of the SSID in the Netdisco
|
||||
database.
|
||||
|
||||
=cut
|
||||
|
||||
sub get_ssids {
|
||||
my $rs = shift;
|
||||
|
||||
return $rs->search(
|
||||
{},
|
||||
{ select => [ 'ssid', 'broadcast', { count => 'ssid' } ],
|
||||
as => [qw/ ssid broadcast count /],
|
||||
group_by => [qw/ ssid broadcast /],
|
||||
order_by => { -desc => [qw/count/] },
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
1;
|
||||
78
lib/App/Netdisco/DB/ResultSet/DevicePower.pm
Normal file
78
lib/App/Netdisco/DB/ResultSet/DevicePower.pm
Normal file
@@ -0,0 +1,78 @@
|
||||
package App::Netdisco::DB::ResultSet::DevicePower;
|
||||
use base 'App::Netdisco::DB::ResultSet';
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
=head1 ADDITIONAL METHODS
|
||||
|
||||
|
||||
=head2 with_poestats
|
||||
|
||||
This is a modifier for any C<search()> which will add the following
|
||||
additional synthesized columns to the result set:
|
||||
|
||||
=over 4
|
||||
|
||||
=item poe_capable_ports
|
||||
|
||||
Count of ports which have the ability to supply PoE.
|
||||
|
||||
=item poe_powered_ports
|
||||
|
||||
Count of ports with PoE administratively disabled.
|
||||
|
||||
=item poe_disabled_ports
|
||||
|
||||
Count of ports which are delivering power.
|
||||
|
||||
=item poe_errored_ports
|
||||
|
||||
Count of ports either reporting a fault or in test mode.
|
||||
|
||||
=item poe_power_committed
|
||||
|
||||
Total power that has been negotiated and therefore committed on ports
|
||||
actively supplying power.
|
||||
|
||||
=item poe_power_delivering
|
||||
|
||||
Total power as measured on ports actively supplying power.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub with_poestats {
|
||||
my ($rs, $cond, $attrs) = @_;
|
||||
|
||||
return $rs
|
||||
->search_rs($cond, $attrs)
|
||||
->search({},
|
||||
{
|
||||
'columns' => {
|
||||
ip => \"DISTINCT ON (me.ip, me.module) me.ip",
|
||||
module => 'module',
|
||||
power => 'power::bigint',
|
||||
status => 'status',
|
||||
poe_capable_ports => \"COUNT(ports.port) OVER (PARTITION BY me.ip, me.module)",
|
||||
poe_powered_ports => \"SUM(CASE WHEN ports.status = 'deliveringPower' THEN 1 ELSE 0 END) OVER (PARTITION BY me.ip, me.module)",
|
||||
poe_disabled_ports => \"SUM(CASE WHEN ports.admin = 'false' THEN 1 ELSE 0 END) OVER (PARTITION BY me.ip, me.module)",
|
||||
poe_errored_ports => \"SUM(CASE WHEN ports.status ILIKE '%fault' THEN 1 ELSE 0 END) OVER (PARTITION BY me.ip, me.module)",
|
||||
poe_power_committed => \("SUM(CASE "
|
||||
. "WHEN ports.status = 'deliveringPower' AND ports.class = 'class0' THEN 15.4 "
|
||||
. "WHEN ports.status = 'deliveringPower' AND ports.class = 'class1' THEN 4.0 "
|
||||
. "WHEN ports.status = 'deliveringPower' AND ports.class = 'class2' THEN 7.0 "
|
||||
. "WHEN ports.status = 'deliveringPower' AND ports.class = 'class3' THEN 15.4 "
|
||||
. "WHEN ports.status = 'deliveringPower' AND ports.class = 'class4' THEN 30.0 "
|
||||
. "WHEN ports.status = 'deliveringPower' AND ports.class IS NULL THEN 15.4 "
|
||||
. "ELSE 0 END) OVER (PARTITION BY me.ip, me.module)"),
|
||||
poe_power_delivering => \("SUM(CASE WHEN (ports.power IS NULL OR ports.power = '0') "
|
||||
. "THEN 0 ELSE round(ports.power/1000.0, 1) END) "
|
||||
. "OVER (PARTITION BY me.ip, me.module)")
|
||||
},
|
||||
join => 'ports'
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
149
lib/App/Netdisco/DB/ResultSet/Node.pm
Normal file
149
lib/App/Netdisco/DB/ResultSet/Node.pm
Normal file
@@ -0,0 +1,149 @@
|
||||
package App::Netdisco::DB::ResultSet::Node;
|
||||
use base 'App::Netdisco::DB::ResultSet';
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
__PACKAGE__->load_components(qw/
|
||||
+App::Netdisco::DB::ExplicitLocking
|
||||
/);
|
||||
|
||||
=head1 ADDITIONAL METHODS
|
||||
|
||||
=head2 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 Node
|
||||
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 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};
|
||||
|
||||
return $rs
|
||||
->search_rs({}, {
|
||||
order_by => {'-desc' => 'time_last'},
|
||||
'+columns' => [
|
||||
'device.dns',
|
||||
{ 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 => 'device',
|
||||
})
|
||||
->search($cond, $attrs);
|
||||
}
|
||||
|
||||
=head1 SPECIAL METHODS
|
||||
|
||||
=head2 delete( \%options? )
|
||||
|
||||
Overrides the built-in L<DBIx::Class> delete method to more efficiently
|
||||
handle the removal or archiving of nodes.
|
||||
|
||||
=cut
|
||||
|
||||
sub delete {
|
||||
my $self = shift;
|
||||
my ($opts) = @_;
|
||||
$opts = {} if (ref {} ne ref $opts);
|
||||
|
||||
my $schema = $self->result_source->schema;
|
||||
my $nodes = $self->search(undef, { columns => 'mac' });
|
||||
|
||||
if (exists $opts->{archive_nodes} and $opts->{archive_nodes}) {
|
||||
foreach my $set (qw/
|
||||
NodeIp
|
||||
NodeNbt
|
||||
NodeMonitor
|
||||
Node
|
||||
/) {
|
||||
$schema->resultset($set)->search(
|
||||
{ mac => { '-in' => $nodes->as_query }},
|
||||
)->update({ active => \'false' });
|
||||
}
|
||||
|
||||
$schema->resultset('NodeWireless')
|
||||
->search({ mac => { '-in' => $nodes->as_query }})->delete;
|
||||
|
||||
# avoid letting DBIC delete nodes
|
||||
return 0E0;
|
||||
}
|
||||
elsif (exists $opts->{only_nodes} and $opts->{only_nodes}) {
|
||||
# now let DBIC do its thing
|
||||
return $self->next::method();
|
||||
}
|
||||
elsif (exists $opts->{keep_nodes} and $opts->{keep_nodes}) {
|
||||
# avoid letting DBIC delete nodes
|
||||
return 0E0;
|
||||
}
|
||||
else {
|
||||
# for node_ip and node_nbt *only* delete if there are no longer
|
||||
# any active nodes referencing the IP or NBT (hence 2nd IN clause).
|
||||
foreach my $set (qw/
|
||||
NodeIp
|
||||
NodeNbt
|
||||
/) {
|
||||
$schema->resultset($set)->search({
|
||||
'me.mac' => { '-in' => $schema->resultset($set)->search({
|
||||
'-and' => [
|
||||
-bool => 'nodes.active',
|
||||
'me.mac' => { '-in' => $nodes->as_query }
|
||||
]
|
||||
},
|
||||
{
|
||||
columns => 'mac',
|
||||
join => 'nodes',
|
||||
group_by => 'me.mac',
|
||||
having => \[ 'count(nodes.mac) = 0' ],
|
||||
})->as_query,
|
||||
},
|
||||
})->delete;
|
||||
}
|
||||
|
||||
foreach my $set (qw/
|
||||
NodeMonitor
|
||||
NodeWireless
|
||||
/) {
|
||||
$schema->resultset($set)->search(
|
||||
{ mac => { '-in' => $nodes->as_query }},
|
||||
)->delete;
|
||||
}
|
||||
|
||||
# now let DBIC do its thing
|
||||
return $self->next::method();
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
219
lib/App/Netdisco/DB/ResultSet/NodeIp.pm
Normal file
219
lib/App/Netdisco/DB/ResultSet/NodeIp.pm
Normal file
@@ -0,0 +1,219 @@
|
||||
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 $search_attr = {
|
||||
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({}, $search_attr)
|
||||
->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({}, $search_attr)
|
||||
->search($cond, $attrs);
|
||||
}
|
||||
|
||||
=head1 search_by_name( \%cond, \%attrs? )
|
||||
|
||||
my $set = $rs->search_by_name({dns => 'foo.example.com', 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 *
|
||||
|
||||
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};
|
||||
|
||||
$cond->{dns} = { '-ilike' => delete $cond->{dns} };
|
||||
|
||||
return $rs
|
||||
->search_rs({}, $search_attr)
|
||||
->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({}, $search_attr)
|
||||
->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.
|
||||
|
||||
=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;
|
||||
189
lib/App/Netdisco/DB/ResultSet/NodeNbt.pm
Normal file
189
lib/App/Netdisco/DB/ResultSet/NodeNbt.pm
Normal file
@@ -0,0 +1,189 @@
|
||||
package App::Netdisco::DB::ResultSet::NodeNbt;
|
||||
use base 'App::Netdisco::DB::ResultSet';
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
__PACKAGE__->load_components(qw/
|
||||
+App::Netdisco::DB::ExplicitLocking
|
||||
/);
|
||||
|
||||
my $search_attr = {
|
||||
order_by => {'-desc' => 'time_last'},
|
||||
'+columns' => [
|
||||
'oui.company',
|
||||
{ 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({}, $search_attr)
|
||||
->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
|
||||
NodeNbt 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({}, $search_attr)
|
||||
->search($cond, $attrs);
|
||||
}
|
||||
|
||||
=head1 search_by_name( \%cond, \%attrs? )
|
||||
|
||||
my $set = $rs->search_by_name({nbname => 'MYNAME', active => 1});
|
||||
|
||||
Like C<search()>, this returns a ResultSet of matching rows from the
|
||||
NodeNbt table.
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
The C<cond> parameter must be a hashref containing a key C<nbname> 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_name {
|
||||
my ($rs, $cond, $attrs) = @_;
|
||||
|
||||
die "nbname field required for search_by_name\n"
|
||||
if ref {} ne ref $cond or !exists $cond->{nbname};
|
||||
|
||||
$cond->{nbname} = { '-ilike' => delete $cond->{nbname} };
|
||||
|
||||
return $rs
|
||||
->search_rs({}, $search_attr)
|
||||
->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
|
||||
NodeNbt 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({}, $search_attr)
|
||||
->search($cond, $attrs);
|
||||
}
|
||||
|
||||
1;
|
||||
11
lib/App/Netdisco/DB/ResultSet/NodeWireless.pm
Normal file
11
lib/App/Netdisco/DB/ResultSet/NodeWireless.pm
Normal file
@@ -0,0 +1,11 @@
|
||||
package App::Netdisco::DB::ResultSet::NodeWireless;
|
||||
use base 'App::Netdisco::DB::ResultSet';
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
__PACKAGE__->load_components(qw/
|
||||
+App::Netdisco::DB::ExplicitLocking
|
||||
/);
|
||||
|
||||
1;
|
||||
11
lib/App/Netdisco/DB/ResultSet/Subnet.pm
Normal file
11
lib/App/Netdisco/DB/ResultSet/Subnet.pm
Normal file
@@ -0,0 +1,11 @@
|
||||
package App::Netdisco::DB::ResultSet::Subnet;
|
||||
use base 'App::Netdisco::DB::ResultSet';
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
__PACKAGE__->load_components(qw/
|
||||
+App::Netdisco::DB::ExplicitLocking
|
||||
/);
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user