include free ports calculation in SQL

This commit is contained in:
Oliver Gorwits
2012-02-22 19:11:37 +00:00
parent aad35e13e1
commit 9857ae2868
4 changed files with 91 additions and 45 deletions

View File

@@ -202,44 +202,6 @@ sub neighbor {
return eval { $row->neighbor_alias->device || undef };
}
=head2 is_free( $quantity, $unit )
This method can be used to evaluate whether a device port could be considered
unused, based on the last time it changed from the "up" state to a "down"
state.
Pass in two parameters, first the C<$quantity> which must be an integer, and
second the C<$unit> which must be a string of either C<days>, C<weeks>,
C<months> or C<years>.
A True value is returned if the port is in a "down" state but administratively
"up", yet last changed state at or further back than the parameters' time
window. If the port is not in the correct state, or last changed state more
recently, then a False value is returned.
=cut
sub is_free {
my ($row, $num, $unit) = @_;
return unless $num =~ m/^\d+$/
and $unit =~ m/(?:days|weeks|months|years)/;
return 0 unless
($row->up_admin and $row->up_admin eq 'up')
and ($row->up and $row->up eq 'down');
my $quan = {
days => (60 * 60 * 24),
weeks => (60 * 60 * 24 * 7),
months => (60 * 60 * 24 * 31),
years => (60 * 60 * 24 * 365),
};
my $total = $num * $quan->{$unit};
my $diff_sec = $row->lastchange / 100;
return ($diff_sec >= $total ? 1 : 0);
}
=head1 ADDITIONAL COLUMNS
=head2 tagged_vlans_count
@@ -265,4 +227,16 @@ between the date stamp and time stamp. That is:
sub lastchange_stamp { return (shift)->get_column('lastchange_stamp') }
=head2 is_free
This method can be used to evaluate whether a device port could be considered
unused, based on the last time it changed from the "up" state to a "down"
state.
See the C<with_is_free> and C<only_free_ports> modifiers to C<search()>.
=cut
sub is_free { return (shift)->get_column('is_free') }
1;

View File

@@ -35,6 +35,75 @@ sub with_times {
});
}
=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({},
{
'+select' => [
\["up != 'up' and "
."age(to_timestamp(extract(epoch from device.last_discover) "
."- (device.uptime - lastchange)/100)) "
."> ?::interval",
[{} => $interval]],
],
'+as' => [qw/ is_free /],
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(
{
'up' => { '!=' => 'up' },
},{
where =>
\["age(to_timestamp(extract(epoch from device.last_discover) "
."- (device.uptime - lastchange)/100)) "
."> ?::interval",
[{} => $interval]],
join => 'device' },
);
}
=head2 with_vlan_count
This is a modifier for any C<search()> (including the helpers below) which

View File

@@ -93,6 +93,13 @@ ajax '/ajax/content/device/ports' => sub {
}
}
# filter for free ports if asked
my $free_filter = (param('free') ? 'only_free_ports' : 'with_is_free');
$set = $set->$free_filter({
age_num => (param('age_num') || 3),
age_unit => (param('age_unit') || 'months')
});
# make sure query asks for formatted timestamps when needed
$set = $set->with_times if param('c_lastchange');
@@ -108,12 +115,8 @@ ajax '/ajax/content/device/ports' => sub {
prefetch => [{$nodes_name => 'ips'}, {neighbor_alias => 'device'}],
}) if param('c_connected');
# sort, and filter by free ports
# the filter could be in the template but here allows a 'no records' msg
my $results = [ sort { &netdisco::sort_port($a->port, $b->port) }
grep { not param('free')
or $_->is_free(param('age_num'), param('age_unit')) } $set->all ];
# sort ports (empty set would be a 'no records' msg)
my $results = [ sort { &netdisco::sort_port($a->port, $b->port) } $set->all ];
return unless scalar @$results;
content_type('text/html');

View File

@@ -16,7 +16,7 @@
<span class="label">s</span>
[% ELSIF row.stp == 'blocking' %]
<span class="label notice">b</span>
[% ELSIF row.is_free(params.age_num, params.age_unit) %]
[% ELSIF params.free OR row.is_free %]
<span class="label success">f</span>
[% ELSIF row.up_admin == 'up' AND row.up == 'down' %]
<span class="label warning">d</span>