Merge branch 'master' of ssh://git.code.sf.net/p/netdisco/netdisco-ng
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
2.029015
|
2.029015
|
||||||
|
|
||||||
|
[NEW FEATURES]
|
||||||
|
|
||||||
|
* [#4] Allow comment on device port in the log, for any user
|
||||||
|
* [#18] Inventory by Model by OS Report
|
||||||
|
|
||||||
[ENHANCEMENTS]
|
[ENHANCEMENTS]
|
||||||
|
|
||||||
* Request net-snmp-devel on Fedora/Red-Hat builds
|
* Request net-snmp-devel on Fedora/Red-Hat builds
|
||||||
@@ -10,6 +15,9 @@
|
|||||||
|
|
||||||
* Fix for node search on some formats of IPv6 addr being seen as MAC
|
* Fix for node search on some formats of IPv6 addr being seen as MAC
|
||||||
* [#190] Ignore entries in the discover form that don't look like IP/hostname
|
* [#190] Ignore entries in the discover form that don't look like IP/hostname
|
||||||
|
* Delete all job queue entries (regardless of status) when deleting device
|
||||||
|
* [#15] Undiscovered Neighbor report JOIN fixed, and updated to include
|
||||||
|
the ports where Macsuck saw the MAC address of a known Device
|
||||||
|
|
||||||
2.029014 - 2014-11-19
|
2.029014 - 2014-11-19
|
||||||
|
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ lib/App/Netdisco/Web/Plugin/Report/DeviceDnsMismatch.pm
|
|||||||
lib/App/Netdisco/Web/Plugin/Report/DevicePoeStatus.pm
|
lib/App/Netdisco/Web/Plugin/Report/DevicePoeStatus.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Report/DuplexMismatch.pm
|
lib/App/Netdisco/Web/Plugin/Report/DuplexMismatch.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Report/HalfDuplex.pm
|
lib/App/Netdisco/Web/Plugin/Report/HalfDuplex.pm
|
||||||
|
lib/App/Netdisco/Web/Plugin/Report/InventoryByModelByOS.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Report/IpInventory.pm
|
lib/App/Netdisco/Web/Plugin/Report/IpInventory.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Report/ModuleInventory.pm
|
lib/App/Netdisco/Web/Plugin/Report/ModuleInventory.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Report/Netbios.pm
|
lib/App/Netdisco/Web/Plugin/Report/Netbios.pm
|
||||||
@@ -341,6 +342,7 @@ share/views/ajax/report/generic_report.tt
|
|||||||
share/views/ajax/report/generic_report_csv.tt
|
share/views/ajax/report/generic_report_csv.tt
|
||||||
share/views/ajax/report/halfduplex.tt
|
share/views/ajax/report/halfduplex.tt
|
||||||
share/views/ajax/report/halfduplex_csv.tt
|
share/views/ajax/report/halfduplex_csv.tt
|
||||||
|
share/views/ajax/report/inventorybymodelbyos.tt
|
||||||
share/views/ajax/report/ipinventory.tt
|
share/views/ajax/report/ipinventory.tt
|
||||||
share/views/ajax/report/ipinventory_csv.tt
|
share/views/ajax/report/ipinventory_csv.tt
|
||||||
share/views/ajax/report/moduleinventory.tt
|
share/views/ajax/report/moduleinventory.tt
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ build_requires:
|
|||||||
ExtUtils::MakeMaker: 6.59
|
ExtUtils::MakeMaker: 6.59
|
||||||
Test::More: 0.88
|
Test::More: 0.88
|
||||||
configure_requires:
|
configure_requires:
|
||||||
DBIx::Class: 0.082801
|
DBIx::Class: '0.082801'
|
||||||
ExtUtils::MakeMaker: 6.59
|
ExtUtils::MakeMaker: 6.59
|
||||||
distribution_type: module
|
distribution_type: module
|
||||||
dynamic_config: 1
|
dynamic_config: 1
|
||||||
generated_by: 'Module::Install version 1.06'
|
generated_by: 'Module::Install version 1.12'
|
||||||
license: bsd
|
license: bsd
|
||||||
meta-spec:
|
meta-spec:
|
||||||
url: http://module-build.sourceforge.net/META-spec-v1.4.html
|
url: http://module-build.sourceforge.net/META-spec-v1.4.html
|
||||||
@@ -39,7 +39,7 @@ requires:
|
|||||||
DBIx::Class: 0.08281
|
DBIx::Class: 0.08281
|
||||||
DBIx::Class::Helpers: 2.024
|
DBIx::Class::Helpers: 2.024
|
||||||
Daemon::Control: 0.001006
|
Daemon::Control: 0.001006
|
||||||
Dancer: 1.3132
|
Dancer: '1.3132'
|
||||||
Dancer::Plugin::Auth::Extensible: 0.3
|
Dancer::Plugin::Auth::Extensible: 0.3
|
||||||
Dancer::Plugin::DBIC: 0.2001
|
Dancer::Plugin::DBIC: 0.2001
|
||||||
Dancer::Plugin::Passphrase: 2.0.1
|
Dancer::Plugin::Passphrase: 2.0.1
|
||||||
@@ -68,7 +68,7 @@ requires:
|
|||||||
Plack::Middleware::ReverseProxy: 0.15
|
Plack::Middleware::ReverseProxy: 0.15
|
||||||
Role::Tiny: 1.002005
|
Role::Tiny: 1.002005
|
||||||
SNMP::Info: 3.18
|
SNMP::Info: 3.18
|
||||||
SQL::Translator: 0.11018
|
SQL::Translator: '0.11018'
|
||||||
Sereal: 0
|
Sereal: 0
|
||||||
Socket6: 0.23
|
Socket6: 0.23
|
||||||
Starman: 0.4008
|
Starman: 0.4008
|
||||||
@@ -91,4 +91,4 @@ resources:
|
|||||||
homepage: http://netdisco.org/
|
homepage: http://netdisco.org/
|
||||||
license: http://opensource.org/licenses/bsd-license.php
|
license: http://opensource.org/licenses/bsd-license.php
|
||||||
repository: git://git.code.sf.net/p/netdisco/netdisco-ng
|
repository: git://git.code.sf.net/p/netdisco/netdisco-ng
|
||||||
version: 2.029014
|
version: '2.029014'
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ package Module::Install;
|
|||||||
# 3. The ./inc/ version of Module::Install loads
|
# 3. The ./inc/ version of Module::Install loads
|
||||||
# }
|
# }
|
||||||
|
|
||||||
use 5.005;
|
use 5.006;
|
||||||
use strict 'vars';
|
use strict 'vars';
|
||||||
use Cwd ();
|
use Cwd ();
|
||||||
use File::Find ();
|
use File::Find ();
|
||||||
@@ -31,7 +31,7 @@ BEGIN {
|
|||||||
# This is not enforced yet, but will be some time in the next few
|
# This is not enforced yet, but will be some time in the next few
|
||||||
# releases once we can make sure it won't clash with custom
|
# releases once we can make sure it won't clash with custom
|
||||||
# Module::Install extensions.
|
# Module::Install extensions.
|
||||||
$VERSION = '1.06';
|
$VERSION = '1.12';
|
||||||
|
|
||||||
# Storage for the pseudo-singleton
|
# Storage for the pseudo-singleton
|
||||||
$MAIN = undef;
|
$MAIN = undef;
|
||||||
@@ -156,10 +156,10 @@ END_DIE
|
|||||||
sub autoload {
|
sub autoload {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $who = $self->_caller;
|
my $who = $self->_caller;
|
||||||
my $cwd = Cwd::cwd();
|
my $cwd = Cwd::getcwd();
|
||||||
my $sym = "${who}::AUTOLOAD";
|
my $sym = "${who}::AUTOLOAD";
|
||||||
$sym->{$cwd} = sub {
|
$sym->{$cwd} = sub {
|
||||||
my $pwd = Cwd::cwd();
|
my $pwd = Cwd::getcwd();
|
||||||
if ( my $code = $sym->{$pwd} ) {
|
if ( my $code = $sym->{$pwd} ) {
|
||||||
# Delegate back to parent dirs
|
# Delegate back to parent dirs
|
||||||
goto &$code unless $cwd eq $pwd;
|
goto &$code unless $cwd eq $pwd;
|
||||||
@@ -239,7 +239,7 @@ sub new {
|
|||||||
|
|
||||||
# ignore the prefix on extension modules built from top level.
|
# ignore the prefix on extension modules built from top level.
|
||||||
my $base_path = Cwd::abs_path($FindBin::Bin);
|
my $base_path = Cwd::abs_path($FindBin::Bin);
|
||||||
unless ( Cwd::abs_path(Cwd::cwd()) eq $base_path ) {
|
unless ( Cwd::abs_path(Cwd::getcwd()) eq $base_path ) {
|
||||||
delete $args{prefix};
|
delete $args{prefix};
|
||||||
}
|
}
|
||||||
return $args{_self} if $args{_self};
|
return $args{_self} if $args{_self};
|
||||||
@@ -338,7 +338,7 @@ sub find_extensions {
|
|||||||
if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) {
|
if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) {
|
||||||
my $content = Module::Install::_read($subpath . '.pm');
|
my $content = Module::Install::_read($subpath . '.pm');
|
||||||
my $in_pod = 0;
|
my $in_pod = 0;
|
||||||
foreach ( split //, $content ) {
|
foreach ( split /\n/, $content ) {
|
||||||
$in_pod = 1 if /^=\w/;
|
$in_pod = 1 if /^=\w/;
|
||||||
$in_pod = 0 if /^=cut/;
|
$in_pod = 0 if /^=cut/;
|
||||||
next if ($in_pod || /^=cut/); # skip pod text
|
next if ($in_pod || /^=cut/); # skip pod text
|
||||||
@@ -434,7 +434,7 @@ END_OLD
|
|||||||
|
|
||||||
# _version is for processing module versions (eg, 1.03_05) not
|
# _version is for processing module versions (eg, 1.03_05) not
|
||||||
# Perl versions (eg, 5.8.1).
|
# Perl versions (eg, 5.8.1).
|
||||||
sub _version ($) {
|
sub _version {
|
||||||
my $s = shift || 0;
|
my $s = shift || 0;
|
||||||
my $d =()= $s =~ /(\.)/g;
|
my $d =()= $s =~ /(\.)/g;
|
||||||
if ( $d >= 2 ) {
|
if ( $d >= 2 ) {
|
||||||
@@ -450,12 +450,12 @@ sub _version ($) {
|
|||||||
return $l + 0;
|
return $l + 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _cmp ($$) {
|
sub _cmp {
|
||||||
_version($_[1]) <=> _version($_[2]);
|
_version($_[1]) <=> _version($_[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Cloned from Params::Util::_CLASS
|
# Cloned from Params::Util::_CLASS
|
||||||
sub _CLASS ($) {
|
sub _CLASS {
|
||||||
(
|
(
|
||||||
defined $_[0]
|
defined $_[0]
|
||||||
and
|
and
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ package Module::Install::Base;
|
|||||||
use strict 'vars';
|
use strict 'vars';
|
||||||
use vars qw{$VERSION};
|
use vars qw{$VERSION};
|
||||||
BEGIN {
|
BEGIN {
|
||||||
$VERSION = '1.06';
|
$VERSION = '1.12';
|
||||||
}
|
}
|
||||||
|
|
||||||
# Suspend handler for "redefined" warnings
|
# Suspend handler for "redefined" warnings
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use Module::Install::Base ();
|
|||||||
|
|
||||||
use vars qw{$VERSION @ISA $ISCORE};
|
use vars qw{$VERSION @ISA $ISCORE};
|
||||||
BEGIN {
|
BEGIN {
|
||||||
$VERSION = '1.06';
|
$VERSION = '1.12';
|
||||||
@ISA = 'Module::Install::Base';
|
@ISA = 'Module::Install::Base';
|
||||||
$ISCORE = 1;
|
$ISCORE = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use Module::Install::Base ();
|
|||||||
|
|
||||||
use vars qw{$VERSION @ISA $ISCORE};
|
use vars qw{$VERSION @ISA $ISCORE};
|
||||||
BEGIN {
|
BEGIN {
|
||||||
$VERSION = '1.06';
|
$VERSION = '1.12';
|
||||||
@ISA = 'Module::Install::Base';
|
@ISA = 'Module::Install::Base';
|
||||||
$ISCORE = 1;
|
$ISCORE = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use Fcntl qw/:flock :seek/;
|
|||||||
|
|
||||||
use vars qw{$VERSION @ISA $ISCORE};
|
use vars qw{$VERSION @ISA $ISCORE};
|
||||||
BEGIN {
|
BEGIN {
|
||||||
$VERSION = '1.06';
|
$VERSION = '1.12';
|
||||||
@ISA = 'Module::Install::Base';
|
@ISA = 'Module::Install::Base';
|
||||||
$ISCORE = 1;
|
$ISCORE = 1;
|
||||||
}
|
}
|
||||||
@@ -133,7 +133,7 @@ sub makemaker_args {
|
|||||||
return $args;
|
return $args;
|
||||||
}
|
}
|
||||||
|
|
||||||
# For mm args that take multiple space-seperated args,
|
# For mm args that take multiple space-separated args,
|
||||||
# append an argument to the current list.
|
# append an argument to the current list.
|
||||||
sub makemaker_append {
|
sub makemaker_append {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use Module::Install::Base ();
|
|||||||
|
|
||||||
use vars qw{$VERSION @ISA $ISCORE};
|
use vars qw{$VERSION @ISA $ISCORE};
|
||||||
BEGIN {
|
BEGIN {
|
||||||
$VERSION = '1.06';
|
$VERSION = '1.12';
|
||||||
@ISA = 'Module::Install::Base';
|
@ISA = 'Module::Install::Base';
|
||||||
$ISCORE = 1;
|
$ISCORE = 1;
|
||||||
}
|
}
|
||||||
@@ -347,7 +347,7 @@ sub name_from {
|
|||||||
^ \s*
|
^ \s*
|
||||||
package \s*
|
package \s*
|
||||||
([\w:]+)
|
([\w:]+)
|
||||||
\s* ;
|
[\s|;]*
|
||||||
/ixms
|
/ixms
|
||||||
) {
|
) {
|
||||||
my ($name, $module_name) = ($1, $1);
|
my ($name, $module_name) = ($1, $1);
|
||||||
@@ -705,7 +705,7 @@ sub _write_mymeta_data {
|
|||||||
my @yaml = Parse::CPAN::Meta::LoadFile('META.yml');
|
my @yaml = Parse::CPAN::Meta::LoadFile('META.yml');
|
||||||
my $meta = $yaml[0];
|
my $meta = $yaml[0];
|
||||||
|
|
||||||
# Overwrite the non-configure dependency hashs
|
# Overwrite the non-configure dependency hashes
|
||||||
delete $meta->{requires};
|
delete $meta->{requires};
|
||||||
delete $meta->{build_requires};
|
delete $meta->{build_requires};
|
||||||
delete $meta->{recommends};
|
delete $meta->{recommends};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use Module::Install::Base ();
|
|||||||
|
|
||||||
use vars qw{$VERSION @ISA $ISCORE};
|
use vars qw{$VERSION @ISA $ISCORE};
|
||||||
BEGIN {
|
BEGIN {
|
||||||
$VERSION = '1.06';
|
$VERSION = '1.12';
|
||||||
@ISA = 'Module::Install::Base';
|
@ISA = 'Module::Install::Base';
|
||||||
$ISCORE = 1;
|
$ISCORE = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use ExtUtils::Manifest ();
|
|||||||
|
|
||||||
use vars qw{$VERSION @ISA $ISCORE};
|
use vars qw{$VERSION @ISA $ISCORE};
|
||||||
BEGIN {
|
BEGIN {
|
||||||
$VERSION = '1.06';
|
$VERSION = '1.12';
|
||||||
@ISA = 'Module::Install::Base';
|
@ISA = 'Module::Install::Base';
|
||||||
$ISCORE = 1;
|
$ISCORE = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use Module::Install::Base ();
|
|||||||
|
|
||||||
use vars qw{$VERSION @ISA $ISCORE};
|
use vars qw{$VERSION @ISA $ISCORE};
|
||||||
BEGIN {
|
BEGIN {
|
||||||
$VERSION = '1.06';
|
$VERSION = '1.12';
|
||||||
@ISA = 'Module::Install::Base';
|
@ISA = 'Module::Install::Base';
|
||||||
$ISCORE = 1;
|
$ISCORE = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use Module::Install::Base ();
|
|||||||
|
|
||||||
use vars qw{$VERSION @ISA $ISCORE};
|
use vars qw{$VERSION @ISA $ISCORE};
|
||||||
BEGIN {
|
BEGIN {
|
||||||
$VERSION = '1.06';
|
$VERSION = '1.12';
|
||||||
@ISA = qw{Module::Install::Base};
|
@ISA = qw{Module::Install::Base};
|
||||||
$ISCORE = 1;
|
$ISCORE = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,6 +160,16 @@ __PACKAGE__->has_many( active_nodes_with_age => 'App::Netdisco::DB::Result::Virt
|
|||||||
cascade_copy => 0, cascade_update => 0, cascade_delete => 0 },
|
cascade_copy => 0, cascade_update => 0, cascade_delete => 0 },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
=head2 logs
|
||||||
|
|
||||||
|
Returns the set of C<device_port_log> entries associated with this Port.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->has_many( logs => 'App::Netdisco::DB::Result::DevicePortLog',
|
||||||
|
{ 'foreign.ip' => 'self.ip', 'foreign.port' => 'self.port' },
|
||||||
|
);
|
||||||
|
|
||||||
=head2 power
|
=head2 power
|
||||||
|
|
||||||
Returns a row from the C<device_port_power> table if one refers to this
|
Returns a row from the C<device_port_power> table if one refers to this
|
||||||
@@ -345,4 +355,16 @@ Returns the C<mac> column instantiated into a L<NetAddr::MAC> object.
|
|||||||
|
|
||||||
sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
|
sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
|
||||||
|
|
||||||
|
=head2 last_comment
|
||||||
|
|
||||||
|
Returns the most recent comment from the logs for this device port.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub last_comment {
|
||||||
|
my $row = (shift)->logs->search(undef,
|
||||||
|
{ order_by => { -desc => 'creation' }, rows => 1 })->first;
|
||||||
|
return ($row ? $row->log : '');
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -22,14 +22,17 @@ __PACKAGE__->result_source_instance->view_definition(<<'ENDSQL');
|
|||||||
a.log,
|
a.log,
|
||||||
a.finished
|
a.finished
|
||||||
FROM device_port p
|
FROM device_port p
|
||||||
JOIN device d ON d.ip = p.ip
|
JOIN device d
|
||||||
JOIN ADMIN a ON p.remote_ip = a.device
|
ON d.ip = p.ip
|
||||||
WHERE p.remote_ip NOT IN
|
LEFT JOIN admin a
|
||||||
(SELECT ALIAS
|
ON (p.remote_ip = a.device AND a.action = 'discover')
|
||||||
FROM device_ip)
|
WHERE
|
||||||
AND a.action = 'discover'
|
(p.remote_ip NOT IN (SELECT alias FROM device_ip))
|
||||||
ORDER BY p.remote_ip,
|
OR
|
||||||
a.finished DESC
|
((p.remote_ip IS NULL) AND p.is_uplink)
|
||||||
|
ORDER BY
|
||||||
|
p.remote_ip ASC,
|
||||||
|
a.finished DESC
|
||||||
ENDSQL
|
ENDSQL
|
||||||
|
|
||||||
__PACKAGE__->add_columns(
|
__PACKAGE__->add_columns(
|
||||||
|
|||||||
@@ -594,7 +594,6 @@ sub delete {
|
|||||||
|
|
||||||
$schema->resultset('Admin')->search({
|
$schema->resultset('Admin')->search({
|
||||||
device => { '-in' => $devices->as_query },
|
device => { '-in' => $devices->as_query },
|
||||||
action => { '-like' => 'queued%' },
|
|
||||||
})->delete;
|
})->delete;
|
||||||
|
|
||||||
$schema->resultset('Topology')->search({
|
$schema->resultset('Topology')->search({
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ sub delete {
|
|||||||
DevicePortVlan
|
DevicePortVlan
|
||||||
DevicePortWireless
|
DevicePortWireless
|
||||||
DevicePortSsid
|
DevicePortSsid
|
||||||
|
DevicePortLog
|
||||||
/) {
|
/) {
|
||||||
$schema->resultset($set)->search(
|
$schema->resultset($set)->search(
|
||||||
{ ip => { '-in' => $ports->as_query }},
|
{ ip => { '-in' => $ports->as_query }},
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ hook 'before' => sub {
|
|||||||
|
|
||||||
my @default_port_columns_right = (
|
my @default_port_columns_right = (
|
||||||
{ name => 'c_descr', label => 'Description', default => '' },
|
{ name => 'c_descr', label => 'Description', default => '' },
|
||||||
|
{ name => 'c_comment', label => 'Last Comment', default => '' },
|
||||||
{ name => 'c_type', label => 'Type', default => '' },
|
{ name => 'c_type', label => 'Type', default => '' },
|
||||||
{ name => 'c_duplex', label => 'Duplex', default => '' },
|
{ name => 'c_duplex', label => 'Duplex', default => '' },
|
||||||
{ name => 'c_lastchange', label => 'Last Change', default => '' },
|
{ name => 'c_lastchange', label => 'Last Change', default => '' },
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package App::Netdisco::Web::Plugin::Report::InventoryByModelByOS;
|
||||||
|
|
||||||
|
use Dancer ':syntax';
|
||||||
|
use Dancer::Plugin::DBIC;
|
||||||
|
use Dancer::Plugin::Auth::Extensible;
|
||||||
|
|
||||||
|
use App::Netdisco::Web::Plugin;
|
||||||
|
|
||||||
|
register_report(
|
||||||
|
{ category => 'Device',
|
||||||
|
tag => 'inventorybymodelbyos',
|
||||||
|
label => 'Inventory by Model by OS',
|
||||||
|
provides_csv => 0,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
get '/ajax/content/report/inventorybymodelbyos' => require_login sub {
|
||||||
|
my @results = schema('netdisco')->resultset('Device')->search(undef, {
|
||||||
|
columns => [qw/vendor model os os_ver/],
|
||||||
|
select => [ { count => 'os_ver' } ],
|
||||||
|
as => [qw/ os_ver_count /],
|
||||||
|
group_by => [qw/ vendor model os os_ver /],
|
||||||
|
order_by => ['vendor', 'model', { -desc => 'count' }, 'os_ver'],
|
||||||
|
})->hri->all;
|
||||||
|
|
||||||
|
template 'ajax/report/inventorybymodelbyos.tt', { results => \@results, },
|
||||||
|
{ layout => undef };
|
||||||
|
};
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -14,6 +14,32 @@ register_report({
|
|||||||
hidden => true,
|
hidden => true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sub _sanity_ok {
|
||||||
|
return 0 unless
|
||||||
|
param('ip') =~ m/^[[:print:]]+$/
|
||||||
|
and param('port') =~ m/^[[:print:]]+$/
|
||||||
|
and param('log') =~ m/^[[:print:]]+$/;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ajax '/ajax/control/report/portlog/add' => require_login sub {
|
||||||
|
send_error('Bad Request', 400) unless _sanity_ok();
|
||||||
|
|
||||||
|
schema('netdisco')->txn_do(sub {
|
||||||
|
my $user = schema('netdisco')->resultset('DevicePortLog')
|
||||||
|
->create({
|
||||||
|
ip => param('ip'),
|
||||||
|
port => param('port'),
|
||||||
|
reason => 'other',
|
||||||
|
log => param('log'),
|
||||||
|
username => session('logged_in_user'),
|
||||||
|
userip => request->remote_address,
|
||||||
|
action => 'comment',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
ajax '/ajax/content/report/portlog' => require_role port_control => sub {
|
ajax '/ajax/content/report/portlog' => require_role port_control => sub {
|
||||||
my $device = param('q');
|
my $device = param('q');
|
||||||
my $port = param('f');
|
my $port = param('f');
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ web_plugins:
|
|||||||
- Report::HalfDuplex
|
- Report::HalfDuplex
|
||||||
- Report::DeviceAddrNoDNS
|
- Report::DeviceAddrNoDNS
|
||||||
- Report::DeviceByLocation
|
- Report::DeviceByLocation
|
||||||
|
- Report::InventoryByModelByOS
|
||||||
- Report::DeviceDnsMismatch
|
- Report::DeviceDnsMismatch
|
||||||
- Report::DevicePoeStatus
|
- Report::DevicePoeStatus
|
||||||
- Report::DuplexMismatch
|
- Report::DuplexMismatch
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<table id="data-table" class="table table-striped table-bordered" width="100%" cellspacing="0">
|
<table id="data-table" class="table table-striped table-bordered" width="100%" cellspacing="0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Device Location Triggering<br>Last Discovery Attempt</th>
|
<th>Observing Device</th>
|
||||||
<th>Undiscovered Neighbor</th>
|
<th>Undiscovered Neighbor</th>
|
||||||
<th class="nd_center-cell">Last Discovery Attempt</th>
|
<th class="nd_center-cell">Last Discovery Attempt</th>
|
||||||
<th class="nd_center-cell">Last Discovery Log</th>
|
<th class="nd_center-cell">Last Discovery Log</th>
|
||||||
@@ -12,11 +12,18 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><a href="[% device_ports %]&q=[% row.ip | uri %]&f=[% row.port | uri %]">
|
<td><a href="[% device_ports %]&q=[% row.ip | uri %]&f=[% row.port | uri %]">
|
||||||
[% row.dns || row.name || row.ip | html_entity %] ( [% row.port | html_entity %] ) </a></td>
|
[% row.dns || row.name || row.ip | html_entity %] ( [% row.port | html_entity %] ) </a></td>
|
||||||
<td><a href="[% search_node %]&q=[% row.remote_ip | uri %]">
|
<td>
|
||||||
[% row.remote_ip | html_entity %]</a>
|
[% IF row.remote_ip %]
|
||||||
([% row.remote_port | html_entity %])
|
<a href="[% search_node %]&q=[% row.remote_ip | uri %]">
|
||||||
[% ' id: '_ row.remote_id IF row.remote_id %]
|
[% row.remote_ip | html_entity %]
|
||||||
[% ' type: '_ row.remote_type IF row.remote_type %]</td>
|
</a> ([% row.remote_port | html_entity %])
|
||||||
|
[% '<br />' IF row.remote_id or row.remote_type %]
|
||||||
|
[% ' id: '_ row.remote_id IF row.remote_id %]
|
||||||
|
[% ' type: '_ row.remote_type IF row.remote_type %]
|
||||||
|
[% ELSE %]
|
||||||
|
Known Device's MAC Address seen on this Port during Macsuck
|
||||||
|
[% END %]
|
||||||
|
</td>
|
||||||
<td class="nd_center-cell">[% row.finished | html_entity %]</td>
|
<td class="nd_center-cell">[% row.finished | html_entity %]</td>
|
||||||
<td class="nd_center-cell">[% row.log | html_entity %]</td>
|
<td class="nd_center-cell">[% row.log | html_entity %]</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[% USE CSV -%]
|
[% USE CSV -%]
|
||||||
[% CSV.dump([ 'Device Triggering Last Discovery Attempt' 'Device Port'
|
[% CSV.dump([ 'Observing Device' 'Device Port'
|
||||||
'Remote IP' 'Remote Port' 'Remote ID' 'Remote Type'
|
'Remote IP' 'Remote Port' 'Remote ID' 'Remote Type'
|
||||||
'Last Discovery Attempt' 'Discovery Log']) %]
|
'Last Discovery Attempt' 'Discovery Log']) %]
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,10 @@
|
|||||||
rel="tooltip" data-placement="top" data-offset="3"
|
rel="tooltip" data-placement="top" data-offset="3"
|
||||||
data-animation="" data-title="Enable Port"></i>
|
data-animation="" data-title="Enable Port"></i>
|
||||||
</span>
|
</span>
|
||||||
|
[% END %]
|
||||||
|
[% ELSE %]
|
||||||
|
<td nowrap class="nd_editable-cell"
|
||||||
|
data-order="[% row.port | html_entity %]" data-filter="[% row.port | html_entity %]">
|
||||||
[% END %]
|
[% END %]
|
||||||
<a class="nd_log-icon"
|
<a class="nd_log-icon"
|
||||||
href="[% uri_for('/report/portlog') %]?q=[% device.ip | uri %]&f=[% row.port | uri %]">
|
href="[% uri_for('/report/portlog') %]?q=[% device.ip | uri %]&f=[% row.port | uri %]">
|
||||||
@@ -89,9 +93,6 @@
|
|||||||
rel="tooltip" data-placement="top" data-offset="3"
|
rel="tooltip" data-placement="top" data-offset="3"
|
||||||
data-animation="" data-title="View Port Log"></i>
|
data-animation="" data-title="View Port Log"></i>
|
||||||
</a>
|
</a>
|
||||||
[% ELSE %]
|
|
||||||
<td nowrap data-order="[% row.port | html_entity %]" data-filter="[% row.port | html_entity %]">
|
|
||||||
[% END %]
|
|
||||||
<a class="nd_this-port-only nd_port-only-first" href="[% uri_for('/device',
|
<a class="nd_this-port-only nd_port-only-first" href="[% uri_for('/device',
|
||||||
self_options) %]&q=[% params.q | uri %]&f=[% row.port | uri %]&prefer=port">
|
self_options) %]&q=[% params.q | uri %]&f=[% row.port | uri %]&prefer=port">
|
||||||
[% IF row.is_master %]
|
[% IF row.is_master %]
|
||||||
@@ -121,6 +122,10 @@
|
|||||||
<td nowrap>[% row.descr | html_entity %]</td>
|
<td nowrap>[% row.descr | html_entity %]</td>
|
||||||
[% END %]
|
[% END %]
|
||||||
|
|
||||||
|
[% IF params.c_comment %]
|
||||||
|
<td nowrap>[% row.last_comment | html_entity %]</td>
|
||||||
|
[% END %]
|
||||||
|
|
||||||
[% IF params.c_type %]
|
[% IF params.c_type %]
|
||||||
<td>[% row.type | html_entity %]</td>
|
<td>[% row.type | html_entity %]</td>
|
||||||
[% END %]
|
[% END %]
|
||||||
|
|||||||
@@ -61,6 +61,10 @@
|
|||||||
[% myport.push(row.descr) %]
|
[% myport.push(row.descr) %]
|
||||||
[% END %]
|
[% END %]
|
||||||
|
|
||||||
|
[% IF params.c_comment %]
|
||||||
|
[% myport.push(row.last_comment) %]
|
||||||
|
[% END %]
|
||||||
|
|
||||||
[% IF params.c_type %]
|
[% IF params.c_type %]
|
||||||
[% myport.push(row.type) %]
|
[% myport.push(row.type) %]
|
||||||
[% END %]
|
[% END %]
|
||||||
|
|||||||
71
Netdisco/share/views/ajax/report/inventorybymodelbyos.tt
Normal file
71
Netdisco/share/views/ajax/report/inventorybymodelbyos.tt
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<table id="nsbi-data-table" class="table table-bordered table-hover" width="100%" cellspacing="0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Model</th>
|
||||||
|
<th>Operating System Version</th>
|
||||||
|
<th>Count</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</tbody>
|
||||||
|
[% FOREACH row IN results %]
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="[% search_device %]&q=[% row.model | uri %]&vendor=[% row.vendor | uri %]&model=[% row.model | uri %]">
|
||||||
|
[% row.vendor.ucfirst | html_entity %] [% row.model | html_entity %]</a>
|
||||||
|
[% IF row.os %] running "[% row.os | html_entity %]"[% END %]
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="nd_linkcell"
|
||||||
|
href="[% search_device %]&q=[% row.os_ver | uri %]&vendor=[% row.vendor | uri %]&model=[% row.model | uri %]&os=[% row.os | uri %]&os_ver=[% row.os_ver | uri %]&matchall=on">
|
||||||
|
[% row.os_ver | html_entity %]</a>
|
||||||
|
</td>
|
||||||
|
<td>[% row.os_ver_count | html_entity %]</td>
|
||||||
|
</tr>
|
||||||
|
[% END %]
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
tr.group,
|
||||||
|
tr.group:hover {
|
||||||
|
background-color: #ddd !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
var table = $('#nsbi-data-table').DataTable({
|
||||||
|
"columnDefs": [
|
||||||
|
{ "visible": false, "targets": 0 }
|
||||||
|
],
|
||||||
|
sort: false,
|
||||||
|
"drawCallback": function ( settings ) {
|
||||||
|
var api = this.api();
|
||||||
|
var rows = api.rows( {page:'current'} ).nodes();
|
||||||
|
var last=null;
|
||||||
|
|
||||||
|
api.column(0, {page:'current'} ).data().each( function ( group, i ) {
|
||||||
|
if ( last !== group ) {
|
||||||
|
$(rows).eq( i ).before(
|
||||||
|
'<tr class="group"><td colspan="2">'+group+'</td></tr>'
|
||||||
|
);
|
||||||
|
|
||||||
|
last = group;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
[% INCLUDE 'ajax/datatabledefaults.tt' -%]
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Order by the grouping
|
||||||
|
$('#nsbi-data-table tbody').on( 'click', 'tr.group', function () {
|
||||||
|
var currentOrder = table.order()[0];
|
||||||
|
if ( currentOrder[0] === 0 && currentOrder[1] === 'asc' ) {
|
||||||
|
table.order( [ 0, 'desc' ] ).draw();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
table.order( [ 0, 'asc' ] ).draw();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
</script>
|
||||||
@@ -4,8 +4,8 @@
|
|||||||
[% FOREACH row IN results %]
|
[% FOREACH row IN results %]
|
||||||
[% mylist = [] %]
|
[% mylist = [] %]
|
||||||
[% mylist.push(row.ip) %]
|
[% mylist.push(row.ip) %]
|
||||||
|
[% mylist.push(row.mac) %]
|
||||||
[% mylist.push(row.dns) %]
|
[% mylist.push(row.dns) %]
|
||||||
[% mylist.push(row.time_first) %]
|
|
||||||
[% mylist.push(row.time_last) %]
|
[% mylist.push(row.time_last) %]
|
||||||
[% CSV.dump(mylist) %]
|
[% CSV.dump(mylist) %]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
[% IF results.count == 0 %]
|
|
||||||
<div class="span2 alert alert-info">This port's log is empty.</div>
|
|
||||||
[% ELSE %]
|
|
||||||
<table id="data-table" class="table table-bordered table-condensed table-striped" width="100%" cellspacing="0">
|
<table id="data-table" class="table table-bordered table-condensed table-striped" width="100%" cellspacing="0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -10,9 +7,24 @@
|
|||||||
<th class="nd_center-cell">Action</th>
|
<th class="nd_center-cell">Action</th>
|
||||||
<th class="nd_center-cell">Reason</th>
|
<th class="nd_center-cell">Reason</th>
|
||||||
<th class="nd_center-cell">Log</th>
|
<th class="nd_center-cell">Log</th>
|
||||||
|
<th class="nd_center-cell">Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="nd_center-cell">-</td>
|
||||||
|
<td class="nd_center-cell">[% session.logged_in_user | html_entity %]</td>
|
||||||
|
<td class="nd_center-cell">-</td>
|
||||||
|
<td class="nd_center-cell">comment</td>
|
||||||
|
<td class="nd_center-cell">Other</td>
|
||||||
|
<td class="nd_center-cell"><input data-form="add" class="span4" name="log" type="text" placeholder="Add comment..."></td>
|
||||||
|
<input data-form="add" name="ip" type="hidden" value="[% params.q | html_entity %]">
|
||||||
|
<input data-form="add" name="port" type="hidden" value="[% params.f | html_entity %]">
|
||||||
|
<td class="nd_center-cell">
|
||||||
|
<button class="btn btn-small nd_adminbutton" name="add" type="submit"><i class="icon-plus-sign"></i> Add</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
[% WHILE (row = results.next) %]
|
[% WHILE (row = results.next) %]
|
||||||
<tr>
|
<tr>
|
||||||
<td class="nd_center-cell">[% row.creation_stamp | html_entity %]</td>
|
<td class="nd_center-cell">[% row.creation_stamp | html_entity %]</td>
|
||||||
@@ -21,15 +33,16 @@
|
|||||||
<td class="nd_center-cell">[% row.action | html_entity %]</td>
|
<td class="nd_center-cell">[% row.action | html_entity %]</td>
|
||||||
<td class="nd_center-cell">[% settings.port_control_reasons.item(row.reason) || row.reason | html_entity %]</td>
|
<td class="nd_center-cell">[% settings.port_control_reasons.item(row.reason) || row.reason | html_entity %]</td>
|
||||||
<td class="nd_center-cell">[% row.log || '-' | html_entity %]</td>
|
<td class="nd_center-cell">[% row.log || '-' | html_entity %]</td>
|
||||||
|
<td class="nd_center-cell"></td>
|
||||||
</tr>
|
</tr>
|
||||||
[% END %]
|
[% END %]
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
[% END %]
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('#data-table').dataTable({
|
$('#data-table').dataTable({
|
||||||
|
sort: false,
|
||||||
[% INCLUDE 'ajax/datatabledefaults.tt' -%]
|
[% INCLUDE 'ajax/datatabledefaults.tt' -%]
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|||||||
@@ -52,4 +52,35 @@
|
|||||||
,delay: 150
|
,delay: 150
|
||||||
,minLength: 3
|
,minLength: 3
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// dynamically bind to all forms in the table
|
||||||
|
$('.content').on('click', '.nd_adminbutton', function(event) {
|
||||||
|
// stop form from submitting normally
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// what purpose - add/update/del
|
||||||
|
var mode = $(this).attr('name');
|
||||||
|
|
||||||
|
// submit the query and put results into the tab pane
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST'
|
||||||
|
,async: true
|
||||||
|
,dataType: 'html'
|
||||||
|
,url: uri_base + '/ajax/control/report/' + tab + '/' + mode
|
||||||
|
,data: $(this).closest('tr').find('input[data-form="' + mode + '"]').serializeArray()
|
||||||
|
,beforeSend: function() {
|
||||||
|
$(target).html(
|
||||||
|
'<div class="span2 alert">Request submitted...</div>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
,success: function() {
|
||||||
|
$('#' + tab + '_form').trigger('submit');
|
||||||
|
}
|
||||||
|
// skip any error reporting for now
|
||||||
|
// TODO: fix sanity_ok in Netdisco Web
|
||||||
|
,error: function() {
|
||||||
|
$('#' + tab + '_form').trigger('submit');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user