From cb9abc2355f6cb07f5b3763833cfe8bf2ac670bf Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Wed, 1 Jan 2014 15:21:23 +0000 Subject: [PATCH] Subnet Utilization report --- Netdisco/Changes | 1 + .../DB/Result/Virtual/SubnetUtilization.pm | 48 +++++++++++++++++++ .../Web/Plugin/Report/SubnetUtilization.pm | 37 ++++++++++++++ Netdisco/share/config.yml | 1 + .../share/views/ajax/admintask/slowdevices.tt | 2 +- Netdisco/share/views/ajax/report/subnets.tt | 25 ++++++++++ .../share/views/ajax/report/subnets_csv.tt | 14 ++++++ Netdisco/share/views/js/common.js | 2 +- .../share/views/sidebar/report/subnets.tt | 28 +++++++++++ 9 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 Netdisco/lib/App/Netdisco/DB/Result/Virtual/SubnetUtilization.pm create mode 100644 Netdisco/lib/App/Netdisco/Web/Plugin/Report/SubnetUtilization.pm create mode 100644 Netdisco/share/views/ajax/report/subnets.tt create mode 100644 Netdisco/share/views/ajax/report/subnets_csv.tt create mode 100644 Netdisco/share/views/sidebar/report/subnets.tt diff --git a/Netdisco/Changes b/Netdisco/Changes index 708e78a6..035774b7 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -9,6 +9,7 @@ * [#19] Ask for Reason when changing Port up/down Status, or VLAN * [#30] Support for expire_devices, expire_nodes, and expire_nodes_archive * Port Log viewable via an icon by device port name (Port Control rights req'd) + * [#1] Subnet Utilization report (J. van Ingen) [ENHANCEMENTS] diff --git a/Netdisco/lib/App/Netdisco/DB/Result/Virtual/SubnetUtilization.pm b/Netdisco/lib/App/Netdisco/DB/Result/Virtual/SubnetUtilization.pm new file mode 100644 index 00000000..32c97f63 --- /dev/null +++ b/Netdisco/lib/App/Netdisco/DB/Result/Virtual/SubnetUtilization.pm @@ -0,0 +1,48 @@ +package App::Netdisco::DB::Result::Virtual::SubnetUtilization; + +use strict; +use warnings; + +use utf8; +use base 'DBIx::Class::Core'; + +__PACKAGE__->table_class('DBIx::Class::ResultSource::View'); + +__PACKAGE__->table('cidr_ips'); +__PACKAGE__->result_source_instance->is_virtual(1); +__PACKAGE__->result_source_instance->view_definition(<<'ENDSQL'); + SELECT net as subnet, + power(2, (32 - masklen(net))) as subnet_size, + count(DISTINCT ip) as active, + round(100 * count(DISTINCT ip) / power(2, (32 - masklen(net)))) as percent + FROM ( + SELECT DISTINCT net, ni.ip + FROM subnets s1, node_ip ni + WHERE s1.net <<= ?::cidr + AND ni.ip <<= s1.net + AND ni.time_last > (now() - ?::interval) + AND s1.last_discover > (now() - ?::interval) + UNION + SELECT DISTINCT net, di.alias as ip + FROM subnets s2, device_ip di JOIN device d USING (ip) + WHERE s2.net <<= ?::cidr + AND di.alias <<= s2.net + AND s2.last_discover > (now() - ?::interval) + AND d.last_discover > (now() - ?::interval) + ) as joined + GROUP BY net + ORDER BY percent ASC +ENDSQL + +__PACKAGE__->add_columns( + "subnet", + { data_type => "cidr", is_nullable => 0 }, + "subnet_size", + { data_type => "integer", is_nullable => 0 }, + "active", + { data_type => "integer", is_nullable => 0 }, + "percent", + { data_type => "integer", is_nullable => 0 }, +); + +1; diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Report/SubnetUtilization.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Report/SubnetUtilization.pm new file mode 100644 index 00000000..9fcecc52 --- /dev/null +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Report/SubnetUtilization.pm @@ -0,0 +1,37 @@ +package App::Netdisco::Web::Plugin::Report::SubnetUtilization; + +use Dancer ':syntax'; +use Dancer::Plugin::DBIC; +use Dancer::Plugin::Auth::Extensible; + +use App::Netdisco::Web::Plugin; + +register_report({ + category => 'IP', + tag => 'subnets', + label => 'Subnet Utilization', + provides_csv => 1, +}); + +get '/ajax/content/report/subnets' => require_login sub { + my $subnet = param('subnet') || '0.0.0.0/32'; + my $age = param('age') || '7 days'; + $age = '7 days' unless $age =~ m/^(?:\d+)\s+(?:day|week|month|year)s?$/; + + my $set = schema('netdisco')->resultset('Virtual::SubnetUtilization') + ->search(undef,{ + bind => [ $subnet, $age, $age, $subnet, $age, $age ], + }); + + if ( request->is_ajax ) { + template 'ajax/report/subnets.tt', { results => $set, }, + { layout => undef }; + } + else { + header( 'Content-Type' => 'text/comma-separated-values' ); + template 'ajax/report/subnets_csv.tt', { results => $set }, + { layout => undef }; + } +}; + +1; diff --git a/Netdisco/share/config.yml b/Netdisco/share/config.yml index db8dae23..9a4efaaa 100644 --- a/Netdisco/share/config.yml +++ b/Netdisco/share/config.yml @@ -50,6 +50,7 @@ web_plugins: - Report::PhonesDiscovered - Report::SsidInventory - Report::VlanInventory + - Report::SubnetUtilization - AdminTask::JobQueue - AdminTask::PollerPerformance - AdminTask::SlowDevices diff --git a/Netdisco/share/views/ajax/admintask/slowdevices.tt b/Netdisco/share/views/ajax/admintask/slowdevices.tt index bb4537cd..219f3957 100644 --- a/Netdisco/share/views/ajax/admintask/slowdevices.tt +++ b/Netdisco/share/views/ajax/admintask/slowdevices.tt @@ -1,5 +1,5 @@ [% IF results.count == 0 %] -
The aren't enough jobs to report.
+
The aren't enough jobs to report.
[% ELSE %] diff --git a/Netdisco/share/views/ajax/report/subnets.tt b/Netdisco/share/views/ajax/report/subnets.tt new file mode 100644 index 00000000..1737208e --- /dev/null +++ b/Netdisco/share/views/ajax/report/subnets.tt @@ -0,0 +1,25 @@ +[% IF results.count == 0 %] +
No matching records.
+[% ELSE %] +
+ + + + + + + + + + [% FOREACH row IN results.all %] + + + + + + + [% END %] + +
SubnetSizeNumber of Active NodesPercent Utilization
[% row.subnet | html_entity %][% row.subnet_size | html_entity %][% row.active | html_entity %][% row.percent | html_entity %]
+[% END %] + diff --git a/Netdisco/share/views/ajax/report/subnets_csv.tt b/Netdisco/share/views/ajax/report/subnets_csv.tt new file mode 100644 index 00000000..39bd9b57 --- /dev/null +++ b/Netdisco/share/views/ajax/report/subnets_csv.tt @@ -0,0 +1,14 @@ +[% USE CSV %] +[% CSV.dump([ 'Subnet' 'Size' 'Number of Active Nodes' 'Percent Utilization' ]) %] + +[% FOREACH row IN results.all %] + [% mylist = [] %] + [% mylist.push(row.subnet) %] + [% mylist.push(row.subnet_size) %] + [% mylist.push(row.active) %] + [% mylist.push(row.percent) %] + [% CSV.dump(mylist) %] + +[% END %] + + diff --git a/Netdisco/share/views/js/common.js b/Netdisco/share/views/js/common.js index 7fea3673..951bd0b8 100644 --- a/Netdisco/share/views/js/common.js +++ b/Netdisco/share/views/js/common.js @@ -128,7 +128,7 @@ // on page load, load the content for the active tab [% IF params.tab %] - [% IF params.tab == 'ipinventory' %] + [% IF params.tab == 'ipinventory' OR params.tab == 'subnets' %] $('#[% params.tab %]_submit').click(); [% ELSE %] $('#[% params.tab %]_form').trigger("submit"); diff --git a/Netdisco/share/views/sidebar/report/subnets.tt b/Netdisco/share/views/sidebar/report/subnets.tt new file mode 100644 index 00000000..3478114b --- /dev/null +++ b/Netdisco/share/views/sidebar/report/subnets.tt @@ -0,0 +1,28 @@ + +
+ +
+ +
+ + + +
+
    +
  • + Activity Period:
    + +
  • +
+
+
+ +