Merge branch 'master' into em-device-ports-json

This commit is contained in:
Oliver Gorwits
2014-10-11 12:03:36 +01:00
33 changed files with 434 additions and 284 deletions

View File

@@ -1,8 +1,47 @@
2.029008 2.029012 - 2014-10-09
[BUG FIXES]
* [#152] HP devices with port names "D##" not sorted by portsort.js
2.029011 - 2014-10-07
[BUG FIXES]
* Fix typo in the Device By Location report template
2.029010 - 2014-10-07
[NEW FEATURES]
* Administration (SSH, Telnet, Web) links for devices
* [#143] Pass parameter(s) to custom reports via bind_params config
[BUG FIXES]
* Require old DBIC version to fix deploy problem
2.029009 - 2014-09-27
[ENHANCEMENTS] [ENHANCEMENTS]
* Setting for items in number of records per table page menu (table_showrecordsmenu). * Defaults now exist for all expire tasks
* Added expire_jobs to remove jobs queue items after 14 days
[BUG FIXES]
* Require new DBIC version to fix duplicate DB connection problem
2.029008 - 2014-09-23
[ENHANCEMENTS]
* [#144] Setting for items in number of records per table page menu (table_showrecordsmenu).
[BUG FIXES]
* Add Dancer import to SSHCollector Platforms
* Add note to docs to workaround current Dancer/YAML::XS issue
2.029007 - 2014-09-12 2.029007 - 2014-09-12

View File

@@ -314,6 +314,7 @@ share/views/ajax/admintask/undiscoveredneighbors.tt
share/views/ajax/admintask/undiscoveredneighbors_csv.tt share/views/ajax/admintask/undiscoveredneighbors_csv.tt
share/views/ajax/admintask/userlog.tt share/views/ajax/admintask/userlog.tt
share/views/ajax/admintask/users.tt share/views/ajax/admintask/users.tt
share/views/ajax/datatabledefaults.tt
share/views/ajax/device/addresses.tt share/views/ajax/device/addresses.tt
share/views/ajax/device/addresses_csv.tt share/views/ajax/device/addresses_csv.tt
share/views/ajax/device/details.tt share/views/ajax/device/details.tt
@@ -391,6 +392,7 @@ share/views/report.tt
share/views/search.tt share/views/search.tt
share/views/sidebar/device/netmap.tt share/views/sidebar/device/netmap.tt
share/views/sidebar/device/ports.tt share/views/sidebar/device/ports.tt
share/views/sidebar/report/generic_report.tt
share/views/sidebar/report/ipinventory.tt share/views/sidebar/report/ipinventory.tt
share/views/sidebar/report/moduleinventory.tt share/views/sidebar/report/moduleinventory.tt
share/views/sidebar/report/netbios.tt share/views/sidebar/report/netbios.tt

View File

@@ -10,7 +10,7 @@ configure_requires:
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
@@ -35,7 +35,7 @@ requires:
Archive::Extract: 0 Archive::Extract: 0
CGI::Expand: 2.05 CGI::Expand: 2.05
DBD::Pg: 0 DBD::Pg: 0
DBIx::Class: 0.0825 DBIx::Class: 0.0827
DBIx::Class::Helpers: 2.018004 DBIx::Class::Helpers: 2.018004
Daemon::Control: 0.001 Daemon::Control: 0.001
Dancer: 1.3112 Dancer: 1.3112
@@ -71,7 +71,6 @@ requires:
Sereal: 0 Sereal: 0
Socket6: 0.23 Socket6: 0.23
Starman: 0.4008 Starman: 0.4008
Sys::Proctitle: 0
Template: 2.24 Template: 2.24
Template::Plugin::CSV: 0.04 Template::Plugin::CSV: 0.04
Template::Plugin::Number::Format: 1.02 Template::Plugin::Number::Format: 1.02
@@ -91,4 +90,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.029007 version: '2.029012'

View File

@@ -16,7 +16,7 @@ requires 'Archive::Extract' => 0;
requires 'CGI::Expand' => 2.05; requires 'CGI::Expand' => 2.05;
requires 'Data::Printer' => 0; requires 'Data::Printer' => 0;
requires 'DBD::Pg' => 0; requires 'DBD::Pg' => 0;
requires 'DBIx::Class' => 0.08250; requires 'DBIx::Class' => 0.08270;
requires 'DBIx::Class::Helpers' => 2.018004; requires 'DBIx::Class::Helpers' => 2.018004;
requires 'Daemon::Control' => 0.001000; requires 'Daemon::Control' => 0.001000;
requires 'Dancer' => 1.3112; requires 'Dancer' => 1.3112;

View File

@@ -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

View File

@@ -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

View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -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};

View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -4,7 +4,7 @@ use strict;
use warnings; use warnings;
use 5.010_000; use 5.010_000;
our $VERSION = '2.029007'; our $VERSION = '2.029012';
use App::Netdisco::Configuration; use App::Netdisco::Configuration;
use Module::Find (); use Module::Find ();
@@ -123,6 +123,7 @@ install Netdisco and its dependencies into the C<netdisco> user's home area
su - netdisco su - netdisco
curl -L http://cpanmin.us/ | perl - --notest --local-lib ~/perl5 App::Netdisco curl -L http://cpanmin.us/ | perl - --notest --local-lib ~/perl5 App::Netdisco
~/bin/localenv cpanm --notest --force Dancer@1.3126 DBIx::Class@0.08270
Link some of the newly installed apps into a handy location: Link some of the newly installed apps into a handy location:
@@ -190,7 +191,11 @@ Netdisco 2, disable your system's cron jobs for the Netdisco 1.x poller.
For further documentation on deployment, see For further documentation on deployment, see
L<Deployment|App::Netdisco::Manual::Deployment>. L<Deployment|App::Netdisco::Manual::Deployment>.
=head1 Upgrading =head1 Upgrading from 2.x
If you're running a version of Netdisco prior to 2.x then you should follow
the full installation instructions, above. This process is for upgrading
version 2.x only.
Before upgrading please review the latest L<Release Before upgrading please review the latest L<Release
Notes|App::Netdisco::Manual::ReleaseNotes>. Then, the process is as follows: Notes|App::Netdisco::Manual::ReleaseNotes>. Then, the process is as follows:
@@ -198,6 +203,9 @@ Notes|App::Netdisco::Manual::ReleaseNotes>. Then, the process is as follows:
# upgrade Netdisco # upgrade Netdisco
~/bin/localenv cpanm --notest App::Netdisco ~/bin/localenv cpanm --notest App::Netdisco
# workaround for current upstream bug
~/bin/localenv cpanm --notest --force Dancer@1.3126 DBIx::Class@0.08270
# apply database schema updates # apply database schema updates
~/bin/netdisco-deploy ~/bin/netdisco-deploy

View File

@@ -40,6 +40,15 @@ sub expire {
}); });
} }
if (setting('expire_jobs') and setting('expire_jobs') > 0) {
schema('netdisco')->txn_do(sub {
schema('netdisco')->resultset('Admin')->search({
entered => \[q/< (now() - ?::interval)/,
(setting('expire_jobs') * 86400)],
})->delete();
});
}
return job_done("Checked expiry for all Devices and Nodes"); return job_done("Checked expiry for all Devices and Nodes");
} }

View File

@@ -256,16 +256,21 @@ code or HTML templates. For example:
FROM device d FROM device d
ORDER BY name ORDER BY name
The C<key> of each item in the C<reports> configuration is an alias for the The C<tag> of each item in the C<reports> configuration is an alias for the
report, and becomes part of the web path. report, and becomes part of the web path.
You can munge the data retrieved from the database by placing a Perl script You can munge the data retrieved from the database by placing a Perl script
with the same name as the C<reports> key into the C<site_plugins> directory of with the same name as the C<reports> key into the "C<site_plugins>" directory
Netdisco's home area. The script can access C<$config> for its configuration of Netdisco's home area. The script can access C<$config> for its
and C<@data> for the retrieved data. It should return a list of munged data. configuration and C<@data> for the retrieved data. It should return a list of
munged data.
Within the tree you can provide each of the keys below: Within the tree you can provide each of the keys below:
=head4 C<tag>
Alias for the Report, which must be usable in a web path.
=head4 C<label> =head4 C<label>
Title for the Report. Title for the Report.
@@ -295,6 +300,20 @@ C<query> may not be the same as those in the web report. Set this to a list of
the columns in C<query>. The C<columns> setting will then be used for the web the columns in C<query>. The C<columns> setting will then be used for the web
report. report.
=head4 C<bind_params> (optional)
You can use placeholders in the SQL C<query> (that is, "C<?>") to bind
user-supplied parameters. This setting should be a list of the parameters to
pick out of the URL query string and match to the placeholders in the same
order. For example:
query: |
SELECT ... FROM ... WHERE device = ? AND port = ?
bind-params: ['device', 'port']
# then
http://localhost:5000/report/my_special_report?device=192.0.2.1&port=Vlan142
=head3 C<jobqueue_refresh> =head3 C<jobqueue_refresh>
Value: Integer Number. Default: 5. Value: Integer Number. Default: 5.
@@ -724,14 +743,14 @@ seconds as well as integers.
=head3 C<expire_devices> =head3 C<expire_devices>
Value: Number of Days. Value: Number of Days. Default: 60
Devices that have not been refreshed in this number of days will be removed. Devices that have not been refreshed in this number of days will be removed.
All nodes connected to this device will be removed as well. All nodes connected to this device will be removed as well.
=head3 C<expire_nodes> =head3 C<expire_nodes>
Value: Number of Days. Value: Number of Days. Default: 90
Nodes that have not been refreshed in this number of days will be removed from Nodes that have not been refreshed in this number of days will be removed from
the database. Archived and non-archived nodes are removed. This includes the database. Archived and non-archived nodes are removed. This includes
@@ -739,11 +758,19 @@ SwitchPort/MAC and MAC/IP mappings.
=head3 C<expire_nodes_archive> =head3 C<expire_nodes_archive>
Value: Number of Days. Value: Number of Days. Default: 60
Archived data for switch-port/MAC and MAC/IP mappings older than this number Archived data for switch-port/MAC and MAC/IP mappings older than this number
of days will be removed. of days will be removed.
=head3 C<expire_jobs>
Value: Number of Days. Default: 14
Jobs which entered the job queue more than this many days ago will be removed
from the queue during the scheduled expiry process (regardless of whether they
were ever run).
=head3 C<dns> =head3 C<dns>
Value: Settings Tree. Default: Value: Settings Tree. Default:

View File

@@ -36,6 +36,24 @@ but they are backwards compatible.
=back =back
=head1 2.029010
=head2 General Notices
When upgrading you will encounter a current incompatibility between Netdisco
and one of its components. To work around this, issue the following command:
~/bin/localenv cpanm --notest --force Dancer@1.3126 DBIx::Class@0.08270
=head1 2.029008
=head2 General Notices
When upgrading you will encounter a current incompatibility between Netdisco
and one of its components. To work around this, issue the following command:
~/bin/localenv cpanm --notest --force Dancer@1.3126
=head1 2.029002 =head1 2.029002
=head2 General Notices =head2 General Notices

View File

@@ -23,8 +23,9 @@ the same context.
use strict; use strict;
use warnings; use warnings;
use Moo; use Dancer ':script';
use Expect; use Expect;
use Moo;
=head1 PUBLIC METHODS =head1 PUBLIC METHODS

View File

@@ -22,6 +22,7 @@ can't be executed, falls back to the latter.
use strict; use strict;
use warnings; use warnings;
use Dancer ':script';
use Moo; use Moo;
=head1 PUBLIC METHODS =head1 PUBLIC METHODS

View File

@@ -16,7 +16,6 @@ use strict;
use warnings; use warnings;
use Dancer ':script'; use Dancer ':script';
use Data::Printer;
use Moo; use Moo;
=head1 PUBLIC METHODS =head1 PUBLIC METHODS

View File

@@ -16,9 +16,8 @@ use strict;
use warnings; use warnings;
use Dancer ':script'; use Dancer ':script';
use Data::Printer;
use Moo;
use Expect; use Expect;
use Moo;
=head1 PUBLIC METHODS =head1 PUBLIC METHODS

View File

@@ -16,9 +16,8 @@ use strict;
use warnings; use warnings;
use Dancer ':script'; use Dancer ':script';
use Data::Printer;
use Moo;
use Expect; use Expect;
use Moo;
=head1 PUBLIC METHODS =head1 PUBLIC METHODS

View File

@@ -22,11 +22,10 @@ foreach my $report (@{setting('reports')}) {
}); });
get "/ajax/content/report/$r" => require_login sub { get "/ajax/content/report/$r" => require_login sub {
my $rs = schema('netdisco')->resultset('Virtual::GenericReport')->result_source;
# TODO: this should be done by creating a new Virtual Result class on # TODO: this should be done by creating a new Virtual Result class on
# the fly (package...) and then calling DBIC register_class on it. # the fly (package...) and then calling DBIC register_class on it.
my $rs = schema('netdisco')->resultset('Virtual::GenericReport')->result_source;
$rs->view_definition($report->{query}); $rs->view_definition($report->{query});
$rs->remove_columns($rs->columns); $rs->remove_columns($rs->columns);
$rs->add_columns( exists $report->{query_columns} $rs->add_columns( exists $report->{query_columns}
@@ -35,13 +34,17 @@ foreach my $report (@{setting('reports')}) {
); );
my $set = schema('netdisco')->resultset('Virtual::GenericReport') my $set = schema('netdisco')->resultset('Virtual::GenericReport')
->search(undef, {result_class => 'DBIx::Class::ResultClass::HashRefInflator'}); ->search(undef, {
result_class => 'DBIx::Class::ResultClass::HashRefInflator',
( (exists $report->{bind_params})
? (bind => [map { param($_) } @{ $report->{bind_params} }]) : () ),
});
@data = $set->all; @data = $set->all;
# Data Munging support... # Data Munging support...
my $compartment = Safe->new; my $compartment = Safe->new;
$config = $report; $config = $report; # closure for the config of this report
$compartment->share(qw/$config @data/); $compartment->share(qw/$config @data/);
$compartment->permit_only(qw/:default sort/); $compartment->permit_only(qw/:default sort/);

View File

@@ -169,15 +169,23 @@ register 'register_report' => sub {
return error "bad config to register_report"; return error "bad config to register_report";
} }
foreach my $item (@{setting('_reports_menu')->{ $config->{category} }}) { if (0 == scalar grep {$_ eq $config->{tag}}
if ($item eq $config->{tag}) { @{setting('_reports_menu')->{ $config->{category} }}) {
setting('_reports')->{$config->{tag}} = $config; push @{setting('_reports_menu')->{ $config->{category} }}, $config->{tag};
return;
}
} }
push @{setting('_reports_menu')->{ $config->{category} }}, $config->{tag}; foreach my $tag (@{setting('_reports_menu')->{ $config->{category} }}) {
setting('_reports')->{$config->{tag}} = $config; if ($config->{tag} eq $tag) {
setting('_reports')->{$tag} = $config;
foreach my $rconfig (@{setting('reports')}) {
if ($rconfig->{tag} eq $tag) {
setting('_reports')->{$tag}->{'rconfig'} = $rconfig;
last;
}
}
}
}
}; };
register_plugin; register_plugin;

View File

@@ -130,9 +130,10 @@ nbtstat_only: []
nbtstat_max_age: 7 nbtstat_max_age: 7
nbtstat_interval: 0.02 nbtstat_interval: 0.02
nbtstat_timeout: 1 nbtstat_timeout: 1
expire_devices: 0 expire_devices: 60
expire_nodes: 0 expire_nodes: 90
expire_nodes_archive: 0 expire_nodes_archive: 60
expire_jobs: 14
store_wireless_clients: true store_wireless_clients: true
store_modules: true store_modules: true
ignore_interfaces: ignore_interfaces:

View File

@@ -24,45 +24,53 @@
* See: http://js-naturalsort.googlecode.com/svn/trunk/naturalSort.js * See: http://js-naturalsort.googlecode.com/svn/trunk/naturalSort.js
*/ */
function portSort (a, b) { function portSort (a, b) {
var re = /(^(-?\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi, var re = /(^0x[0-9a-f]+$|[0-9]+)/gi,
// string regex // string regex
sre = /(^[ ]*|[ ]*$)/g, sre = /(^[ ]*|[ ]*$)/g,
// octal regex // octal regex
ore = /^0/, ore = /^0/,
// convert all to strings and trim() // convert all to strings and trim()
x = a.toString().replace(sre, '') || '', x = a.toString().replace(sre, '') || '',
y = b.toString().replace(sre, '') || ''; y = b.toString().replace(sre, '') || '';
// hack for foundry "10GigabitEthernet" -> cisco-like "TenGigabitEthernet"
x = x.replace(/^10GigabitEthernet/, 'GigabitEthernet'); // hack for foundry "10GigabitEthernet" -> cisco-like "TenGigabitEthernet"
y = y.replace(/^10GigabitEthernet/, 'GigabitEthernet'); x = x.replace(/^10GigabitEthernet/, 'GigabitEthernet');
// chunk/tokenize y = y.replace(/^10GigabitEthernet/, 'GigabitEthernet');
var xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'); // chunk/tokenize
for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) { var xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
// find floats not starting with '0', string or 0 if not defined (Clint Priest) yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0');
var oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
var oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0; for (var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {
// handle numeric vs string comparison - number < string - (Kyle Adams) // find floats not starting with '0', string or 0 if not defined (Clint Priest)
if (isNaN(oFxNcL) !== isNaN(oFyNcL)) return (isNaN(oFxNcL)) ? 1 : -1; var oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' var oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;
else if (typeof oFxNcL !== typeof oFyNcL) {
oFxNcL += ''; // handle numeric vs string comparison - number < string - (Kyle Adams)
oFyNcL += ''; if (isNaN(oFxNcL) !== isNaN(oFyNcL)) {
} return (isNaN(oFxNcL)) ? 1 : -1;
if (oFxNcL < oFyNcL) return -1; }
if (oFxNcL > oFyNcL) return 1; // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
} else if (typeof oFxNcL !== typeof oFyNcL) {
return 0; oFxNcL += '';
oFyNcL += '';
}
if (oFxNcL < oFyNcL) { return -1; }
if (oFxNcL > oFyNcL) { return 1; }
}
return 0;
} }
jQuery.extend( jQuery.fn.dataTableExt.oSort, { jQuery.extend( jQuery.fn.dataTableExt.oSort, {
"portsort-asc": function ( a, b ) { "portsort-asc": function ( a, b ) {
return portSort(a,b); return portSort(a,b);
}, },
"portsort-desc": function ( a, b ) { "portsort-desc": function ( a, b ) {
return portSort(a,b) * -1; return portSort(a,b) * -1;
} }
} ); } );
}()); }());

View File

@@ -80,6 +80,17 @@
[% END %] [% END %]
</tr> </tr>
[% END %] [% END %]
<tr>
<td>Administration</td>
<td>
<a href="ssh://[% d.ip | html_entity %]" target="_blank">
<span class="label label-info"><i class="icon-keyboard"></i> SSH</span></a>
<a href="telnet://[% d.ip | html_entity %]" target="_blank">
<span class="label label-info"><i class="icon-keyboard"></i> Telnet</span></a>
<a href="https://[% d.ip | html_entity %]/" target="_blank">
<span class="label label-info"><i class="icon-external-link"></i> Web</span></a>
</td>
</tr>
<tr> <tr>
<td>Uptime</td> <td>Uptime</td>
<td>[% d.uptime_age | html_entity %]</td> <td>[% d.uptime_age | html_entity %]</td>

View File

@@ -48,7 +48,7 @@ $(document).ready(function() {
return '<a href="[% search_device %]&q=' + encodeURIComponent(data) + '&model=' + encodeURIComponent(data) + '">' + he.encode(data || '') + '</a>'; return '<a href="[% search_device %]&q=' + encodeURIComponent(data) + '&model=' + encodeURIComponent(data) + '">' + he.encode(data || '') + '</a>';
} }
} }
]. ],
[% INCLUDE 'ajax/datatabledefaults.tt' -%] [% INCLUDE 'ajax/datatabledefaults.tt' -%]
}); });

View File

@@ -17,6 +17,7 @@
[% INCLUDE "sidebar/report/${report.tag}.tt" %] [% INCLUDE "sidebar/report/${report.tag}.tt" %]
[% CATCH %] [% CATCH %]
<script type="text/javascript">has_sidebar["[% report.tag %]"] = 0;</script> <script type="text/javascript">has_sidebar["[% report.tag %]"] = 0;</script>
[% INCLUDE "sidebar/report/generic_report.tt" %]
[% END %] [% END %]
</form> </form>
</div> <!-- /tab-pane --> </div> <!-- /tab-pane -->

View File

@@ -0,0 +1,4 @@
[% FOREACH k IN report.rconfig.bind_params %]
<input name="[% k %]" value="[% params.$k | html_entity %]" type="hidden"/>
[% END %]

View File

@@ -13,5 +13,6 @@ BEGIN {
is(sort_port(1,1), 0, 'number - same values'); is(sort_port(1,1), 0, 'number - same values');
is(sort_port('1:2','1:10'), -1, 'colon number (Extreme) - first lesser'); is(sort_port('1:2','1:10'), -1, 'colon number (Extreme) - first lesser');
is(sort_port('D1','D10'), -1, 'HP - simple letter and number [#152]');
done_testing; done_testing;

View File

@@ -1,188 +1,200 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>portsort.js test suite</title> <title>portsort.js test suite</title>
<script src="http://code.jquery.com/jquery-1.11.1.min.js" type="text/javascript"></script> <script src="http://code.jquery.com/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="http://code.jquery.com/qunit/qunit-1.14.0.js" type="text/javascript"></script> <script src="http://code.jquery.com/qunit/qunit-1.14.0.js" type="text/javascript"></script>
<script src="../js/qunit-tap.js" type="text/javascript"></script> <script src="../js/qunit-tap.js" type="text/javascript"></script>
<script> <script>
qunitTap(QUnit, function() { console.log.apply(console, arguments); }); qunitTap(QUnit, function() { console.log.apply(console, arguments); });
</script> </script>
<link href="http://code.jquery.com/qunit/qunit-1.14.0.css" type="text/css" rel="stylesheet"></link> <link href="http://code.jquery.com/qunit/qunit-1.14.0.css" type="text/css" rel="stylesheet"></link>
<script src="../../share/public/javascripts/jquery.dataTables.min.js" type="text/javascript"></script> <script src="../../share/public/javascripts/jquery.dataTables.min.js" type="text/javascript"></script>
<script src="../../share/public/javascripts/portsort.js" type="text/javascript"></script> <script src="../../share/public/javascripts/portsort.js" type="text/javascript"></script>
<script type="text/javascript"> <script type="text/javascript">
$(function () { $(function () {
module("portsort.js"), module("portsort.js"),
test("different values types", function () { test("different values types", function () {
wrapTest( wrapTest(
['a',1], ['a',1],
[1,'a'], [1,'a'],
'number always comes first'); 'number always comes first');
wrapTest( wrapTest(
['1',1], ['1',1],
['1',1], ['1',1],
'number vs numeric string - should remain unchanged (error in chrome)'); 'number vs numeric string - should remain unchanged (error in chrome)');
wrapTest( wrapTest(
['02',3,2,'01'], ['02',3,2,'01'],
['01','02',2,3], ['01','02',2,3],
'padding numeric string vs number'); 'padding numeric string vs number');
}); });
test("numerics", function () { test("numerics", function () {
wrapTest( wrapTest(
['10',9,2,'1','4'], ['10',9,2,'1','4'],
['1',2,'4',9,'10'], ['1',2,'4',9,'10'],
'string vs number'); 'string vs number');
wrapTest( wrapTest(
['0001','002','001'], ['0001','002','001'],
['0001','001','002'], ['0001','001','002'],
'0 left-padded numbers'); '0 left-padded numbers');
wrapTest( wrapTest(
[2,1,'1','0001','002','02','001'], [2,1,'1','0001','002','02','001'],
['0001','001','002','02',1,'1',2], ['0001','001','002','02',1,'1',2],
'0 left-padded numbers and regular numbers'); '0 left-padded numbers and regular numbers');
wrapTest( wrapTest(
['10.0401',10.022,10.042,'10.021999'], ['10.0401',10.022,10.042,'10.021999'],
['10.021999',10.022,'10.0401',10.042], ['10.021999',10.022,'10.0401',10.042],
'decimal string vs decimal, different precision'); 'decimal string vs decimal, different precision');
wrapTest( wrapTest(
['10.04',10.02,10.03,'10.01'], ['10.04',10.02,10.03,'10.01'],
['10.01',10.02,10.03,'10.04'], ['10.01',10.02,10.03,'10.04'],
'decimal string vs decimal, same precision'); 'decimal string vs decimal, same precision');
wrapTest( wrapTest(
['10001','10011','101','10010','10','100','10002', ['10001','10011','101','10010','10','100','10002',
'10112','10111'], '10112','10111'],
['10','100','101','10001','10002','10010','10011', ['10','100','101','10001','10002','10010','10011',
'10111','10112'], '10111','10112'],
'mixed length'); 'mixed length');
}); });
test("IP addresses", function () { test("IP addresses", function () {
wrapTest( wrapTest(
[ [
'192.168.0.100', '192.168.0.100',
'192.168.0.1', '192.168.0.1',
'192.168.1.1', '192.168.1.1',
'192.168.0.250', '192.168.0.250',
'192.168.1.123', '192.168.1.123',
'10.0.0.2', '10.0.0.2',
'10.0.0.1' '10.0.0.1'
], ],
[ [
'10.0.0.1', '10.0.0.1',
'10.0.0.2', '10.0.0.2',
'192.168.0.1', '192.168.0.1',
'192.168.0.100', '192.168.0.100',
'192.168.0.250', '192.168.0.250',
'192.168.1.1', '192.168.1.1',
'192.168.1.123' '192.168.1.123'
]); ]);
}); });
test("space(s) as first character(s)", function () { test("space(s) as first character(s)", function () {
wrapTest( wrapTest(
['alpha',' 1',' 3',' 2',0], ['alpha',' 1',' 3',' 2',0],
[0,' 1',' 2',' 3','alpha']); [0,' 1',' 2',' 3','alpha']);
}); });
test("wireless controllers", function () { test("wireless controllers", function () {
wrapTest( wrapTest(
[ [
'00:14:0e:12:34:56','00:08:30:01:23:45.1', '00:14:0e:12:34:56','00:08:30:01:23:45.1',
'00:15:c7:ab:23:10.0','00:14:0e:01:23:45', '00:15:c7:ab:23:10.0','00:14:0e:01:23:45',
'00:08:30:01:23:45.0','00:15:c7:ab:23:00.1' '00:08:30:01:23:45.0','00:15:c7:ab:23:00.1'
], ],
[ [
'00:08:30:01:23:45.0','00:08:30:01:23:45.1', '00:08:30:01:23:45.0','00:08:30:01:23:45.1',
'00:14:0e:01:23:45','00:14:0e:12:34:56', '00:14:0e:01:23:45','00:14:0e:12:34:56',
'00:15:c7:ab:23:00.1','00:15:c7:ab:23:10.0' '00:15:c7:ab:23:00.1','00:15:c7:ab:23:10.0'
],'ap ports'); ],'ap ports');
wrapTest( wrapTest(
[ [
'wlan-controller1/0.104','wlan-controller1/0', 'wlan-controller1/0.104','wlan-controller1/0',
'wlan-controller1/0.252','wlan-controller1/0.103' 'wlan-controller1/0.252','wlan-controller1/0.103'
], ],
[ [
'wlan-controller1/0','wlan-controller1/0.103', 'wlan-controller1/0','wlan-controller1/0.103',
'wlan-controller1/0.104','wlan-controller1/0.252' 'wlan-controller1/0.104','wlan-controller1/0.252'
],'controller ports'); ],'controller ports');
}); });
test("ports", function () { test("ports", function () {
wrapTest( wrapTest(
[ [
'1.1','1.13','1.14','1.19','1.2','Vlan318','1.25', '1.1','1.13','1.14','1.19','1.2','Vlan318','1.25',
'1.29','3.12','1.3','1.37','1.38','1.4','1.43', '1.29','3.12','1.3','1.37','1.38','1.4','1.43',
'1.6','8.34' '1.6','8.34'
], ],
[ [
'1.1','1.2','1.3','1.4','1.6','1.13','1.14','1.19', '1.1','1.2','1.3','1.4','1.6','1.13','1.14','1.19',
'1.25','1.29','1.37','1.38','1.43','3.12','8.34', '1.25','1.29','1.37','1.38','1.43','3.12','8.34',
'Vlan318' 'Vlan318'
],'Avaya'); ],'Avaya');
wrapTest( wrapTest(
[ [
'GigabitEthernet9/0/12', 'GigabitEthernet9/0/12',
'GigabitEthernet9/0/11', 'GigabitEthernet9/0/11',
'GigabitEthernet1/0/14', 'GigabitEthernet1/0/14',
'GigabitEthernet1/1/12', 'GigabitEthernet1/1/12',
], ],
[ [
'GigabitEthernet1/0/14', 'GigabitEthernet1/0/14',
'GigabitEthernet1/1/12', 'GigabitEthernet1/1/12',
'GigabitEthernet9/0/11', 'GigabitEthernet9/0/11',
'GigabitEthernet9/0/12', 'GigabitEthernet9/0/12',
],'Cisco'); ],'Cisco');
wrapTest( wrapTest(
[ [
'1/1/1','0/1/1','0/3/20','0/2/1','0/3/1','0/3/2', '1/1/1','0/1/1','0/3/20','0/2/1','0/3/1','0/3/2',
'0/3/11','0/3/10' '0/3/11','0/3/10'
],[ ],[
'0/1/1','0/2/1','0/3/1','0/3/2','0/3/10','0/3/11', '0/1/1','0/2/1','0/3/1','0/3/2','0/3/10','0/3/11',
'0/3/20','1/1/1' '0/3/20','1/1/1'
],'Dell'); ],'Dell');
wrapTest( wrapTest(
[ [
'1:10','1:2','1:1','1:11' '1:10','1:2','1:1','1:11'
],[ ],[
'1:1','1:2','1:10','1:11' '1:1','1:2','1:10','1:11'
],'Extreme'); ],'Extreme');
wrapTest( wrapTest(
[ [
'10GigabitEthernet1/1/12', 'D10','D11','D2','D1', 'A30', 'A3'
'GigabitEthernet1/0/14', ],[
'GigabitEthernet9/0/12', 'A3', 'A30', 'D1','D2','D10','D11'
'10GigabitEthernet9/0/11', ],'HP A & D');
],[ wrapTest(
'GigabitEthernet1/0/14', [
'10GigabitEthernet1/1/12', 'B10','B11','B2','B1', 'A30', 'A3'
'10GigabitEthernet9/0/11', ],[
'GigabitEthernet9/0/12', 'A3', 'A30', 'B1','B2','B10','B11'
],'Foundry 10Gb'); ],'HP A & B');
wrapTest( wrapTest(
[ [
'Slot: 1 Port: 2 Gigabit - Level', '10GigabitEthernet1/1/12',
'GigabitEthernet1/0/14',
'GigabitEthernet9/0/12',
'10GigabitEthernet9/0/11',
],[
'GigabitEthernet1/0/14',
'10GigabitEthernet1/1/12',
'10GigabitEthernet9/0/11',
'GigabitEthernet9/0/12',
],'Foundry 10Gb');
wrapTest(
[
'Slot: 1 Port: 2 Gigabit - Level',
'Slot: 1 Port: 1 Gigabit - Level', 'Slot: 1 Port: 1 Gigabit - Level',
'Slot: 0 Port: 15 Gigabit - Level', 'Slot: 0 Port: 15 Gigabit - Level',
'Slot: 1 Port: 10 Gigabit - Level', 'Slot: 1 Port: 10 Gigabit - Level',
'Slot: 0 Port: 1 Gigabit - Level' 'Slot: 0 Port: 1 Gigabit - Level'
],[ ],[
'Slot: 0 Port: 1 Gigabit - Level', 'Slot: 0 Port: 1 Gigabit - Level',
'Slot: 0 Port: 15 Gigabit - Level', 'Slot: 0 Port: 15 Gigabit - Level',
'Slot: 1 Port: 1 Gigabit - Level', 'Slot: 1 Port: 1 Gigabit - Level',
'Slot: 1 Port: 2 Gigabit - Level', 'Slot: 1 Port: 2 Gigabit - Level',
'Slot: 1 Port: 10 Gigabit - Level' 'Slot: 1 Port: 10 Gigabit - Level'
],'Netgear'); ],'Netgear');
wrapTest( wrapTest(
[ [
'port-channel190','port-channel19', 'port-channel190','port-channel19',
'port-channel1044','port-channel2','port-channel104' 'port-channel1044','port-channel2','port-channel104'
],[ ],[
'port-channel2','port-channel19','port-channel104', 'port-channel2','port-channel19','port-channel104',
'port-channel190','port-channel1044' 'port-channel190','port-channel1044'
],'port-channel'); ],'port-channel');
wrapTest( wrapTest(
[ [
'Serial1/1:5', 'Serial1/1:5',
'Serial2/0:5-Bearer Channel', 'Serial2/0:5-Bearer Channel',
'Serial2/0:20', 'Serial2/0:20',
@@ -191,7 +203,7 @@
'Serial2/0:21', 'Serial2/0:21',
'Serial2/0:5', 'Serial2/0:5',
'Serial2/0:20-Bearer Channel' 'Serial2/0:20-Bearer Channel'
],[ ],[
'Serial1/1:0', 'Serial1/1:0',
'Serial1/1:5', 'Serial1/1:5',
'Serial1/1:5-Bearer Channel', 'Serial1/1:5-Bearer Channel',
@@ -200,41 +212,41 @@
'Serial2/0:20', 'Serial2/0:20',
'Serial2/0:20-Bearer Channel', 'Serial2/0:20-Bearer Channel',
'Serial2/0:21' 'Serial2/0:21'
],'serial'); ],'serial');
wrapTest( wrapTest(
[ [
'unrouted VLAN 990','unrouted VLAN 95', 'unrouted VLAN 990','unrouted VLAN 95',
'unrouted VLAN 985','unrouted VLAN 99', 'unrouted VLAN 985','unrouted VLAN 99',
'unrouted VLAN 950' 'unrouted VLAN 950'
],[
'unrouted VLAN 95','unrouted VLAN 99',
'unrouted VLAN 950','unrouted VLAN 985',
'unrouted VLAN 990'
],'unrouted vlans');
wrapTest(
[
'Vlan10','Vlan910','Vlan1','Vlan91'
],[
'Vlan1','Vlan10','Vlan91','Vlan910'
],'vlans');
wrapTest(
[
'voice-port 2/10','voice-port 2/1','voice-port 2/2',
'voice-port 2/11'
],[
'voice-port 2/1','voice-port 2/2','voice-port 2/10',
'voice-port 2/11',
],'voice-port'); ],[
}); 'unrouted VLAN 95','unrouted VLAN 99',
'unrouted VLAN 950','unrouted VLAN 985',
'unrouted VLAN 990'
],'unrouted vlans');
wrapTest(
[
'Vlan10','Vlan910','Vlan1','Vlan91'
],[
'Vlan1','Vlan10','Vlan91','Vlan910'
],'vlans');
wrapTest(
[
'voice-port 2/10','voice-port 2/1','voice-port 2/2',
'voice-port 2/11'
],[
'voice-port 2/1','voice-port 2/2','voice-port 2/10',
'voice-port 2/11',
],'voice-port');
});
}); });
var sortFn = jQuery.fn.dataTableExt.oSort["portsort-asc"]; var sortFn = jQuery.fn.dataTableExt.oSort["portsort-asc"];
function wrapTest(origArray, sortArray, message) { function wrapTest(origArray, sortArray, message) {
deepEqual($.extend([], origArray).sort(sortFn), sortArray, (message ? message + ' - ' : '') + QUnit.jsDump.parse(origArray)); deepEqual($.extend([], origArray).sort(sortFn), sortArray, (message ? message + ' - ' : '') + QUnit.jsDump.parse(origArray));
}; };
</script> </script>
</head> </head>
<body> <body>
<div id="qunit"></div> <div id="qunit"></div>