diff --git a/Netdisco/Changes b/Netdisco/Changes index 441e62f0..9c3b19e0 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -7,6 +7,7 @@ * Add Ports with multiple nodes attached report * Add Ports administratively disabled report * Add Ports that are blocking report + * Add Access Point client count report [ENHANCEMENTS] diff --git a/Netdisco/lib/App/Netdisco/DB/Result/DevicePort.pm b/Netdisco/lib/App/Netdisco/DB/Result/DevicePort.pm index c4c0ce41..7ccf135c 100644 --- a/Netdisco/lib/App/Netdisco/DB/Result/DevicePort.pm +++ b/Netdisco/lib/App/Netdisco/DB/Result/DevicePort.pm @@ -152,6 +152,20 @@ __PACKAGE__->might_have( power => 'App::Netdisco::DB::Result::DevicePortPower', 'foreign.ip' => 'self.ip', 'foreign.port' => 'self.port', }); +=head2 wireless + +Returns a row from the C table if one refers to this +device port. + +=cut + +__PACKAGE__->might_have( + wireless => 'App::Netdisco::DB::Result::DevicePortWireless', + { 'foreign.ip' => 'self.ip', + 'foreign.port' => 'self.port', + } +); + =head2 neighbor_alias When a device port has an attached neighbor device, this relationship will diff --git a/Netdisco/lib/App/Netdisco/DB/Result/DevicePortWireless.pm b/Netdisco/lib/App/Netdisco/DB/Result/DevicePortWireless.pm index 7cc6085b..11e2656a 100644 --- a/Netdisco/lib/App/Netdisco/DB/Result/DevicePortWireless.pm +++ b/Netdisco/lib/App/Netdisco/DB/Result/DevicePortWireless.pm @@ -45,5 +45,21 @@ __PACKAGE__->belongs_to( port => 'App::Netdisco::DB::Result::DevicePort', { 'foreign.ip' => 'self.ip', 'foreign.port' => 'self.port', }); +=head2 nodes + +Returns the set of Nodes whose MAC addresses are associated with this Device +Port Wireless. + +=cut + +__PACKAGE__->has_many( nodes => 'App::Netdisco::DB::Result::Node', + { + 'foreign.switch' => 'self.ip', + 'foreign.port' => 'self.port', + }, + { join_type => 'LEFT', + cascade_copy => 0, cascade_update => 0, cascade_delete => 0 }, +); + # You can replace this text with custom code or comments, and it will be preserved on regeneration 1; diff --git a/Netdisco/lib/App/Netdisco/DB/Result/Node.pm b/Netdisco/lib/App/Netdisco/DB/Result/Node.pm index 6b22144c..8aa6a320 100644 --- a/Netdisco/lib/App/Netdisco/DB/Result/Node.pm +++ b/Netdisco/lib/App/Netdisco/DB/Result/Node.pm @@ -83,6 +83,22 @@ __PACKAGE__->belongs_to( device_port => 'App::Netdisco::DB::Result::DevicePort', { join_type => 'LEFT' } ); +=head2 wireless_port + +Returns the single C to which this Node entry was associated at +the time of discovery. + +The JOIN is of type LEFT, in case the C is no longer present in the +database but the relation is being used in C. + +=cut + +__PACKAGE__->belongs_to( + wireless_port => 'App::Netdisco::DB::Result::DeviceWirelessPort', + { 'foreign.ip' => 'self.switch', 'foreign.port' => 'self.port' }, + { join_type => 'LEFT' } +); + =head2 ips Returns the set of C entries associated with this Node. That is, the diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Report/ApClients.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Report/ApClients.pm new file mode 100644 index 00000000..26d7cd10 --- /dev/null +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Report/ApClients.pm @@ -0,0 +1,50 @@ +package App::Netdisco::Web::Plugin::Report::ApClients; + +use Dancer ':syntax'; +use Dancer::Plugin::DBIC; +use Dancer::Plugin::Auth::Extensible; + +use App::Netdisco::Web::Plugin; + +register_report( + { category => 'Wireless', + tag => 'apclients', + label => 'Access Point Client Count', + provides_csv => 1, + } +); + +get '/ajax/content/report/apclients' => require_login sub { + my @results = schema('netdisco')->resultset('Device')->search( + { 'nodes.time_last' => { '>=', \'me.last_macsuck' } }, + { result_class => 'DBIx::Class::ResultClass::HashRefInflator', + select => [ 'ip', 'dns', 'name', 'model', 'location' ], + join => { 'ports' => { 'wireless' => 'nodes' } }, + '+columns' => [ + { 'port' => 'ports.port' }, + { 'description' => 'ports.name' }, + { 'mac_count' => { count => 'nodes.mac' } }, + ], + group_by => [ + 'me.ip', 'me.dns', 'me.name', 'me.model', + 'me.location', 'ports.port', 'ports.descr', 'ports.name' + ], + order_by => { -desc => [qw/count/] }, + } + )->all; + + return unless scalar @results; + + if ( request->is_ajax ) { + template 'ajax/report/portmultinodes.tt', { results => \@results, }, + { layout => undef }; + } + else { + header( 'Content-Type' => 'text/comma-separated-values' ); + template 'ajax/report/portmultinodes_csv.tt', + { results => \@results, }, + { layout => undef }; + } +}; + +1; diff --git a/Netdisco/share/config.yml b/Netdisco/share/config.yml index 36be210d..a9846c88 100644 --- a/Netdisco/share/config.yml +++ b/Netdisco/share/config.yml @@ -38,6 +38,7 @@ web_plugins: - Report::PortMultiNodes - Report::PortUtilization - Report::ApChannelDist + - Report::ApClients - Report::ApRadioChannelPower - Report::HalfDuplex - Report::DeviceAddrNoDNS