Merge branch 'master' into em-device-ports-json
Conflicts: Netdisco/lib/App/Netdisco/Web/Device.pm
This commit is contained in:
@@ -1,9 +1,24 @@
|
|||||||
2.029013 -
|
2.029013_002 - 2014-11-14
|
||||||
|
|
||||||
|
[ENHANCEMENTS]
|
||||||
|
|
||||||
|
* [#161] Updated IOS-XR SSHCollector
|
||||||
|
* [#165] Mention system clock in docs
|
||||||
|
* [#164] Workers should restart periodically
|
||||||
|
* [#168] Jobs requested via web UI are treated as high priority
|
||||||
|
* [#162] Change from Net::MAC to NetAddr::MAC
|
||||||
|
* [#159] Macsuck archive behaviour same as ND1 (unseen nodes remain active)
|
||||||
|
* [#170] Show device SNMP::Info class in web interface
|
||||||
|
* Add "Run Expire Job" to the Admin Menu
|
||||||
|
|
||||||
[BUG FIXES]
|
[BUG FIXES]
|
||||||
|
|
||||||
* Fix for latest DBIx::Class (deploy)
|
* Fix for latest DBIx::Class (deploy)
|
||||||
* Fix for latest Dancer (YAML::XS)
|
* Fix for latest Dancer (YAML::XS)
|
||||||
|
* [#160] Job Queue fatal error on num_slots
|
||||||
|
* [#157] Device Port Log being emptied by device discover
|
||||||
|
* [#156] Only delete node_ip and node_nbt when no active nodes reference
|
||||||
|
* [#169] Remove ref to force install of Dancer and DBIC
|
||||||
|
|
||||||
2.029012 - 2014-10-09
|
2.029012 - 2014-10-09
|
||||||
|
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ requires:
|
|||||||
Net::DNS: 0.72
|
Net::DNS: 0.72
|
||||||
Net::Domain: 1.23
|
Net::Domain: 1.23
|
||||||
Net::LDAP: 0
|
Net::LDAP: 0
|
||||||
Net::MAC: 2.103622
|
|
||||||
NetAddr::IP: 4.068
|
NetAddr::IP: 4.068
|
||||||
|
NetAddr::MAC: 0.87
|
||||||
Opcode: 1.07
|
Opcode: 1.07
|
||||||
Path::Class: 0.32
|
Path::Class: 0.32
|
||||||
Plack: 1.0023
|
Plack: 1.0023
|
||||||
@@ -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.029012
|
version: 2.029013_002
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use inc::Module::Install;
|
use inc::Module::Install;
|
||||||
|
|
||||||
name 'App-Netdisco';
|
name 'App-Netdisco';
|
||||||
license 'bsd';
|
license 'bsd';
|
||||||
all_from 'lib/App/Netdisco.pm';
|
all_from 'lib/App/Netdisco.pm';
|
||||||
|
|
||||||
test_requires 'Test::More' => 0.88;
|
test_requires 'Test::More' => 0.88;
|
||||||
test_requires 'Env::Path' => 0;
|
test_requires 'Env::Path' => 0;
|
||||||
|
|
||||||
requires 'Algorithm::Cron' => 0.07;
|
requires 'Algorithm::Cron' => 0.07;
|
||||||
requires 'AnyEvent' => 7.05;
|
requires 'AnyEvent' => 7.05;
|
||||||
requires 'AnyEvent::DNS::EtcHosts' => 0;
|
requires 'AnyEvent::DNS::EtcHosts' => 0;
|
||||||
@@ -38,7 +38,7 @@ requires 'MCE' => 1.515;
|
|||||||
requires 'Net::Domain' => 1.23;
|
requires 'Net::Domain' => 1.23;
|
||||||
requires 'Net::DNS' => 0.72;
|
requires 'Net::DNS' => 0.72;
|
||||||
requires 'Net::LDAP' => 0;
|
requires 'Net::LDAP' => 0;
|
||||||
requires 'Net::MAC' => 2.103622;
|
requires 'NetAddr::MAC' => 0.87;
|
||||||
requires 'NetAddr::IP' => 4.068;
|
requires 'NetAddr::IP' => 4.068;
|
||||||
requires 'Opcode' => 1.07;
|
requires 'Opcode' => 1.07;
|
||||||
requires 'Path::Class' => 0.32;
|
requires 'Path::Class' => 0.32;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use 5.010_000;
|
use 5.010_000;
|
||||||
|
|
||||||
our $VERSION = '2.029012';
|
our $VERSION = '2.029013_002';
|
||||||
use App::Netdisco::Configuration;
|
use App::Netdisco::Configuration;
|
||||||
|
|
||||||
use Module::Find ();
|
use Module::Find ();
|
||||||
@@ -75,7 +75,8 @@ On Fedora/Red-Hat:
|
|||||||
|
|
||||||
root:~# yum install perl-core perl-DBD-Pg net-snmp-perl make automake gcc
|
root:~# yum install perl-core perl-DBD-Pg net-snmp-perl make automake gcc
|
||||||
|
|
||||||
With those installed, we can proceed...
|
With those installed, next check that your system's clock is correct. Then, we
|
||||||
|
can proceed...
|
||||||
|
|
||||||
Create a user on your system called C<netdisco> if one does not already exist.
|
Create a user on your system called C<netdisco> if one does not already exist.
|
||||||
We'll install Netdisco and its dependencies into this user's home area, which
|
We'll install Netdisco and its dependencies into this user's home area, which
|
||||||
@@ -123,7 +124,6 @@ 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:
|
||||||
|
|
||||||
@@ -203,9 +203,6 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use NetAddr::IP::Lite ':lower';
|
|||||||
use List::MoreUtils ();
|
use List::MoreUtils ();
|
||||||
use Encode;
|
use Encode;
|
||||||
use Try::Tiny;
|
use Try::Tiny;
|
||||||
use Net::MAC;
|
use NetAddr::MAC;
|
||||||
|
|
||||||
use base 'Exporter';
|
use base 'Exporter';
|
||||||
our @EXPORT = ();
|
our @EXPORT = ();
|
||||||
@@ -754,9 +754,9 @@ sub store_neighbors {
|
|||||||
$device->ip, $remote_ip, $port, $remote_id;
|
$device->ip, $remote_ip, $port, $remote_id;
|
||||||
|
|
||||||
if (!defined $neigh) {
|
if (!defined $neigh) {
|
||||||
my $mac = Net::MAC->new(mac => $remote_id, 'die' => 0, verbose => 0);
|
my $mac = NetAddr::MAC->new(mac => $remote_id);
|
||||||
if (not $mac->get_error) {
|
if ($mac and not $mac->errstr) {
|
||||||
$neigh = $devices->single({mac => $mac->as_IEEE()});
|
$neigh = $devices->single({mac => $mac->as_microsoft()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -765,13 +765,13 @@ sub store_neighbors {
|
|||||||
# "myswitchname(012345-012345)"
|
# "myswitchname(012345-012345)"
|
||||||
if (!defined $neigh) {
|
if (!defined $neigh) {
|
||||||
(my $tmpid = $remote_id) =~ s/.([0-9a-f]{6})-([0-9a-f]{6})./$1$2/;
|
(my $tmpid = $remote_id) =~ s/.([0-9a-f]{6})-([0-9a-f]{6})./$1$2/;
|
||||||
my $mac = Net::MAC->new(mac => $tmpid, 'die' => 0, verbose => 0);
|
my $mac = NetAddr::MAC->new(mac => $tmpid);
|
||||||
|
|
||||||
if (not $mac->get_error) {
|
if ($mac and not $mac->errstr) {
|
||||||
info sprintf
|
info sprintf
|
||||||
'[%s] neigh - found neighbor %s by MAC %s',
|
'[%s] neigh - found neighbor %s by MAC %s',
|
||||||
$device->ip, $remote_id, $mac->as_IEEE();
|
$device->ip, $remote_id, $mac->as_microsoft();
|
||||||
$neigh = $devices->single({mac => $mac->as_IEEE()});
|
$neigh = $devices->single({mac => $mac->as_microsoft()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,10 +112,15 @@ sub do_macsuck {
|
|||||||
$ip, $total_nodes;
|
$ip, $total_nodes;
|
||||||
|
|
||||||
# a use for $now ... need to archive dissapeared nodes
|
# a use for $now ... need to archive dissapeared nodes
|
||||||
my $archived = schema('netdisco')->resultset('Node')->search({
|
my $archived = 0;
|
||||||
switch => $ip,
|
|
||||||
time_last => { '<' => \$now },
|
if (setting('node_freshness')) {
|
||||||
})->update({ active => \'false' });
|
$archived = schema('netdisco')->resultset('Node')->search({
|
||||||
|
switch => $ip,
|
||||||
|
time_last => \[ "< ($now - ?::interval)",
|
||||||
|
setting('node_freshness') .' minutes' ],
|
||||||
|
})->update({ active => \'false' });
|
||||||
|
}
|
||||||
|
|
||||||
debug sprintf ' [%s] macsuck - removed %d fwd table entries to archive',
|
debug sprintf ' [%s] macsuck - removed %d fwd table entries to archive',
|
||||||
$ip, $archived;
|
$ip, $archived;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ package App::Netdisco::DB::Result::DevicePort;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Net::MAC;
|
use NetAddr::MAC;
|
||||||
|
|
||||||
use MIME::Base64 'encode_base64url';
|
use MIME::Base64 'encode_base64url';
|
||||||
|
|
||||||
@@ -339,10 +339,10 @@ sub base64url_port { return encode_base64url((shift)->port) }
|
|||||||
|
|
||||||
=head2 net_mac
|
=head2 net_mac
|
||||||
|
|
||||||
Returns the C<mac> column instantiated into a L<Net::MAC> object.
|
Returns the C<mac> column instantiated into a L<NetAddr::MAC> object.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub net_mac { return Net::MAC->new(mac => (shift)->mac) }
|
sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ package App::Netdisco::DB::Result::Node;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Net::MAC;
|
use NetAddr::MAC;
|
||||||
|
|
||||||
use base 'DBIx::Class::Core';
|
use base 'DBIx::Class::Core';
|
||||||
__PACKAGE__->table("node");
|
__PACKAGE__->table("node");
|
||||||
@@ -175,10 +175,10 @@ sub time_last_stamp { return (shift)->get_column('time_last_stamp') }
|
|||||||
|
|
||||||
=head2 net_mac
|
=head2 net_mac
|
||||||
|
|
||||||
Returns the C<mac> column instantiated into a L<Net::MAC> object.
|
Returns the C<mac> column instantiated into a L<NetAddr::MAC> object.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub net_mac { return Net::MAC->new(mac => (shift)->mac) }
|
sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ package App::Netdisco::DB::Result::NodeIp;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Net::MAC;
|
use NetAddr::MAC;
|
||||||
|
|
||||||
use base 'DBIx::Class::Core';
|
use base 'DBIx::Class::Core';
|
||||||
__PACKAGE__->table("node_ip");
|
__PACKAGE__->table("node_ip");
|
||||||
@@ -221,10 +221,10 @@ sub time_last_stamp { return (shift)->get_column('time_last_stamp') }
|
|||||||
|
|
||||||
=head2 net_mac
|
=head2 net_mac
|
||||||
|
|
||||||
Returns the C<mac> column instantiated into a L<Net::MAC> object.
|
Returns the C<mac> column instantiated into a L<NetAddr::MAC> object.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub net_mac { return Net::MAC->new(mac => (shift)->mac) }
|
sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ package App::Netdisco::DB::Result::NodeNbt;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Net::MAC;
|
use NetAddr::MAC;
|
||||||
|
|
||||||
use base 'DBIx::Class::Core';
|
use base 'DBIx::Class::Core';
|
||||||
__PACKAGE__->table("node_nbt");
|
__PACKAGE__->table("node_nbt");
|
||||||
@@ -178,10 +178,10 @@ sub time_last_stamp { return (shift)->get_column('time_last_stamp') }
|
|||||||
|
|
||||||
=head2 net_mac
|
=head2 net_mac
|
||||||
|
|
||||||
Returns the C<mac> column instantiated into a L<Net::MAC> object.
|
Returns the C<mac> column instantiated into a L<NetAddr::MAC> object.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub net_mac { return Net::MAC->new(mac => (shift)->mac) }
|
sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ package App::Netdisco::DB::Result::NodeWireless;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Net::MAC;
|
use NetAddr::MAC;
|
||||||
|
|
||||||
use base 'DBIx::Class::Core';
|
use base 'DBIx::Class::Core';
|
||||||
__PACKAGE__->table("node_wireless");
|
__PACKAGE__->table("node_wireless");
|
||||||
@@ -87,10 +87,10 @@ __PACKAGE__->belongs_to( node => 'App::Netdisco::DB::Result::Node',
|
|||||||
|
|
||||||
=head2 net_mac
|
=head2 net_mac
|
||||||
|
|
||||||
Returns the C<mac> column instantiated into a L<Net::MAC> object.
|
Returns the C<mac> column instantiated into a L<NetAddr::MAC> object.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub net_mac { return Net::MAC->new(mac => (shift)->mac) }
|
sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -157,7 +157,6 @@ 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 }},
|
||||||
|
|||||||
@@ -109,9 +109,30 @@ sub delete {
|
|||||||
return 0E0;
|
return 0E0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
# for node_ip and node_nbt *only* delete if there are no longer
|
||||||
|
# any active nodes referencing the IP or NBT (hence 2nd IN clause).
|
||||||
foreach my $set (qw/
|
foreach my $set (qw/
|
||||||
NodeIp
|
NodeIp
|
||||||
NodeNbt
|
NodeNbt
|
||||||
|
/) {
|
||||||
|
$schema->resultset($set)->search({
|
||||||
|
'-and' => [
|
||||||
|
'me.mac' => { '-in' => $nodes->as_query },
|
||||||
|
'me.mac' => { '-in' => $schema->resultset($set)->search({
|
||||||
|
-bool => 'nodes.active',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
columns => 'mac',
|
||||||
|
join => 'nodes',
|
||||||
|
group_by => 'me.mac',
|
||||||
|
having => \[ 'count(nodes.mac) = 0' ],
|
||||||
|
})->as_query,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})->delete;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $set (qw/
|
||||||
NodeMonitor
|
NodeMonitor
|
||||||
NodeWireless
|
NodeWireless
|
||||||
/) {
|
/) {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ use namespace::clean;
|
|||||||
|
|
||||||
use App::Netdisco::JobQueue qw/jq_defer jq_complete/;
|
use App::Netdisco::JobQueue qw/jq_defer jq_complete/;
|
||||||
|
|
||||||
|
sub worker_begin { (shift)->{started} = time }
|
||||||
|
|
||||||
sub worker_body {
|
sub worker_body {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $wid = $self->wid;
|
my $wid = $self->wid;
|
||||||
@@ -38,6 +40,14 @@ sub worker_body {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$self->close_job($job);
|
$self->close_job($job);
|
||||||
|
|
||||||
|
# restart worker once a day.
|
||||||
|
# relies on the worker seeing a job at least every hour.
|
||||||
|
my $hour = [localtime()]->[2];
|
||||||
|
if ($wid and (time >= ($self->{started} + 86400))
|
||||||
|
and ($hour == ($wid % 24))) {
|
||||||
|
$self->exit(0, "recycling worker $wid");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,26 +25,40 @@ our @EXPORT_OK = qw/
|
|||||||
/;
|
/;
|
||||||
our %EXPORT_TAGS = ( all => \@EXPORT_OK );
|
our %EXPORT_TAGS = ( all => \@EXPORT_OK );
|
||||||
|
|
||||||
sub jq_getsome {
|
sub _getsome {
|
||||||
my ($num_slots, $prio) = @_;
|
my ($num_slots, $where) = @_;
|
||||||
return () if defined $num_slots and $num_slots eq '0';
|
return () if ((!defined $num_slots) or ($num_slots < 1));
|
||||||
$num_slots ||= 1;
|
return () if ((!defined $where) or (ref {} ne ref $where));
|
||||||
$prio ||= 'normal';
|
|
||||||
my @returned = ();
|
|
||||||
|
|
||||||
my $rs = schema('netdisco')->resultset('Admin')
|
my $rs = schema('netdisco')->resultset('Admin')
|
||||||
->search(
|
->search(
|
||||||
{status => 'queued', action => { -in => setting('job_prio')->{$prio} } },
|
{ status => 'queued', %$where },
|
||||||
{order_by => 'random()', rows => ($num_slots || 1)},
|
{ order_by => 'random()', rows => $num_slots },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
my @returned = ();
|
||||||
while (my $job = $rs->next) {
|
while (my $job = $rs->next) {
|
||||||
push @returned, App::Netdisco::Daemon::Job->new({ $job->get_columns });
|
push @returned, App::Netdisco::Daemon::Job->new({ $job->get_columns });
|
||||||
}
|
}
|
||||||
return @returned;
|
return @returned;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub jq_getsomep { return jq_getsome(shift, 'high') }
|
sub jq_getsome {
|
||||||
|
return _getsome(shift,
|
||||||
|
{ action => { -in => setting('job_prio')->{'normal'} } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub jq_getsomep {
|
||||||
|
return _getsome(shift, {
|
||||||
|
-or => [{
|
||||||
|
username => { '!=' => undef },
|
||||||
|
action => { -in => setting('job_prio')->{'normal'} },
|
||||||
|
},{
|
||||||
|
action => { -in => setting('job_prio')->{'high'} },
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
sub jq_locked {
|
sub jq_locked {
|
||||||
my $fqdn = hostfqdn || 'localhost';
|
my $fqdn = hostfqdn || 'localhost';
|
||||||
|
|||||||
@@ -741,6 +741,21 @@ Value: Number. Default: 1.
|
|||||||
Seconds nbtstat will wait for a response before time out. Accepts fractional
|
Seconds nbtstat will wait for a response before time out. Accepts fractional
|
||||||
seconds as well as integers.
|
seconds as well as integers.
|
||||||
|
|
||||||
|
=head3 C<node_freshness>
|
||||||
|
|
||||||
|
Value: Number of Minutes. Default: 0
|
||||||
|
|
||||||
|
Controls the behaviour of Netdisco when a node (workstation, printer, etc) has
|
||||||
|
disappeared from the network (device MAC address tables).
|
||||||
|
|
||||||
|
If set to 0, the default, nodes will remain on the last-seen switch port until
|
||||||
|
"C<expire_nodes>" days have passed (when they'll be deleted if you run the
|
||||||
|
Expire job). This is the same behaviour as Netdisco 1.
|
||||||
|
|
||||||
|
Set to a number of minutes to enforce some kind of ageing on this data. For
|
||||||
|
example you could set to 60 to match the default macsuck schedule, meaning
|
||||||
|
nodes are archived if they're not in the device tables at the time of polling.
|
||||||
|
|
||||||
=head3 C<expire_devices>
|
=head3 C<expire_devices>
|
||||||
|
|
||||||
Value: Number of Days. Default: 60
|
Value: Number of Days. Default: 60
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ the L<documentation|App::Netdisco>. Then:
|
|||||||
|
|
||||||
su - netdisco && cd $HOME
|
su - netdisco && cd $HOME
|
||||||
mkdir git && cd git
|
mkdir git && cd git
|
||||||
|
|
||||||
git clone git://git.code.sf.net/p/netdisco/netdisco-ng netdisco-ng
|
git clone git://git.code.sf.net/p/netdisco/netdisco-ng netdisco-ng
|
||||||
cd netdisco-ng/Netdisco
|
cd netdisco-ng/Netdisco
|
||||||
|
|
||||||
DBIC_TRACE=1 ~/bin/localenv plackup -R share,lib -p 5001 bin/netdisco-web-fg
|
DBIC_TRACE=1 ~/bin/localenv plackup -R share,lib -p 5001 bin/netdisco-web-fg
|
||||||
|
|
||||||
The above creates you a git clone (change the URL if you're a Netdisco
|
The above creates you a git clone (change the URL if you're a Netdisco
|
||||||
@@ -259,7 +259,7 @@ Compared to the current Netdisco, the handler routines are very small. This is
|
|||||||
because (a) they don't include any HTML - this is delegated to a template, and
|
because (a) they don't include any HTML - this is delegated to a template, and
|
||||||
(b) they don't include an SQL - this is delegated to DBIx::Class. Small
|
(b) they don't include an SQL - this is delegated to DBIx::Class. Small
|
||||||
routines are more manageable, and easier to maintain. You'll also notice use
|
routines are more manageable, and easier to maintain. You'll also notice use
|
||||||
of modules such as L<Net::MAC> and L<NetAddr::IP::Lite> to simplify and make
|
of modules such as L<NetAddr::MAC> and L<NetAddr::IP::Lite> to simplify and make
|
||||||
more robust the handling of data.
|
more robust the handling of data.
|
||||||
|
|
||||||
In fact, many sections of the web application have been factored out into
|
In fact, many sections of the web application have been factored out into
|
||||||
|
|||||||
@@ -36,6 +36,15 @@ but they are backwards compatible.
|
|||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
=head1 2.029013_002
|
||||||
|
|
||||||
|
=head2 General Notices
|
||||||
|
|
||||||
|
The node archiving behaviour of Netdisco 2 has until now been accidentally
|
||||||
|
different to that in Netdisco 1. This has now been fixed. See the new
|
||||||
|
"C<node_freshness>" configuration setting if you wish to revert or tune this
|
||||||
|
behaviour.
|
||||||
|
|
||||||
=head1 2.029010
|
=head1 2.029010
|
||||||
|
|
||||||
=head2 General Notices
|
=head2 General Notices
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ App::Netdisco::SSHCollector::Platform::IOSXR
|
|||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
Collect ARP entries from Cisco IOS XR devices.
|
Collect ARP entries from Cisco IOSXR devices.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
@@ -16,7 +16,6 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Dancer ':script';
|
use Dancer ':script';
|
||||||
use Expect;
|
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
=head1 PUBLIC METHODS
|
=head1 PUBLIC METHODS
|
||||||
@@ -36,28 +35,19 @@ sub arpnip {
|
|||||||
my ($self, $hostlabel, $ssh, @args) = @_;
|
my ($self, $hostlabel, $ssh, @args) = @_;
|
||||||
|
|
||||||
debug "$hostlabel $$ arpnip()";
|
debug "$hostlabel $$ arpnip()";
|
||||||
|
my @data = $ssh->capture("show arp vrf all");
|
||||||
|
|
||||||
my ($pty, $pid) = $ssh->open2pty or die "unable to run remote command";
|
chomp @data;
|
||||||
my $expect = Expect->init($pty);
|
|
||||||
|
|
||||||
my ($pos, $error, $match, $before, $after);
|
|
||||||
my $prompt = qr/#/;
|
|
||||||
|
|
||||||
($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);
|
|
||||||
|
|
||||||
$expect->send("terminal length 0\n");
|
|
||||||
($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);
|
|
||||||
|
|
||||||
my @arpentries;
|
my @arpentries;
|
||||||
|
|
||||||
$expect->send("show arp vrf all\n");
|
|
||||||
($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);
|
|
||||||
|
|
||||||
# 0.0.0.0 00:00:00 0000.0000.0000 Dynamic ARPA GigabitEthernet0/0/0/0
|
# 0.0.0.0 00:00:00 0000.0000.0000 Dynamic ARPA GigabitEthernet0/0/0/0
|
||||||
for (split(/\n/, $before)){
|
foreach (@data) {
|
||||||
|
|
||||||
my ($ip, $age, $mac, $state, $t, $iface) = split(/\s+/);
|
my ($ip, $age, $mac, $state, $t, $iface) = split(/\s+/);
|
||||||
if ($ip =~ m/(\d{1,3}\.){3}\d{1,3}/ && $mac =~ m/[0-9a-f.]+/i) {
|
|
||||||
push(@arpentries, { ip => $ip, mac => $mac });
|
if ($ip =~ m/(\d{1,3}\.){3}\d{1,3}/
|
||||||
|
&& $mac =~ m/([0-9a-f]{4}\.){2}[0-9a-f]{4}/i) {
|
||||||
|
push(@arpentries, { ip => $ip, mac => $mac });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package App::Netdisco::Util::Node;
|
|||||||
use Dancer qw/:syntax :script/;
|
use Dancer qw/:syntax :script/;
|
||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
|
|
||||||
use Net::MAC;
|
use NetAddr::MAC;
|
||||||
use App::Netdisco::Util::Permission 'check_acl';
|
use App::Netdisco::Util::Permission 'check_acl';
|
||||||
|
|
||||||
use base 'Exporter';
|
use base 'Exporter';
|
||||||
@@ -66,23 +66,23 @@ MAC address does not belong to an interface on any known Device
|
|||||||
|
|
||||||
sub check_mac {
|
sub check_mac {
|
||||||
my ($device, $node, $port_macs) = @_;
|
my ($device, $node, $port_macs) = @_;
|
||||||
my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0);
|
my $mac = NetAddr::MAC->new(mac => $node);
|
||||||
my $devip = (ref $device ? $device->ip : '');
|
my $devip = (ref $device ? $device->ip : '');
|
||||||
$port_macs ||= {};
|
$port_macs ||= {};
|
||||||
|
|
||||||
# incomplete MAC addresses (BayRS frame relay DLCI, etc)
|
# incomplete MAC addresses (BayRS frame relay DLCI, etc)
|
||||||
if ($mac->get_error) {
|
if (!defined $mac or $mac->errstr) {
|
||||||
debug sprintf ' [%s] check_mac - mac [%s] malformed - skipping',
|
debug sprintf ' [%s] check_mac - mac [%s] malformed - skipping',
|
||||||
$devip, $node;
|
$devip, $node;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
# lower case, hex, colon delimited, 8-bit groups
|
# lower case, hex, colon delimited, 8-bit groups
|
||||||
$node = lc $mac->as_IEEE;
|
$node = lc $mac->as_microsoft;
|
||||||
}
|
}
|
||||||
|
|
||||||
# broadcast MAC addresses
|
# broadcast MAC addresses
|
||||||
return 0 if $node eq 'ff:ff:ff:ff:ff:ff';
|
return 0 if $mac->is_broadcast;
|
||||||
|
|
||||||
# all-zero MAC addresses
|
# all-zero MAC addresses
|
||||||
return 0 if $node eq '00:00:00:00:00:00';
|
return 0 if $node eq '00:00:00:00:00:00';
|
||||||
@@ -91,21 +91,21 @@ sub check_mac {
|
|||||||
return 0 if $node eq '00:00:00:00:00:01';
|
return 0 if $node eq '00:00:00:00:00:01';
|
||||||
|
|
||||||
# multicast
|
# multicast
|
||||||
if ($node =~ m/^[0-9a-f](?:1|3|5|7|9|b|d|f):/) {
|
if ($mac->is_multicast and not $mac->is_msnlb) {
|
||||||
debug sprintf ' [%s] check_mac - multicast mac [%s] - skipping',
|
debug sprintf ' [%s] check_mac - multicast mac [%s] - skipping',
|
||||||
$devip, $node;
|
$devip, $node;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
# VRRP
|
# VRRP
|
||||||
if (index($node, '00:00:5e:00:01:') == 0) {
|
if ($mac->is_vrrp) {
|
||||||
debug sprintf ' [%s] check_mac - VRRP mac [%s] - skipping',
|
debug sprintf ' [%s] check_mac - VRRP mac [%s] - skipping',
|
||||||
$devip, $node;
|
$devip, $node;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
# HSRP
|
# HSRP
|
||||||
if (index($node, '00:00:0c:07:ac:') == 0) {
|
if ($mac->is_hsrp or $mac->is_hsrp2) {
|
||||||
debug sprintf ' [%s] check_mac - HSRP mac [%s] - skipping',
|
debug sprintf ' [%s] check_mac - HSRP mac [%s] - skipping',
|
||||||
$devip, $node;
|
$devip, $node;
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use Dancer::Plugin::DBIC;
|
|||||||
use Dancer::Plugin::Auth::Extensible;
|
use Dancer::Plugin::Auth::Extensible;
|
||||||
|
|
||||||
use NetAddr::IP::Lite ':lower';
|
use NetAddr::IP::Lite ':lower';
|
||||||
use Net::MAC ();
|
use NetAddr::MAC ();
|
||||||
|
|
||||||
use App::Netdisco::Web::Plugin;
|
use App::Netdisco::Web::Plugin;
|
||||||
use App::Netdisco::Util::Web 'sql_match';
|
use App::Netdisco::Util::Web 'sql_match';
|
||||||
@@ -20,9 +20,9 @@ ajax '/ajax/content/search/node' => require_login sub {
|
|||||||
content_type('text/html');
|
content_type('text/html');
|
||||||
|
|
||||||
my $agenot = param('age_invert') || '0';
|
my $agenot = param('age_invert') || '0';
|
||||||
my ( $start, $end ) = param('daterange') =~ /(\d+-\d+-\d+)/gmx;
|
my ( $start, $end ) = param('daterange') =~ m/(\d+-\d+-\d+)/gmx;
|
||||||
|
|
||||||
my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0);
|
my $mac = NetAddr::MAC->new(mac => $node);
|
||||||
my @active = (param('archived') ? () : (-bool => 'active'));
|
my @active = (param('archived') ? () : (-bool => 'active'));
|
||||||
|
|
||||||
my @times = ();
|
my @times = ();
|
||||||
@@ -48,7 +48,7 @@ ajax '/ajax/content/search/node' => require_login sub {
|
|||||||
|
|
||||||
my @where_mac =
|
my @where_mac =
|
||||||
($using_wildcards ? \['me.mac::text ILIKE ?', $likeval]
|
($using_wildcards ? \['me.mac::text ILIKE ?', $likeval]
|
||||||
: ($mac->get_error ? \'0=1' : ('me.mac' => $mac->as_IEEE)) );
|
: ((!defined $mac or $mac->errstr) ? \'0=1' : ('me.mac' => $mac->as_microsoft)) );
|
||||||
|
|
||||||
my $sightings = schema('netdisco')->resultset('Node')
|
my $sightings = schema('netdisco')->resultset('Node')
|
||||||
->search({-and => [@where_mac, @active, @times]}, {
|
->search({-and => [@where_mac, @active, @times]}, {
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ nbtstat_only: []
|
|||||||
nbtstat_max_age: 7
|
nbtstat_max_age: 7
|
||||||
nbtstat_interval: 0.02
|
nbtstat_interval: 0.02
|
||||||
nbtstat_timeout: 1
|
nbtstat_timeout: 1
|
||||||
|
node_freshness: 0
|
||||||
expire_devices: 60
|
expire_devices: 60
|
||||||
expire_nodes: 90
|
expire_nodes: 90
|
||||||
expire_nodes_archive: 60
|
expire_nodes_archive: 60
|
||||||
|
|||||||
@@ -83,14 +83,18 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>Administration</td>
|
<td>Administration</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="ssh://[% d.ip | html_entity %]" target="_blank">
|
<a href="ssh://[% d.ip | uri %]" target="_blank">
|
||||||
<span class="label label-info"><i class="icon-keyboard"></i> SSH</span></a>
|
<span class="label label-info"><i class="icon-keyboard"></i> SSH</span></a>
|
||||||
<a href="telnet://[% d.ip | html_entity %]" target="_blank">
|
<a href="telnet://[% d.ip | uri %]" target="_blank">
|
||||||
<span class="label label-info"><i class="icon-keyboard"></i> Telnet</span></a>
|
<span class="label label-info"><i class="icon-keyboard"></i> Telnet</span></a>
|
||||||
<a href="https://[% d.ip | html_entity %]/" target="_blank">
|
<a href="https://[% d.ip | uri %]/" target="_blank">
|
||||||
<span class="label label-info"><i class="icon-external-link"></i> Web</span></a>
|
<span class="label label-info"><i class="icon-external-link"></i> Web</span></a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SNMP Class</td>
|
||||||
|
<td><a target="_blank" href="https://metacpan.org/pod/[% d.snmp_class | uri %]">[% d.snmp_class | html_entity %]</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Uptime</td>
|
<td>Uptime</td>
|
||||||
<td>[% d.uptime_age | html_entity %]</td>
|
<td>[% d.uptime_age | html_entity %]</td>
|
||||||
|
|||||||
@@ -122,6 +122,11 @@
|
|||||||
<button type="submit" class="btn btn-link nd_btn-link">NBTstat All</button>
|
<button type="submit" class="btn btn-link nd_btn-link">NBTstat All</button>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<form method="post" class="nd_inline-form" action="[% uri_for('/admin/expire') %]">
|
||||||
|
<button type="submit" class="btn btn-link nd_btn-link">Run Expire Job</button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
[% IF settings._admin_tasks.size %]
|
[% IF settings._admin_tasks.size %]
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
[% FOREACH ai IN settings._admin_order %]
|
[% FOREACH ai IN settings._admin_order %]
|
||||||
|
|||||||
@@ -128,9 +128,10 @@
|
|||||||
<li>
|
<li>
|
||||||
<em class="muted">MAC address format:</em><br/>
|
<em class="muted">MAC address format:</em><br/>
|
||||||
<select id="nd_mac-format" name="mac_format">
|
<select id="nd_mac-format" name="mac_format">
|
||||||
[% FOREACH format IN [ 'IEEE', 'Cisco', 'Microsoft', 'Sun' ] %]
|
<option[% ' selected="selected"' IF params.mac_format == 'Cisco' %]>Cisco</option>
|
||||||
<option[% ' selected="selected"' IF params.mac_format == format %]>[% format %]</option>
|
<option[% ' selected="selected"' IF params.mac_format == 'Microsoft' %] value="Microsoft">IEEE</option>
|
||||||
[% END %]
|
<option[% ' selected="selected"' IF params.mac_format == 'IEEE' %] value="IEEE">Microsoft</option>
|
||||||
|
<option[% ' selected="selected"' IF params.mac_format == 'Sun' %]>Sun</option>
|
||||||
</select>
|
</select>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -55,9 +55,10 @@
|
|||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
<em class="muted">MAC address format:</em><br/>
|
<em class="muted">MAC address format:</em><br/>
|
||||||
<select id="nd_node-mac-format" name="mac_format">
|
<select id="nd_node-mac-format" name="mac_format">
|
||||||
[% FOREACH format IN [ 'IEEE', 'Cisco', 'Microsoft', 'Sun' ] %]
|
<option[% ' selected="selected"' IF params.mac_format == 'Cisco' %]>Cisco</option>
|
||||||
<option[% ' selected="selected"' IF params.mac_format == format %]>[% format %]</option>
|
<option[% ' selected="selected"' IF params.mac_format == 'Microsoft' %] value="Microsoft">IEEE</option>
|
||||||
[% END %]
|
<option[% ' selected="selected"' IF params.mac_format == 'IEEE' %] value="IEEE">Microsoft</option>
|
||||||
|
<option[% ' selected="selected"' IF params.mac_format == 'Sun' %]>Sun</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<button id="[% tab.tag %]_submit" type="submit" class="btn btn-info">
|
<button id="[% tab.tag %]_submit" type="submit" class="btn btn-info">
|
||||||
|
|||||||
Reference in New Issue
Block a user