Squashed commit of the following:
commit 4b6f3de36cbf508c05fbf7f18acee1758bc838ed
Merge: 94ed8b8 200dd2d
Author: Eric A. Miller <emiller@cpan.org>
Date: Mon Nov 4 19:30:04 2013 -0500
Merge branch 'master' into em-poe-report
commit 94ed8b8cf01963030a40829fd71bff529750719e
Author: Eric A. Miller <emiller@cpan.org>
Date: Sun Nov 3 23:34:07 2013 -0500
Show PoE module statistics in device details if available
commit 652974b312c11d6017cf6f3c0693d62085774e80
Author: Eric A. Miller <emiller@cpan.org>
Date: Sun Nov 3 23:31:02 2013 -0500
Move PoE statistics to model from controller
Add missing div in PoE status report
commit f94f68b1c84d23b2f252d985509757d95be5c0d0
Author: Eric A. Miller <emiller@cpan.org>
Date: Tue Oct 22 22:38:45 2013 -0400
Device PoE status report
This commit is contained in:
@@ -43,4 +43,15 @@ __PACKAGE__->belongs_to( port => 'App::Netdisco::DB::Result::DevicePort', {
|
|||||||
'foreign.ip' => 'self.ip', 'foreign.port' => 'self.port',
|
'foreign.ip' => 'self.ip', 'foreign.port' => 'self.port',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
=head2 device_module
|
||||||
|
|
||||||
|
Returns the entry from the C<device_power> table for which this Power entry
|
||||||
|
applies.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->belongs_to( device_module => 'App::Netdisco::DB::Result::DevicePower', {
|
||||||
|
'foreign.ip' => 'self.ip', 'foreign.module' => 'self.module',
|
||||||
|
});
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -35,5 +35,15 @@ Returns the entry from the C<device> table on which this power module was discov
|
|||||||
|
|
||||||
__PACKAGE__->belongs_to( device => 'App::Netdisco::DB::Result::Device', 'ip' );
|
__PACKAGE__->belongs_to( device => 'App::Netdisco::DB::Result::Device', 'ip' );
|
||||||
|
|
||||||
|
=head2 ports
|
||||||
|
|
||||||
|
Returns the set of PoE ports associated with a power module.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->has_many( ports => 'App::Netdisco::DB::Result::DevicePortPower', {
|
||||||
|
'foreign.ip' => 'self.ip', 'foreign.module' => 'self.module',
|
||||||
|
} );
|
||||||
|
|
||||||
# You can replace this text with custom code or comments, and it will be preserved on regeneration
|
# You can replace this text with custom code or comments, and it will be preserved on regeneration
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -575,4 +575,94 @@ sub delete {
|
|||||||
return $self->next::method();
|
return $self->next::method();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
=head2 with_poestats_as_hashref
|
||||||
|
|
||||||
|
This is a modifier for C<search()> which returns a hash reference with the
|
||||||
|
power_modules hash augmented with the following statistics as keys:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item capable_ports
|
||||||
|
|
||||||
|
Count of ports which have the ability to supply PoE.
|
||||||
|
|
||||||
|
=item disabled_ports
|
||||||
|
|
||||||
|
Count of ports with PoE administratively disabled.
|
||||||
|
|
||||||
|
=item powered_ports
|
||||||
|
|
||||||
|
Count of ports which are delivering power.
|
||||||
|
|
||||||
|
=item errored_ports
|
||||||
|
|
||||||
|
Count of ports either reporting a fault or in test mode.
|
||||||
|
|
||||||
|
=item pwr_committed
|
||||||
|
|
||||||
|
Total power that has been negotiated and therefore committed on ports
|
||||||
|
actively supplying power.
|
||||||
|
|
||||||
|
=item pwr_delivering
|
||||||
|
|
||||||
|
Total power as measured on ports actively supplying power.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub with_poestats_as_hashref {
|
||||||
|
my ( $rs, $cond, $attrs ) = @_;
|
||||||
|
|
||||||
|
my @return = $rs->search(
|
||||||
|
{},
|
||||||
|
{ result_class => 'DBIx::Class::ResultClass::HashRefInflator',
|
||||||
|
prefetch => { power_modules => 'ports' },
|
||||||
|
order_by => { -asc => [qw/me.ip power_modules.module/] }
|
||||||
|
})->all;
|
||||||
|
|
||||||
|
my $poemax = {
|
||||||
|
'class0' => 15.4,
|
||||||
|
'class1' => 4.0,
|
||||||
|
'class2' => 7.0,
|
||||||
|
'class3' => 15.4,
|
||||||
|
'class4' => 30.0
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach my $device (@return) {
|
||||||
|
foreach my $module (@{$device->{power_modules}}) {
|
||||||
|
$module->{capable_ports} = 0;
|
||||||
|
$module->{disabled_ports} = 0;
|
||||||
|
$module->{powered_ports} = 0;
|
||||||
|
$module->{errored_ports} = 0;
|
||||||
|
$module->{pwr_committed} = 0;
|
||||||
|
$module->{pwr_delivering} = 0;
|
||||||
|
|
||||||
|
foreach my $port ( @{$module->{ports}} ) {
|
||||||
|
$module->{capable_ports}++;
|
||||||
|
|
||||||
|
if ( $port->{admin} eq 'false' ) {
|
||||||
|
$module->{disabled_ports}++;
|
||||||
|
}
|
||||||
|
elsif ( $port->{status} ne 'searching'
|
||||||
|
and $port->{status} ne 'deliveringPower' )
|
||||||
|
{
|
||||||
|
$module->{errored_ports}++;
|
||||||
|
}
|
||||||
|
elsif ( $port->{status} eq 'deliveringPower' ) {
|
||||||
|
$module->{powered_ports}++;
|
||||||
|
if ( defined $port->{power} and $port->{power} ) {
|
||||||
|
$module->{pwr_delivering} += int( $port->{power} / 1000 );
|
||||||
|
$module->{pwr_committed} += $poemax->{ $port->{class} };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$module->{pwr_committed} += $poemax->{ $port->{class} };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return \@return;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -13,11 +13,16 @@ register_device_tab({ tag => 'details', label => 'Details' });
|
|||||||
ajax '/ajax/content/device/details' => require_login sub {
|
ajax '/ajax/content/device/details' => require_login sub {
|
||||||
my $q = param('q');
|
my $q = param('q');
|
||||||
my $device = schema('netdisco')->resultset('Device')
|
my $device = schema('netdisco')->resultset('Device')
|
||||||
->with_times()->search_for_device($q) or send_error('Bad device', 400);
|
->search_for_device($q) or send_error('Bad device', 400);
|
||||||
|
|
||||||
|
my $results
|
||||||
|
= schema('netdisco')->resultset('Device')
|
||||||
|
->search( { 'me.ip' => $device->ip } )->with_times()
|
||||||
|
->with_poestats_as_hashref;
|
||||||
|
|
||||||
content_type('text/html');
|
content_type('text/html');
|
||||||
template 'ajax/device/details.tt', {
|
template 'ajax/device/details.tt', {
|
||||||
d => $device,
|
d => $results->[0],
|
||||||
}, { layout => undef };
|
}, { layout => undef };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package App::Netdisco::Web::Plugin::Report::DevicePoeStatus;
|
||||||
|
|
||||||
|
use Dancer ':syntax';
|
||||||
|
use Dancer::Plugin::DBIC;
|
||||||
|
use Dancer::Plugin::Auth::Extensible;
|
||||||
|
|
||||||
|
use App::Netdisco::Web::Plugin;
|
||||||
|
|
||||||
|
register_report(
|
||||||
|
{ category => 'Device',
|
||||||
|
tag => 'devicepoestatus',
|
||||||
|
label => 'Power over Ethernet (PoE) Status',
|
||||||
|
provides_csv => 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
get '/ajax/content/report/devicepoestatus' => require_login sub {
|
||||||
|
my $results = schema('netdisco')->resultset('Device')
|
||||||
|
->with_poestats_as_hashref;
|
||||||
|
|
||||||
|
return unless scalar $results;
|
||||||
|
|
||||||
|
if ( request->is_ajax ) {
|
||||||
|
template 'ajax/report/devicepoestatus.tt', { results => $results, },
|
||||||
|
{ layout => undef };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
header( 'Content-Type' => 'text/comma-separated-values' );
|
||||||
|
template 'ajax/report/devicepoestatus_csv.tt',
|
||||||
|
{ results => $results, },
|
||||||
|
{ layout => undef };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -38,6 +38,7 @@ web_plugins:
|
|||||||
- Report::ApRadioChannelPower
|
- Report::ApRadioChannelPower
|
||||||
- Report::HalfDuplex
|
- Report::HalfDuplex
|
||||||
- Report::DeviceByLocation
|
- Report::DeviceByLocation
|
||||||
|
- Report::DevicePoeStatus
|
||||||
- Report::DuplexMismatch
|
- Report::DuplexMismatch
|
||||||
- Report::SsidInventory
|
- Report::SsidInventory
|
||||||
- Report::VlanInventory
|
- Report::VlanInventory
|
||||||
|
|||||||
@@ -86,6 +86,19 @@
|
|||||||
<br/>PS1 [[% d.ps1_type | html_entity %]]: [% d.ps1_status | html_entity %]
|
<br/>PS1 [[% d.ps1_type | html_entity %]]: [% d.ps1_status | html_entity %]
|
||||||
<br/>PS2 [[% d.ps2_type | html_entity %]]: [% d.ps2_status | html_entity %]</td>
|
<br/>PS2 [[% d.ps2_type | html_entity %]]: [% d.ps2_status | html_entity %]</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
[% IF d.power_modules.size %]
|
||||||
|
<tr>
|
||||||
|
<td>PoE Status</td>
|
||||||
|
<td>
|
||||||
|
[% FOREACH m IN d.power_modules %]
|
||||||
|
[% UNLESS m.module == 1 %]
|
||||||
|
<br/>
|
||||||
|
[% END %]
|
||||||
|
Module [% m.module %]: [% m.status | html_entity %], [% m.capable_ports %] power-capable ports, [% m.powered_ports %] powered ([% m.disabled_ports %] admin disabled, [% m.errored_ports %] errors), [% m.pwr_committed %]/[% m.power %] watts committed.
|
||||||
|
[% END %]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
[% END %]
|
||||||
<tr>
|
<tr>
|
||||||
<td>MAC Address</td>
|
<td>MAC Address</td>
|
||||||
<td>[% d.mac | html_entity %]</td>
|
<td>[% d.mac | html_entity %]</td>
|
||||||
|
|||||||
60
Netdisco/share/views/ajax/report/devicepoestatus.tt
Normal file
60
Netdisco/share/views/ajax/report/devicepoestatus.tt
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
[% USE Number.Format %]
|
||||||
|
<div class="accordion" id="accordion-radio-pwr">
|
||||||
|
[% count = 0 %]
|
||||||
|
[% FOREACH row IN results %]
|
||||||
|
[% NEXT UNLESS row.power_modules.size %]
|
||||||
|
[% count = count + 1 %]
|
||||||
|
<div class="accordion-group">
|
||||||
|
<div class="accordion-heading">
|
||||||
|
<a class="accordion-toggle" data-toggle="collapse" data-target="#collapse-[% count %]" href="#collapse-[% count %]">
|
||||||
|
<i class="icon-chevron-down"></i>
|
||||||
|
[% row.dns || row.name %]
|
||||||
|
( [% row.model %] )
|
||||||
|
[% IF row.location %]
|
||||||
|
Location: [% row.location %]
|
||||||
|
[% END %]
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div id="collapse-[% count %]" class="accordion-body collapse in">
|
||||||
|
<div class="accordion-inner">
|
||||||
|
<table class="table table-bordered table-condensed">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>PoE<br>Module</th>
|
||||||
|
<th class="nd_center-cell">Power<br>(W)</th>
|
||||||
|
<th class="nd_center-cell">Supply</th>
|
||||||
|
<th class="nd_center-cell">Capable<br>Ports</th>
|
||||||
|
<th class="nd_center-cell">Powered<br>Ports</th>
|
||||||
|
<th class="nd_center-cell">Disabled<br>Ports</th>
|
||||||
|
<th class="nd_center-cell">Errored<br>Ports</th>
|
||||||
|
<th class="nd_center-cell">Committed<br>(W)</th>
|
||||||
|
<th class="nd_center-cell">Delivering<br>(W)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
[% FOREACH m IN row.power_modules %]
|
||||||
|
<tr>
|
||||||
|
<td class="nd_center-cell">[% m.module %]</td>
|
||||||
|
<td class="nd_center-cell">[% m.power | format_number %]</td>
|
||||||
|
<td class="nd_center-cell">[% m.status %]</td>
|
||||||
|
<td class="nd_center-cell">[% m.capable_ports %]</td>
|
||||||
|
<td class="nd_center-cell">[% m.powered_ports %]</td>
|
||||||
|
<td class="nd_center-cell">[% m.disabled_ports %]</td>
|
||||||
|
<td class="nd_center-cell">[% m.errored_ports %]</td>
|
||||||
|
<td class="nd_center-cell">[% m.pwr_committed | format_number %]</td>
|
||||||
|
<td class="nd_center-cell">[% m.pwr_delivering | format_number %]</td>
|
||||||
|
</tr>
|
||||||
|
[% END %]
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
[%END%]
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$('.accordion').on('show hide', function (n) {
|
||||||
|
$(n.target).siblings('.accordion-heading').find('.accordion-toggle i').toggleClass('icon-chevron-up icon-chevron-down');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
25
Netdisco/share/views/ajax/report/devicepoestatus_csv.tt
Normal file
25
Netdisco/share/views/ajax/report/devicepoestatus_csv.tt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
[% USE CSV -%]
|
||||||
|
[% CSV.dump([ 'Device' 'Model' 'Device Location' 'PoE Module' 'Power (W)'
|
||||||
|
'Supply' 'Capable Ports' 'Powered Ports' 'Disabled Ports'
|
||||||
|
'Errored Ports' 'Committed (W)' 'Delivering (W)' ]) %]
|
||||||
|
|
||||||
|
[% FOREACH row IN results %]
|
||||||
|
[% NEXT UNLESS row.power_modules.size %]
|
||||||
|
[% mydlist = [] %]
|
||||||
|
[% mydevice = row.dns || row.name %]
|
||||||
|
[% mydlist.push(mydevice) %]
|
||||||
|
[% mydlist.push(row.model) %]
|
||||||
|
[% mydlist.push(row.location) %]
|
||||||
|
[% FOREACH m IN row.power_modules %]
|
||||||
|
[% myplist = [] %]
|
||||||
|
[% FOREACH col IN [ m.module m.power m.status m.capable_ports
|
||||||
|
m.powered_ports m.disabled_ports m.errored_ports
|
||||||
|
m.pwr_committed m.pwr_delivering
|
||||||
|
] %]
|
||||||
|
[% myplist.push(col) %]
|
||||||
|
[% END %]
|
||||||
|
[% CALL mydlist.splice(3, 9, myplist ) %]
|
||||||
|
[% CSV.dump(mydlist) %]
|
||||||
|
|
||||||
|
[% END %]
|
||||||
|
[%END%]
|
||||||
Reference in New Issue
Block a user