Merge branch 'master' into og-api-tokens-simple
This commit is contained in:
5
Build.PL
5
Build.PL
@@ -17,6 +17,7 @@ Module::Build->new(
|
|||||||
},
|
},
|
||||||
requires => {
|
requires => {
|
||||||
'aliased' => '0',
|
'aliased' => '0',
|
||||||
|
'autovivification' => '0',
|
||||||
'namespace::clean' => '0.24',
|
'namespace::clean' => '0.24',
|
||||||
'version' => '0.9902',
|
'version' => '0.9902',
|
||||||
'Algorithm::Cron' => '0.07',
|
'Algorithm::Cron' => '0.07',
|
||||||
@@ -46,7 +47,7 @@ Module::Build->new(
|
|||||||
'JSON' => '2.90',
|
'JSON' => '2.90',
|
||||||
'JSON::XS' => '3.01',
|
'JSON::XS' => '3.01',
|
||||||
'List::Util' => '1.49',
|
'List::Util' => '1.49',
|
||||||
'List::MoreUtils' => '0.33',
|
'List::MoreUtils' => '0.428',
|
||||||
'MIME::Base64' => '3.13',
|
'MIME::Base64' => '3.13',
|
||||||
'Module::Load' => '0.32',
|
'Module::Load' => '0.32',
|
||||||
'Moo' => '1.001000',
|
'Moo' => '1.001000',
|
||||||
@@ -72,7 +73,7 @@ Module::Build->new(
|
|||||||
'Starman' => '0.4008',
|
'Starman' => '0.4008',
|
||||||
'Storable' => '0',
|
'Storable' => '0',
|
||||||
'Sys::SigAction' => '0',
|
'Sys::SigAction' => '0',
|
||||||
'SNMP::Info' => '3.64',
|
'SNMP::Info' => '3.65',
|
||||||
'SQL::Abstract' => '1.85',
|
'SQL::Abstract' => '1.85',
|
||||||
'SQL::Translator' => '0.11024',
|
'SQL::Translator' => '0.11024',
|
||||||
'Template' => '2.24',
|
'Template' => '2.24',
|
||||||
|
|||||||
73
Changes
73
Changes
@@ -1,3 +1,76 @@
|
|||||||
|
2.040007 - 2019-03-06
|
||||||
|
|
||||||
|
[BUG FIXES]
|
||||||
|
|
||||||
|
* #521-redux Search Node Date Range not working (ollyg)
|
||||||
|
|
||||||
|
2.040006 - 2019-03-04
|
||||||
|
|
||||||
|
[BUG FIXES]
|
||||||
|
|
||||||
|
* #527 update List::MoreUtils version requirement
|
||||||
|
|
||||||
|
2.040005 - 2019-03-04
|
||||||
|
|
||||||
|
[BUG FIXES]
|
||||||
|
|
||||||
|
* #526 fix discover syntax bug
|
||||||
|
|
||||||
|
2.040004 - 2019-03-03
|
||||||
|
|
||||||
|
[NEW FEATURES]
|
||||||
|
|
||||||
|
* #510 store ifindex in Device Port Properties table (rc9000)
|
||||||
|
* new discover_waps and discover_phones boolean settings (ollyg)
|
||||||
|
|
||||||
|
[ENHANCEMENTS]
|
||||||
|
|
||||||
|
* #428 Port-Channels now showing in netmap (ollyg)
|
||||||
|
* #490 use new LLDP capability checks for ports having phones (ollyg)
|
||||||
|
* #494 update Cisco ASA ssh collector (stromsoe)
|
||||||
|
|
||||||
|
[BUG FIXES]
|
||||||
|
|
||||||
|
* #492 Port Control incorrectly uses VLAN config check (inphobia)
|
||||||
|
* #493 HTML tag fix (inphobia)
|
||||||
|
* #498 Map with VLAN filter omits unconnected devices (ollyg)
|
||||||
|
* #499 netdisco-do renumber reports wrong ip (inphobia)
|
||||||
|
* #500 no more duplicate entries in vlan filter (ollyg)
|
||||||
|
* #505 renumbering device missed a few tables (ollyg)
|
||||||
|
* #512 fix regression in phone/wap discovery exclusion (ollyg)
|
||||||
|
* #514 ipinventory report returns consistent data (inphobia)
|
||||||
|
* #520 make sure aggports have a master<->slave (ollyg)
|
||||||
|
* #521 Search Node Date Range not working (ollyg)
|
||||||
|
* #522 TypeAhead.pm can reference empty data (inphobia)
|
||||||
|
* fix bug showing no nodes when only one matches in netmap (ollyg)
|
||||||
|
|
||||||
|
2.040003 - 2019-01-18
|
||||||
|
|
||||||
|
[NEW FEATURES]
|
||||||
|
|
||||||
|
* #485 new "VLANs" device tab showing a VLAN report (inphobia)
|
||||||
|
|
||||||
|
[ENHANCEMENTS]
|
||||||
|
|
||||||
|
* #408, #417 & 477 makerancidconf improvements re-added (earendilfr, inphobia)
|
||||||
|
* #420 IP Inventory Node column renamed to IP Address (ollyg)
|
||||||
|
* #420 sidebar defaults for IP Inventory report can be overridden (ollyg)
|
||||||
|
* #424 column name is "Connected Nodes & Devices" when both are shown (ollyg)
|
||||||
|
* #436 make neighbor matching less strict in netmap (linwood-f)
|
||||||
|
* #482 operating system is now a link in device details (inphobia)
|
||||||
|
* #486 allow snmp::info base class in netdisco-do (inphobia)
|
||||||
|
|
||||||
|
[BUG FIXES]
|
||||||
|
|
||||||
|
* #457 make sorting work for adresses when interface was undefined (inphobia)
|
||||||
|
* #471-redux ospf discovery will now keep on working (ollyg)
|
||||||
|
* #474 better explain public key auth with netdisco-sshcollector (inphobia)
|
||||||
|
* #475, #479 all discover plugins should now respect ignore_* for interfaces (ollyg)
|
||||||
|
* #476 debug log when deleting rows from related tables (ollyg)
|
||||||
|
* Fix to catch when txrate on wifi is scalar and not a list
|
||||||
|
* Remove 'use vars' which is deprecated in Perl
|
||||||
|
* Various documentation improvements (inphobia)
|
||||||
|
|
||||||
2.040002 - 2018-12-30
|
2.040002 - 2018-12-30
|
||||||
|
|
||||||
[BUG FIXES]
|
[BUG FIXES]
|
||||||
|
|||||||
4
MANIFEST
4
MANIFEST
@@ -151,6 +151,7 @@ lib/App/Netdisco/Web/Plugin/Device/Details.pm
|
|||||||
lib/App/Netdisco/Web/Plugin/Device/Modules.pm
|
lib/App/Netdisco/Web/Plugin/Device/Modules.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm
|
lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Device/Ports.pm
|
lib/App/Netdisco/Web/Plugin/Device/Ports.pm
|
||||||
|
lib/App/Netdisco/Web/Plugin/Device/Vlans.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Inventory.pm
|
lib/App/Netdisco/Web/Plugin/Inventory.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Report/ApChannelDist.pm
|
lib/App/Netdisco/Web/Plugin/Report/ApChannelDist.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Report/ApClients.pm
|
lib/App/Netdisco/Web/Plugin/Report/ApClients.pm
|
||||||
@@ -363,6 +364,7 @@ share/schema_versions/App-Netdisco-DB-5-6-PostgreSQL.sql
|
|||||||
share/schema_versions/App-Netdisco-DB-50-51-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-50-51-PostgreSQL.sql
|
||||||
share/schema_versions/App-Netdisco-DB-51-52-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-51-52-PostgreSQL.sql
|
||||||
share/schema_versions/App-Netdisco-DB-52-53-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-52-53-PostgreSQL.sql
|
||||||
|
share/schema_versions/App-Netdisco-DB-53-54-PostgreSQL.sql
|
||||||
share/schema_versions/App-Netdisco-DB-6-7-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-6-7-PostgreSQL.sql
|
||||||
share/schema_versions/App-Netdisco-DB-7-8-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-7-8-PostgreSQL.sql
|
||||||
share/schema_versions/App-Netdisco-DB-8-9-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-8-9-PostgreSQL.sql
|
||||||
@@ -391,6 +393,8 @@ share/views/ajax/device/modules.tt
|
|||||||
share/views/ajax/device/netmap.tt
|
share/views/ajax/device/netmap.tt
|
||||||
share/views/ajax/device/ports.tt
|
share/views/ajax/device/ports.tt
|
||||||
share/views/ajax/device/ports_csv.tt
|
share/views/ajax/device/ports_csv.tt
|
||||||
|
share/views/ajax/device/vlans.tt
|
||||||
|
share/views/ajax/device/vlans_csv.tt
|
||||||
share/views/ajax/report/apchanneldist.tt
|
share/views/ajax/report/apchanneldist.tt
|
||||||
share/views/ajax/report/apchanneldist_csv.tt
|
share/views/ajax/report/apchanneldist_csv.tt
|
||||||
share/views/ajax/report/apclients.tt
|
share/views/ajax/report/apclients.tt
|
||||||
|
|||||||
14
META.json
14
META.json
@@ -60,7 +60,7 @@
|
|||||||
"IO::Socket::SSL" : "2.048",
|
"IO::Socket::SSL" : "2.048",
|
||||||
"JSON" : "2.90",
|
"JSON" : "2.90",
|
||||||
"JSON::XS" : "3.01",
|
"JSON::XS" : "3.01",
|
||||||
"List::MoreUtils" : "0.33",
|
"List::MoreUtils" : "0.428",
|
||||||
"List::Util" : "1.49",
|
"List::Util" : "1.49",
|
||||||
"MCE" : "1.703",
|
"MCE" : "1.703",
|
||||||
"MIME::Base64" : "3.13",
|
"MIME::Base64" : "3.13",
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
"Plack::Middleware::ReverseProxy" : "0.15",
|
"Plack::Middleware::ReverseProxy" : "0.15",
|
||||||
"Pod::Usage" : "0",
|
"Pod::Usage" : "0",
|
||||||
"Role::Tiny" : "1.002005",
|
"Role::Tiny" : "1.002005",
|
||||||
"SNMP::Info" : "3.64",
|
"SNMP::Info" : "3.65",
|
||||||
"SQL::Abstract" : "1.85",
|
"SQL::Abstract" : "1.85",
|
||||||
"SQL::Translator" : "0.11024",
|
"SQL::Translator" : "0.11024",
|
||||||
"Scope::Guard" : "0",
|
"Scope::Guard" : "0",
|
||||||
@@ -102,6 +102,7 @@
|
|||||||
"YAML" : "0.84",
|
"YAML" : "0.84",
|
||||||
"YAML::XS" : "0.41",
|
"YAML::XS" : "0.41",
|
||||||
"aliased" : "0",
|
"aliased" : "0",
|
||||||
|
"autovivification" : "0",
|
||||||
"namespace::clean" : "0.24",
|
"namespace::clean" : "0.24",
|
||||||
"version" : "0.9902"
|
"version" : "0.9902"
|
||||||
}
|
}
|
||||||
@@ -117,7 +118,7 @@
|
|||||||
"provides" : {
|
"provides" : {
|
||||||
"App::Netdisco" : {
|
"App::Netdisco" : {
|
||||||
"file" : "lib/App/Netdisco.pm",
|
"file" : "lib/App/Netdisco.pm",
|
||||||
"version" : "2.040002"
|
"version" : "2.040007"
|
||||||
},
|
},
|
||||||
"App::Netdisco::AnyEvent::Nbtstat" : {
|
"App::Netdisco::AnyEvent::Nbtstat" : {
|
||||||
"file" : "lib/App/Netdisco/AnyEvent/Nbtstat.pm"
|
"file" : "lib/App/Netdisco/AnyEvent/Nbtstat.pm"
|
||||||
@@ -139,7 +140,7 @@
|
|||||||
},
|
},
|
||||||
"App::Netdisco::DB" : {
|
"App::Netdisco::DB" : {
|
||||||
"file" : "lib/App/Netdisco/DB.pm",
|
"file" : "lib/App/Netdisco/DB.pm",
|
||||||
"version" : "53"
|
"version" : "54"
|
||||||
},
|
},
|
||||||
"App::Netdisco::DB::ExplicitLocking" : {
|
"App::Netdisco::DB::ExplicitLocking" : {
|
||||||
"file" : "lib/App/Netdisco/DB/ExplicitLocking.pm"
|
"file" : "lib/App/Netdisco/DB/ExplicitLocking.pm"
|
||||||
@@ -531,6 +532,9 @@
|
|||||||
"App::Netdisco::Web::Plugin::Device::Ports" : {
|
"App::Netdisco::Web::Plugin::Device::Ports" : {
|
||||||
"file" : "lib/App/Netdisco/Web/Plugin/Device/Ports.pm"
|
"file" : "lib/App/Netdisco/Web/Plugin/Device/Ports.pm"
|
||||||
},
|
},
|
||||||
|
"App::Netdisco::Web::Plugin::Device::Vlans" : {
|
||||||
|
"file" : "lib/App/Netdisco/Web/Plugin/Device/Vlans.pm"
|
||||||
|
},
|
||||||
"App::Netdisco::Web::Plugin::Inventory" : {
|
"App::Netdisco::Web::Plugin::Inventory" : {
|
||||||
"file" : "lib/App/Netdisco/Web/Plugin/Inventory.pm"
|
"file" : "lib/App/Netdisco/Web/Plugin/Inventory.pm"
|
||||||
},
|
},
|
||||||
@@ -796,6 +800,6 @@
|
|||||||
"x_IRC" : "irc://irc.freenode.org/#netdisco",
|
"x_IRC" : "irc://irc.freenode.org/#netdisco",
|
||||||
"x_MailingList" : "https://lists.sourceforge.net/lists/listinfo/netdisco-users"
|
"x_MailingList" : "https://lists.sourceforge.net/lists/listinfo/netdisco-users"
|
||||||
},
|
},
|
||||||
"version" : "2.040002",
|
"version" : "2.040007",
|
||||||
"x_serialization_backend" : "JSON::PP version 2.97001"
|
"x_serialization_backend" : "JSON::PP version 2.97001"
|
||||||
}
|
}
|
||||||
|
|||||||
13
META.yml
13
META.yml
@@ -22,7 +22,7 @@ name: App-Netdisco
|
|||||||
provides:
|
provides:
|
||||||
App::Netdisco:
|
App::Netdisco:
|
||||||
file: lib/App/Netdisco.pm
|
file: lib/App/Netdisco.pm
|
||||||
version: '2.040002'
|
version: '2.040007'
|
||||||
App::Netdisco::AnyEvent::Nbtstat:
|
App::Netdisco::AnyEvent::Nbtstat:
|
||||||
file: lib/App/Netdisco/AnyEvent/Nbtstat.pm
|
file: lib/App/Netdisco/AnyEvent/Nbtstat.pm
|
||||||
App::Netdisco::Backend::Job:
|
App::Netdisco::Backend::Job:
|
||||||
@@ -37,7 +37,7 @@ provides:
|
|||||||
file: lib/App/Netdisco/Configuration.pm
|
file: lib/App/Netdisco/Configuration.pm
|
||||||
App::Netdisco::DB:
|
App::Netdisco::DB:
|
||||||
file: lib/App/Netdisco/DB.pm
|
file: lib/App/Netdisco/DB.pm
|
||||||
version: '53'
|
version: '54'
|
||||||
App::Netdisco::DB::ExplicitLocking:
|
App::Netdisco::DB::ExplicitLocking:
|
||||||
file: lib/App/Netdisco/DB/ExplicitLocking.pm
|
file: lib/App/Netdisco/DB/ExplicitLocking.pm
|
||||||
App::Netdisco::DB::Result::Admin:
|
App::Netdisco::DB::Result::Admin:
|
||||||
@@ -298,6 +298,8 @@ provides:
|
|||||||
file: lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm
|
file: lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm
|
||||||
App::Netdisco::Web::Plugin::Device::Ports:
|
App::Netdisco::Web::Plugin::Device::Ports:
|
||||||
file: lib/App/Netdisco/Web/Plugin/Device/Ports.pm
|
file: lib/App/Netdisco/Web/Plugin/Device/Ports.pm
|
||||||
|
App::Netdisco::Web::Plugin::Device::Vlans:
|
||||||
|
file: lib/App/Netdisco/Web/Plugin/Device/Vlans.pm
|
||||||
App::Netdisco::Web::Plugin::Inventory:
|
App::Netdisco::Web::Plugin::Inventory:
|
||||||
file: lib/App/Netdisco/Web/Plugin/Inventory.pm
|
file: lib/App/Netdisco/Web/Plugin/Inventory.pm
|
||||||
App::Netdisco::Web::Plugin::Report::ApChannelDist:
|
App::Netdisco::Web::Plugin::Report::ApChannelDist:
|
||||||
@@ -495,7 +497,7 @@ requires:
|
|||||||
IO::Socket::SSL: '2.048'
|
IO::Socket::SSL: '2.048'
|
||||||
JSON: '2.90'
|
JSON: '2.90'
|
||||||
JSON::XS: '3.01'
|
JSON::XS: '3.01'
|
||||||
List::MoreUtils: '0.33'
|
List::MoreUtils: '0.428'
|
||||||
List::Util: '1.49'
|
List::Util: '1.49'
|
||||||
MCE: '1.703'
|
MCE: '1.703'
|
||||||
MIME::Base64: '3.13'
|
MIME::Base64: '3.13'
|
||||||
@@ -516,7 +518,7 @@ requires:
|
|||||||
Plack::Middleware::ReverseProxy: '0.15'
|
Plack::Middleware::ReverseProxy: '0.15'
|
||||||
Pod::Usage: '0'
|
Pod::Usage: '0'
|
||||||
Role::Tiny: '1.002005'
|
Role::Tiny: '1.002005'
|
||||||
SNMP::Info: '3.64'
|
SNMP::Info: '3.65'
|
||||||
SQL::Abstract: '1.85'
|
SQL::Abstract: '1.85'
|
||||||
SQL::Translator: '0.11024'
|
SQL::Translator: '0.11024'
|
||||||
Scope::Guard: '0'
|
Scope::Guard: '0'
|
||||||
@@ -537,6 +539,7 @@ requires:
|
|||||||
YAML: '0.84'
|
YAML: '0.84'
|
||||||
YAML::XS: '0.41'
|
YAML::XS: '0.41'
|
||||||
aliased: '0'
|
aliased: '0'
|
||||||
|
autovivification: '0'
|
||||||
namespace::clean: '0.24'
|
namespace::clean: '0.24'
|
||||||
version: '0.9902'
|
version: '0.9902'
|
||||||
resources:
|
resources:
|
||||||
@@ -546,5 +549,5 @@ 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: https://github.com/netdisco/netdisco
|
repository: https://github.com/netdisco/netdisco
|
||||||
version: '2.040002'
|
version: '2.040007'
|
||||||
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
|
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
|
||||||
|
|||||||
@@ -301,14 +301,30 @@ the leaf (such as C<interfaces> or C<uptime>).
|
|||||||
|
|
||||||
If you wish to test with a device class other than that discovered, prefix the
|
If you wish to test with a device class other than that discovered, prefix the
|
||||||
leaf with the class short name, for example "C<Layer3::C3550::interfaces>" or
|
leaf with the class short name, for example "C<Layer3::C3550::interfaces>" or
|
||||||
"C<Layer2::HP::uptime>".
|
"C<Layer2::HP::uptime>". Using "C<::>" as the start of the prefix will test
|
||||||
|
against the base "C<SNMP::Info>" class.
|
||||||
|
|
||||||
|
As well, SNMP object names can be used as an argument for "C<-e>", so you can
|
||||||
|
use C<ifName> for example, which will use the netdisco-mibs files for
|
||||||
|
translations.
|
||||||
|
|
||||||
|
All "C<-e>" parameters are case sensitive.
|
||||||
|
|
||||||
~/bin/netdisco-do show -d 192.0.2.1 -e interfaces
|
~/bin/netdisco-do show -d 192.0.2.1 -e interfaces
|
||||||
~/bin/netdisco-do show -d 192.0.2.1 -e Layer2::HP::interfaces
|
~/bin/netdisco-do show -d 192.0.2.1 -e Layer2::HP::interfaces
|
||||||
|
~/bin/netdisco-do show -d 192.0.2.1 -e ::interfaces
|
||||||
|
~/bin/netdisco-do show -d 192.0.2.1 -e ifName
|
||||||
|
|
||||||
A parameter may be passed to the C<SNMP::Info> method in the C<-p> parameter:
|
A parameter may be passed to the C<SNMP::Info> method or SNMP object in the
|
||||||
|
"C<-p>" parameter:
|
||||||
|
|
||||||
~/bin/netdisco-do show -d 192.0.2.1 -e has_layer -p 3
|
~/bin/netdisco-do show -d 192.0.2.1 -e has_layer -p 3
|
||||||
|
~/bin/netdisco-do show -d 192.0.2.1 -e ifName -p 2
|
||||||
|
|
||||||
|
The "C<-e>" parameter C<specify> will show the used configuration for the
|
||||||
|
specified device.
|
||||||
|
|
||||||
|
~/bin/netdisco-do show -d 192.0.2.1 -e specify
|
||||||
|
|
||||||
=head2 psql
|
=head2 psql
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ full SNMP support
|
|||||||
|
|
||||||
# install dependencies:
|
# install dependencies:
|
||||||
~/bin/localenv cpanm --notest Net::OpenSSH Expect
|
~/bin/localenv cpanm --notest Net::OpenSSH Expect
|
||||||
|
|
||||||
# run manually, or add to cron:
|
# run manually, or add to cron:
|
||||||
~/bin/netdisco-sshcollector [-DQO] [-w <max_workers>]
|
~/bin/netdisco-sshcollector [-DQO] [-w <max_workers>]
|
||||||
|
|
||||||
@@ -209,10 +209,10 @@ Currently, ARP tables can be retrieved from the following device classes:
|
|||||||
|
|
||||||
=item * L<App::Netdisco::SSHCollector::Platform::IOS> - Cisco IOS
|
=item * L<App::Netdisco::SSHCollector::Platform::IOS> - Cisco IOS
|
||||||
|
|
||||||
=item * L<App::Netdisco::SSHCollector::Platform::NXOS> - Cisco NXOS
|
|
||||||
|
|
||||||
=item * L<App::Netdisco::SSHCollector::Platform::IOSXR> - Cisco IOS XR
|
=item * L<App::Netdisco::SSHCollector::Platform::IOSXR> - Cisco IOS XR
|
||||||
|
|
||||||
|
=item * L<App::Netdisco::SSHCollector::Platform::NXOS> - Cisco NXOS
|
||||||
|
|
||||||
=item * L<App::Netdisco::SSHCollector::Platform::BigIP> - F5 Networks BigIP
|
=item * L<App::Netdisco::SSHCollector::Platform::BigIP> - F5 Networks BigIP
|
||||||
|
|
||||||
=item * L<App::Netdisco::SSHCollector::Platform::FreeBSD> - FreeBSD
|
=item * L<App::Netdisco::SSHCollector::Platform::FreeBSD> - FreeBSD
|
||||||
@@ -227,8 +227,8 @@ The collected arp entries are then directly stored in the netdisco database.
|
|||||||
|
|
||||||
=head1 CONFIGURATION
|
=head1 CONFIGURATION
|
||||||
|
|
||||||
The following should go into your Netdisco 2 configuration file, "C<<
|
The following should go into your Netdisco configuration file,
|
||||||
~/environments/deployment.yml >>"
|
F<~/environments/deployment.yml>.
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ The following should go into your Netdisco 2 configuration file, "C<<
|
|||||||
|
|
||||||
Data is collected from the machines specified in this setting. The format is a
|
Data is collected from the machines specified in this setting. The format is a
|
||||||
list of dictionaries. The keys C<ip>, C<user>, C<password>, and C<platform>
|
list of dictionaries. The keys C<ip>, C<user>, C<password>, and C<platform>
|
||||||
are required. Optionally the C<hostname> key can be used instead of the
|
are required. Optionally the C<hostname> key can be used instead of the
|
||||||
C<ip>. For example:
|
C<ip>. For example:
|
||||||
|
|
||||||
sshcollector:
|
sshcollector:
|
||||||
@@ -246,14 +246,16 @@ C<ip>. For example:
|
|||||||
platform: IOS
|
platform: IOS
|
||||||
- hostname: 'core-router.example.com'
|
- hostname: 'core-router.example.com'
|
||||||
user: oliver
|
user: oliver
|
||||||
password: letmein
|
password:
|
||||||
platform: IOS
|
platform: IOS
|
||||||
|
|
||||||
Platform is the final part of the classname to be instantiated to query the
|
Platform is the final part of the classname to be instantiated to query the
|
||||||
host, e.g. platform B<ACE> will be queried using
|
host, e.g. platform B<ACE> will be queried using
|
||||||
C<App::Netdisco::SSHCollector::Platform::ACE>.
|
C<App::Netdisco::SSHCollector::Platform::ACE>.
|
||||||
|
|
||||||
If the password is "-", public key authentication will be attempted.
|
If the password is blank, public key authentication will be attempted with the
|
||||||
|
default key for the netdisco user. Password protected keys are currently not
|
||||||
|
supported.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
@@ -294,7 +296,7 @@ B<inetaddr> and B<macaddr> datatypes in PostgreSQL can handle.
|
|||||||
|
|
||||||
=item C<-D>
|
=item C<-D>
|
||||||
|
|
||||||
Netdisco debug log level
|
Netdisco debug log level.
|
||||||
|
|
||||||
=item C<-Q>
|
=item C<-Q>
|
||||||
|
|
||||||
@@ -302,7 +304,7 @@ L<DBIx::Class> trace enabled.
|
|||||||
|
|
||||||
=item C<-O>
|
=item C<-O>
|
||||||
|
|
||||||
L<Net::OpenSSH> trace enabled
|
L<Net::OpenSSH> trace enabled.
|
||||||
|
|
||||||
=item C<-w>
|
=item C<-w>
|
||||||
|
|
||||||
@@ -310,9 +312,8 @@ Set maximum parallel workers for L<MCE::Loop>. The default is B<auto>.
|
|||||||
|
|
||||||
=item C<-d device>
|
=item C<-d device>
|
||||||
|
|
||||||
Only run for a single device. Takes an IP or hostname, must exactly match the value
|
Only run for a single device. Takes an IP or hostname, must exactly match the
|
||||||
in the config file.
|
value in the config file.
|
||||||
|
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
@@ -326,6 +327,8 @@ in the config file.
|
|||||||
|
|
||||||
=item L<Expect>
|
=item L<Expect>
|
||||||
|
|
||||||
|
=item L<http://www.openssh.com/>
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use 5.010_000;
|
use 5.010_000;
|
||||||
|
|
||||||
our $VERSION = '2.040002';
|
our $VERSION = '2.040007';
|
||||||
use App::Netdisco::Configuration;
|
use App::Netdisco::Configuration;
|
||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
@@ -312,7 +312,7 @@ of Waikato, Hamilton NZ), Dusty Hall (Auburn U), Jon Monroe (center pointe),
|
|||||||
Alexander Barthel, Bill Anderson, Alexander Hartmaier (t-systems.at), Justin
|
Alexander Barthel, Bill Anderson, Alexander Hartmaier (t-systems.at), Justin
|
||||||
Hunter (Arizona State U), Jethro Binks (U of Strathclyde, Glasgow), Jordi
|
Hunter (Arizona State U), Jethro Binks (U of Strathclyde, Glasgow), Jordi
|
||||||
Guijarro (UAB.es), Sam Stickland (spacething.org), Stefan Radman (CTBTO.org),
|
Guijarro (UAB.es), Sam Stickland (spacething.org), Stefan Radman (CTBTO.org),
|
||||||
Clint Wise, Max Kosmach, and Bernhard Augenstein.
|
Clint Wise, Max Kosmach, Bernhard Augenstein and Nick Nauwelaerts (aquafin.be).
|
||||||
|
|
||||||
We probably forgot some names - sorry about that :-(.
|
We probably forgot some names - sorry about that :-(.
|
||||||
|
|
||||||
|
|||||||
@@ -262,20 +262,27 @@ sub renumber {
|
|||||||
foreach my $set (qw/
|
foreach my $set (qw/
|
||||||
DeviceIp
|
DeviceIp
|
||||||
DeviceModule
|
DeviceModule
|
||||||
DevicePower
|
|
||||||
DeviceVlan
|
|
||||||
DevicePort
|
DevicePort
|
||||||
DevicePortLog
|
DevicePortLog
|
||||||
DevicePortPower
|
DevicePortPower
|
||||||
|
DevicePortProperties
|
||||||
DevicePortSsid
|
DevicePortSsid
|
||||||
DevicePortVlan
|
DevicePortVlan
|
||||||
DevicePortWireless
|
DevicePortWireless
|
||||||
|
DevicePower
|
||||||
|
DeviceVlan
|
||||||
/) {
|
/) {
|
||||||
$schema->resultset($set)
|
$schema->resultset($set)
|
||||||
->search({ip => $old_ip})
|
->search({ip => $old_ip})
|
||||||
->update({ip => $new_ip});
|
->update({ip => $new_ip});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$schema->resultset('DeviceSkip')
|
||||||
|
->search({device => $new_ip})->delete;
|
||||||
|
$schema->resultset('DeviceSkip')
|
||||||
|
->search({device => $old_ip})
|
||||||
|
->update({device => $new_ip});
|
||||||
|
|
||||||
$schema->resultset('DevicePort')
|
$schema->resultset('DevicePort')
|
||||||
->search({remote_ip => $old_ip})
|
->search({remote_ip => $old_ip})
|
||||||
->update({remote_ip => $new_ip});
|
->update({remote_ip => $new_ip});
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ __PACKAGE__->add_columns(
|
|||||||
{ data_type => "bigint", is_nullable => 1 },
|
{ data_type => "bigint", is_nullable => 1 },
|
||||||
"faststart",
|
"faststart",
|
||||||
{ data_type => "boolean", is_nullable => 1 },
|
{ data_type => "boolean", is_nullable => 1 },
|
||||||
|
"ifindex",
|
||||||
|
{ data_type => "bigint", is_nullable => 1 },
|
||||||
);
|
);
|
||||||
__PACKAGE__->set_primary_key("port", "ip");
|
__PACKAGE__->set_primary_key("port", "ip");
|
||||||
|
|
||||||
|
|||||||
@@ -15,32 +15,61 @@ __PACKAGE__->table_class('DBIx::Class::ResultSource::View');
|
|||||||
__PACKAGE__->table('device_links');
|
__PACKAGE__->table('device_links');
|
||||||
__PACKAGE__->result_source_instance->is_virtual(1);
|
__PACKAGE__->result_source_instance->is_virtual(1);
|
||||||
__PACKAGE__->result_source_instance->view_definition(<<ENDSQL
|
__PACKAGE__->result_source_instance->view_definition(<<ENDSQL
|
||||||
SELECT dp.ip AS left_ip, ld.dns AS left_dns, ld.name AS left_name,
|
WITH BothWays AS
|
||||||
array_agg(dp.port) AS left_port, array_agg(dp.name) AS left_descr,
|
( SELECT dp.ip AS left_ip,
|
||||||
sum( COALESCE(dpp.raw_speed,0) ) as aggspeed,
|
ld.dns AS left_dns,
|
||||||
count(*) AS aggports,
|
ld.name AS left_name,
|
||||||
di.ip AS right_ip, rd.dns AS right_dns, rd.name AS right_name,
|
array_agg(dp.port) AS left_port,
|
||||||
array_agg(dp.remote_port) AS right_port, array_agg(dp2.name) AS right_descr
|
array_agg(dp.name) AS left_descr,
|
||||||
|
|
||||||
FROM device_port dp
|
count(dpp.*) AS aggports,
|
||||||
LEFT OUTER JOIN device_port_properties dpp USING (ip, port)
|
sum(COALESCE(dpp.raw_speed, 0)) AS aggspeed,
|
||||||
INNER JOIN device ld ON dp.ip = ld.ip
|
|
||||||
INNER JOIN device_ip di ON dp.remote_ip = di.alias
|
|
||||||
INNER JOIN device rd ON di.ip = rd.ip
|
|
||||||
LEFT OUTER JOIN device_port dp2
|
|
||||||
ON (di.ip = dp2.ip
|
|
||||||
AND ((dp.remote_port = dp2.port)
|
|
||||||
OR (dp.remote_port = dp2.name)
|
|
||||||
OR (dp.remote_port = dp2.descr)))
|
|
||||||
|
|
||||||
WHERE dp.remote_port IS NOT NULL
|
di.ip AS right_ip,
|
||||||
AND dp.port !~* 'vlan'
|
rd.dns AS right_dns,
|
||||||
AND (dp.descr IS NULL OR dp.descr !~* 'vlan')
|
rd.name AS right_name,
|
||||||
AND (dp.type IS NULL OR dp.type !~* '^(53|ieee8023adLag|propVirtual|l2vlan|l3ipvlan|135|136|137)\$')
|
array_agg(dp.remote_port) AS right_port,
|
||||||
AND (dp.is_master = 'false' OR dp.slave_of IS NOT NULL)
|
array_agg(dp2.name) AS right_descr
|
||||||
AND dp.ip <= di.ip
|
|
||||||
GROUP BY left_ip, left_dns, left_name, right_ip, right_dns, right_name
|
FROM device_port dp
|
||||||
ORDER BY dp.ip
|
|
||||||
|
LEFT OUTER JOIN device_port_properties dpp ON (
|
||||||
|
(dp.ip = dpp.ip) AND (dp.port = dpp.port)
|
||||||
|
AND (dp.type IS NULL
|
||||||
|
OR dp.type !~* '^(53|ieee8023adLag|propVirtual|l2vlan|l3ipvlan|135|136|137)\$')
|
||||||
|
AND (dp.is_master = 'false'
|
||||||
|
OR dp.slave_of IS NOT NULL) )
|
||||||
|
|
||||||
|
INNER JOIN device ld ON dp.ip = ld.ip
|
||||||
|
INNER JOIN device_ip di ON dp.remote_ip = di.alias
|
||||||
|
INNER JOIN device rd ON di.ip = rd.ip
|
||||||
|
|
||||||
|
LEFT OUTER JOIN device_port dp2 ON (di.ip = dp2.ip
|
||||||
|
AND ((dp.remote_port = dp2.port)
|
||||||
|
OR (dp.remote_port = dp2.name)
|
||||||
|
OR (dp.remote_port = dp2.descr)))
|
||||||
|
|
||||||
|
WHERE dp.remote_port IS NOT NULL
|
||||||
|
AND dp.port !~* 'vlan'
|
||||||
|
AND (dp.descr IS NULL OR dp.descr !~* 'vlan')
|
||||||
|
|
||||||
|
GROUP BY left_ip,
|
||||||
|
left_dns,
|
||||||
|
left_name,
|
||||||
|
right_ip,
|
||||||
|
right_dns,
|
||||||
|
right_name )
|
||||||
|
|
||||||
|
SELECT *
|
||||||
|
FROM BothWays b
|
||||||
|
WHERE NOT EXISTS
|
||||||
|
( SELECT *
|
||||||
|
FROM BothWays b2
|
||||||
|
WHERE b2.right_ip = b.left_ip
|
||||||
|
AND b2.right_port = b.left_port
|
||||||
|
AND b2.left_ip < b.left_ip )
|
||||||
|
ORDER BY 1,
|
||||||
|
2
|
||||||
ENDSQL
|
ENDSQL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ __PACKAGE__->result_source_instance->view_definition(<<'ENDSQL');
|
|||||||
d.ip, d.name, d.dns,
|
d.ip, d.name, d.dns,
|
||||||
p.port, p.name AS port_description,
|
p.port, p.name AS port_description,
|
||||||
p.remote_ip, p.remote_id, p.remote_type, p.remote_port,
|
p.remote_ip, p.remote_id, p.remote_type, p.remote_port,
|
||||||
|
dpp.remote_is_wap, dpp.remote_is_phone,
|
||||||
l.log AS comment,
|
l.log AS comment,
|
||||||
a.log, a.finished
|
a.log, a.finished
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ __PACKAGE__->result_source_instance->view_definition(<<'ENDSQL');
|
|||||||
INNER JOIN device d USING (ip)
|
INNER JOIN device d USING (ip)
|
||||||
LEFT OUTER JOIN device_skip ds
|
LEFT OUTER JOIN device_skip ds
|
||||||
ON ('discover' = ANY(ds.actionset) AND p.remote_ip = ds.device)
|
ON ('discover' = ANY(ds.actionset) AND p.remote_ip = ds.device)
|
||||||
|
LEFT OUTER JOIN device_port_properties dpp USING (ip, port)
|
||||||
LEFT OUTER JOIN device_port_log l USING (ip, port)
|
LEFT OUTER JOIN device_port_log l USING (ip, port)
|
||||||
LEFT OUTER JOIN admin a
|
LEFT OUTER JOIN admin a
|
||||||
ON (p.remote_ip = a.device AND a.action = 'discover')
|
ON (p.remote_ip = a.device AND a.action = 'discover')
|
||||||
@@ -58,6 +60,10 @@ __PACKAGE__->add_columns(
|
|||||||
{ data_type => "text", is_nullable => 1 },
|
{ data_type => "text", is_nullable => 1 },
|
||||||
"remote_id",
|
"remote_id",
|
||||||
{ data_type => "text", is_nullable => 1 },
|
{ data_type => "text", is_nullable => 1 },
|
||||||
|
"remote_is_wap",
|
||||||
|
{ data_type => "boolean", is_nullable => 1 },
|
||||||
|
"remote_is_phone",
|
||||||
|
{ data_type => "boolean", is_nullable => 1 },
|
||||||
"comment",
|
"comment",
|
||||||
{ data_type => "text", is_nullable => 1 },
|
{ data_type => "text", is_nullable => 1 },
|
||||||
"log",
|
"log",
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ use base 'App::Netdisco::DB::ResultSet';
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
use Try::Tiny;
|
||||||
use NetAddr::IP::Lite ':lower';
|
use NetAddr::IP::Lite ':lower';
|
||||||
|
require Dancer::Logger;
|
||||||
|
|
||||||
=head1 ADDITIONAL METHODS
|
=head1 ADDITIONAL METHODS
|
||||||
|
|
||||||
@@ -44,16 +47,16 @@ sub with_times {
|
|||||||
->search({},
|
->search({},
|
||||||
{
|
{
|
||||||
'+columns' => {
|
'+columns' => {
|
||||||
uptime_age => \("replace(age(timestamp 'epoch' + uptime / 100 * interval '1 second', "
|
uptime_age => \("replace(age(timestamp 'epoch' + me.uptime / 100 * interval '1 second', "
|
||||||
."timestamp '1970-01-01 00:00:00-00')::text, 'mon', 'month')"),
|
."timestamp '1970-01-01 00:00:00-00')::text, 'mon', 'month')"),
|
||||||
first_seen_stamp => \"to_char(me.creation, 'YYYY-MM-DD HH24:MI')",
|
first_seen_stamp => \"to_char(me.creation, 'YYYY-MM-DD HH24:MI')",
|
||||||
last_discover_stamp => \"to_char(last_discover, 'YYYY-MM-DD HH24:MI')",
|
last_discover_stamp => \"to_char(me.last_discover, 'YYYY-MM-DD HH24:MI')",
|
||||||
last_macsuck_stamp => \"to_char(last_macsuck, 'YYYY-MM-DD HH24:MI')",
|
last_macsuck_stamp => \"to_char(me.last_macsuck, 'YYYY-MM-DD HH24:MI')",
|
||||||
last_arpnip_stamp => \"to_char(last_arpnip, 'YYYY-MM-DD HH24:MI')",
|
last_arpnip_stamp => \"to_char(me.last_arpnip, 'YYYY-MM-DD HH24:MI')",
|
||||||
since_first_seen => \"extract(epoch from (age(now(), me.creation)))",
|
since_first_seen => \"extract(epoch from (age(now(), me.creation)))",
|
||||||
since_last_discover => \"extract(epoch from (age(now(), last_discover)))",
|
since_last_discover => \"extract(epoch from (age(now(), me.last_discover)))",
|
||||||
since_last_macsuck => \"extract(epoch from (age(now(), last_macsuck)))",
|
since_last_macsuck => \"extract(epoch from (age(now(), me.last_macsuck)))",
|
||||||
since_last_arpnip => \"extract(epoch from (age(now(), last_arpnip)))",
|
since_last_arpnip => \"extract(epoch from (age(now(), me.last_arpnip)))",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -591,12 +594,22 @@ handle the removal or archiving of nodes.
|
|||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
sub _plural { (shift || 0) == 1 ? 'entry' : 'entries' };
|
||||||
|
|
||||||
sub delete {
|
sub delete {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
my $schema = $self->result_source->schema;
|
my $schema = $self->result_source->schema;
|
||||||
my $devices = $self->search(undef, { columns => 'ip' });
|
my $devices = $self->search(undef, { columns => 'ip' });
|
||||||
|
|
||||||
|
my $ip = undef;
|
||||||
|
{
|
||||||
|
no autovivification;
|
||||||
|
try { $ip ||= $devices->{attrs}->{where}->{ip} };
|
||||||
|
try { $ip ||= $devices->{attrs}->{where}->{'me.ip'} };
|
||||||
|
}
|
||||||
|
$ip ||= 'netdisco';
|
||||||
|
|
||||||
foreach my $set (qw/
|
foreach my $set (qw/
|
||||||
DeviceIp
|
DeviceIp
|
||||||
DeviceVlan
|
DeviceVlan
|
||||||
@@ -604,9 +617,12 @@ sub delete {
|
|||||||
DeviceModule
|
DeviceModule
|
||||||
Community
|
Community
|
||||||
/) {
|
/) {
|
||||||
$schema->resultset($set)->search(
|
my $gone = $schema->resultset($set)->search(
|
||||||
{ ip => { '-in' => $devices->as_query } },
|
{ ip => { '-in' => $devices->as_query } },
|
||||||
)->delete;
|
)->delete;
|
||||||
|
|
||||||
|
Dancer::Logger::debug sprintf ' [%s] db/device - removed %d %s from %s',
|
||||||
|
$ip, $gone, _plural($gone), $set if defined Dancer::Logger::logger();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $set (qw/
|
foreach my $set (qw/
|
||||||
@@ -618,13 +634,16 @@ sub delete {
|
|||||||
)->delete;
|
)->delete;
|
||||||
}
|
}
|
||||||
|
|
||||||
$schema->resultset('Topology')->search({
|
my $gone = $schema->resultset('Topology')->search({
|
||||||
-or => [
|
-or => [
|
||||||
{ dev1 => { '-in' => $devices->as_query } },
|
{ dev1 => { '-in' => $devices->as_query } },
|
||||||
{ dev2 => { '-in' => $devices->as_query } },
|
{ dev2 => { '-in' => $devices->as_query } },
|
||||||
],
|
],
|
||||||
})->delete;
|
})->delete;
|
||||||
|
|
||||||
|
Dancer::Logger::debug sprintf ' [%s] db/device - removed %d manual topology %s',
|
||||||
|
$ip, $gone, _plural($gone) if defined Dancer::Logger::logger();
|
||||||
|
|
||||||
$schema->resultset('DevicePort')->search(
|
$schema->resultset('DevicePort')->search(
|
||||||
{ ip => { '-in' => $devices->as_query } },
|
{ ip => { '-in' => $devices->as_query } },
|
||||||
)->delete(@_);
|
)->delete(@_);
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ use base 'App::Netdisco::DB::ResultSet';
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
use Try::Tiny;
|
||||||
|
require Dancer::Logger;
|
||||||
|
|
||||||
__PACKAGE__->load_components(qw/
|
__PACKAGE__->load_components(qw/
|
||||||
+App::Netdisco::DB::ExplicitLocking
|
+App::Netdisco::DB::ExplicitLocking
|
||||||
/);
|
/);
|
||||||
@@ -222,12 +225,22 @@ handle the removal or archiving of nodes.
|
|||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
sub _plural { (shift || 0) == 1 ? 'entry' : 'entries' };
|
||||||
|
|
||||||
sub delete {
|
sub delete {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
my $schema = $self->result_source->schema;
|
my $schema = $self->result_source->schema;
|
||||||
my $ports = $self->search(undef, { columns => 'ip' });
|
my $ports = $self->search(undef, { columns => 'ip' });
|
||||||
|
|
||||||
|
my $ip = undef;
|
||||||
|
{
|
||||||
|
no autovivification;
|
||||||
|
try { $ip ||= ${ $ports->{attrs}->{where}->{ip}->{'-in'} }->[1]->[1] };
|
||||||
|
try { $ip ||= $ports->{attrs}->{where}->{'me.ip'} };
|
||||||
|
}
|
||||||
|
$ip ||= 'netdisco';
|
||||||
|
|
||||||
foreach my $set (qw/
|
foreach my $set (qw/
|
||||||
DevicePortPower
|
DevicePortPower
|
||||||
DevicePortProperties
|
DevicePortProperties
|
||||||
@@ -235,9 +248,12 @@ sub delete {
|
|||||||
DevicePortWireless
|
DevicePortWireless
|
||||||
DevicePortSsid
|
DevicePortSsid
|
||||||
/) {
|
/) {
|
||||||
$schema->resultset($set)->search(
|
my $gone = $schema->resultset($set)->search(
|
||||||
{ ip => { '-in' => $ports->as_query }},
|
{ ip => { '-in' => $ports->as_query }},
|
||||||
)->delete;
|
)->delete;
|
||||||
|
|
||||||
|
Dancer::Logger::debug sprintf ' [%s] db/ports - removed %d port %s from %s',
|
||||||
|
$ip, $gone, _plural($gone), $set if defined Dancer::Logger::logger();
|
||||||
}
|
}
|
||||||
|
|
||||||
$schema->resultset('Node')->search(
|
$schema->resultset('Node')->search(
|
||||||
|
|||||||
@@ -75,21 +75,21 @@ sub arpnip {
|
|||||||
$expect->send( $args->{enable_password} ."\n" );
|
$expect->send( $args->{enable_password} ."\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
$prompt = qr/#/;
|
$prompt = qr/#\s*$/;
|
||||||
($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);
|
($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);
|
||||||
|
|
||||||
|
$expect->send("terminal pager 2147483647\n");
|
||||||
|
($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);
|
||||||
|
|
||||||
$expect->send("show names\n");
|
$expect->send("show names\n");
|
||||||
($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);
|
($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);
|
||||||
my @names = split(m/\n/, $before);
|
my @names = split(m/\n/, $before);
|
||||||
|
|
||||||
$expect->send("terminal pager 2147483647\n");
|
|
||||||
($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);
|
|
||||||
|
|
||||||
$expect->send("show arp\n");
|
$expect->send("show arp\n");
|
||||||
($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);
|
($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);
|
||||||
|
my @lines = split(m/\n/, $before);
|
||||||
|
|
||||||
my @arpentries = ();
|
my @arpentries = ();
|
||||||
my @lines = split(m/\n/, $before);
|
|
||||||
|
|
||||||
# ifname 192.0.2.1 0011.2233.4455 123
|
# ifname 192.0.2.1 0011.2233.4455 123
|
||||||
my $linereg = qr/[A-z0-9\-\.]+\s([A-z0-9\-\.]+)\s
|
my $linereg = qr/[A-z0-9\-\.]+\s([A-z0-9\-\.]+)\s
|
||||||
@@ -98,7 +98,7 @@ sub arpnip {
|
|||||||
foreach my $line (@lines) {
|
foreach my $line (@lines) {
|
||||||
if ($line =~ $linereg) {
|
if ($line =~ $linereg) {
|
||||||
my ($ip, $mac) = ($1, $2);
|
my ($ip, $mac) = ($1, $2);
|
||||||
if ($ip !~ m/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/) {
|
if ($ip !~ m/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) {
|
||||||
foreach my $name (@names) {
|
foreach my $name (@names) {
|
||||||
if ($name =~ qr/name\s([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\s([\w-]*)/x) {
|
if ($name =~ qr/name\s([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\s([\w-]*)/x) {
|
||||||
if ($ip eq $2) {
|
if ($ip eq $2) {
|
||||||
@@ -107,7 +107,7 @@ sub arpnip {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($ip =~ m/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/) {
|
if ($ip =~ m/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) {
|
||||||
push @arpentries, { mac => $mac, ip => $ip };
|
push @arpentries, { mac => $mac, ip => $ip };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ our @EXPORT_OK = qw/
|
|||||||
get_device
|
get_device
|
||||||
delete_device
|
delete_device
|
||||||
renumber_device
|
renumber_device
|
||||||
match_devicetype
|
match_to_setting
|
||||||
is_discoverable is_discoverable_now
|
is_discoverable is_discoverable_now
|
||||||
is_arpnipable is_arpnipable_now
|
is_arpnipable is_arpnipable_now
|
||||||
is_macsuckable is_macsuckable_now
|
is_macsuckable is_macsuckable_now
|
||||||
@@ -100,8 +100,8 @@ sub delete_device {
|
|||||||
=head2 renumber_device( $current_ip, $new_ip )
|
=head2 renumber_device( $current_ip, $new_ip )
|
||||||
|
|
||||||
Will update all records in Netdisco referring to the device with
|
Will update all records in Netdisco referring to the device with
|
||||||
C<$current_ip> to use C<$new_ip> instead, followed by renumbering the device
|
C<$current_ip> to use C<$new_ip> instead, followed by renumbering the
|
||||||
iteself.
|
device itself.
|
||||||
|
|
||||||
Returns true if the transaction completes, else returns false.
|
Returns true if the transaction completes, else returns false.
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ sub renumber_device {
|
|||||||
schema('netdisco')->resultset('UserLog')->create({
|
schema('netdisco')->resultset('UserLog')->create({
|
||||||
username => session('logged_in_user'),
|
username => session('logged_in_user'),
|
||||||
userip => scalar eval {request->remote_address},
|
userip => scalar eval {request->remote_address},
|
||||||
event => (sprintf "Renumber device %s to %s", $device->ip, $new_ip),
|
event => (sprintf "Renumber device %s to %s", $ip, $new_ip),
|
||||||
});
|
});
|
||||||
|
|
||||||
$happy = 1;
|
$happy = 1;
|
||||||
@@ -129,7 +129,7 @@ sub renumber_device {
|
|||||||
return $happy;
|
return $happy;
|
||||||
}
|
}
|
||||||
|
|
||||||
=head2 match_devicetype( $type, $setting_name )
|
=head2 match_to_setting( $type, $setting_name )
|
||||||
|
|
||||||
Given a C<$type> (which may be any text value), returns true if any of the
|
Given a C<$type> (which may be any text value), returns true if any of the
|
||||||
list of regular expressions in C<$setting_name> is matched, otherwise returns
|
list of regular expressions in C<$setting_name> is matched, otherwise returns
|
||||||
@@ -137,7 +137,7 @@ false.
|
|||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub match_devicetype {
|
sub match_to_setting {
|
||||||
my ($type, $setting_name) = @_;
|
my ($type, $setting_name) = @_;
|
||||||
return 0 unless $type and $setting_name;
|
return 0 unless $type and $setting_name;
|
||||||
return (scalar grep {$type =~ m/$_/}
|
return (scalar grep {$type =~ m/$_/}
|
||||||
@@ -146,7 +146,7 @@ sub match_devicetype {
|
|||||||
|
|
||||||
sub _bail_msg { debug $_[0]; return 0; }
|
sub _bail_msg { debug $_[0]; return 0; }
|
||||||
|
|
||||||
=head2 is_discoverable( $ip, $device_type? )
|
=head2 is_discoverable( $ip, [$device_type, \@device_capabilities]? )
|
||||||
|
|
||||||
Given an IP address, returns C<true> if Netdisco on this host is permitted by
|
Given an IP address, returns C<true> if Netdisco on this host is permitted by
|
||||||
the local configuration to discover the device.
|
the local configuration to discover the device.
|
||||||
@@ -154,20 +154,32 @@ the local configuration to discover the device.
|
|||||||
The configuration items C<discover_no> and C<discover_only> are checked
|
The configuration items C<discover_no> and C<discover_only> are checked
|
||||||
against the given IP.
|
against the given IP.
|
||||||
|
|
||||||
If C<$device_type> is also given, then C<discover_no_type> will also be
|
If C<$device_type> is also given, then C<discover_no_type> will be checked.
|
||||||
checked.
|
Also respects C<discover_phones> and C<discover_waps> if either are set to
|
||||||
|
false.
|
||||||
|
|
||||||
Returns false if the host is not permitted to discover the target device.
|
Returns false if the host is not permitted to discover the target device.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub is_discoverable {
|
sub is_discoverable {
|
||||||
my ($ip, $remote_type) = @_;
|
my ($ip, $remote_type, $remote_cap) = @_;
|
||||||
my $device = get_device($ip) or return 0;
|
my $device = get_device($ip) or return 0;
|
||||||
|
$remote_type ||= '';
|
||||||
|
$remote_cap ||= [];
|
||||||
|
|
||||||
if (match_devicetype($remote_type, 'discover_no_type')) {
|
return _bail_msg("is_discoverable: $device matches wap_platforms but discover_waps is not enabled")
|
||||||
return _bail_msg("is_discoverable: $device matched discover_no_type");
|
if ((not setting('discover_waps')) and
|
||||||
}
|
(match_to_setting($remote_type, 'wap_platforms') or
|
||||||
|
scalar grep {match_to_setting($_, 'wap_capabilities')} @$remote_cap));
|
||||||
|
|
||||||
|
return _bail_msg("is_discoverable: $device matches phone_platforms but discover_phones is not enabled")
|
||||||
|
if ((not setting('discover_phones')) and
|
||||||
|
(match_to_setting($remote_type, 'phone_platforms') or
|
||||||
|
scalar grep {match_to_setting($_, 'phone_capabilities')} @$remote_cap));
|
||||||
|
|
||||||
|
return _bail_msg("is_discoverable: $device matched discover_no_type")
|
||||||
|
if (match_to_setting($remote_type, 'discover_no_type'));
|
||||||
|
|
||||||
return _bail_msg("is_discoverable: $device matched discover_no")
|
return _bail_msg("is_discoverable: $device matched discover_no")
|
||||||
if check_acl_no($device, 'discover_no');
|
if check_acl_no($device, 'discover_no');
|
||||||
|
|||||||
@@ -105,7 +105,8 @@ sub port_reconfig_check {
|
|||||||
|
|
||||||
# uplink check
|
# uplink check
|
||||||
return "forbidden: port [$name] on [$ip] is an uplink"
|
return "forbidden: port [$name] on [$ip] is an uplink"
|
||||||
if $port->remote_type and not $has_phone and not setting('portctl_uplinks');
|
if ($port->is_uplink or $port->remote_type)
|
||||||
|
and not $has_phone and not setting('portctl_uplinks');
|
||||||
|
|
||||||
# phone check
|
# phone check
|
||||||
return "forbidden: port [$name] on [$ip] is a phone"
|
return "forbidden: port [$name] on [$ip] is a phone"
|
||||||
@@ -215,18 +216,10 @@ sub is_vlan_interface {
|
|||||||
|
|
||||||
Returns true if the C<$port> L<DBIx::Class> object has a phone connected.
|
Returns true if the C<$port> L<DBIx::Class> object has a phone connected.
|
||||||
|
|
||||||
This uses a simple check on the I<type> of the remote connected device, and
|
|
||||||
therefore might sometimes return a false-negative result.
|
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub port_has_phone {
|
sub port_has_phone {
|
||||||
my $port = shift;
|
return (shift)->with_properties->remote_is_phone;
|
||||||
|
|
||||||
my $has_phone = ($port->remote_type
|
|
||||||
and $port->remote_type =~ /ip.phone/i) ? 1 : 0;
|
|
||||||
|
|
||||||
return $has_phone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use Dancer::Plugin::Auth::Extensible;
|
|||||||
|
|
||||||
use URI ();
|
use URI ();
|
||||||
use URL::Encode 'url_params_mixed';
|
use URL::Encode 'url_params_mixed';
|
||||||
use App::Netdisco::Util::Device 'match_devicetype';
|
use App::Netdisco::Util::Device 'match_to_setting';
|
||||||
|
|
||||||
# build view settings for port connected nodes and devices
|
# build view settings for port connected nodes and devices
|
||||||
set('connected_properties' => [
|
set('connected_properties' => [
|
||||||
@@ -20,7 +20,7 @@ hook 'before_template' => sub {
|
|||||||
my $tokens = shift;
|
my $tokens = shift;
|
||||||
|
|
||||||
# allow checking of discoverability of remote connected device
|
# allow checking of discoverability of remote connected device
|
||||||
$tokens->{has_snmp} = sub { not match_devicetype(shift, 'discover_no_type') };
|
$tokens->{has_snmp} = sub { not match_to_setting(shift, 'discover_no_type') };
|
||||||
|
|
||||||
my $defaults = var('sidebar_defaults')->{'device_ports'}
|
my $defaults = var('sidebar_defaults')->{'device_ports'}
|
||||||
or return;
|
or return;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use App::Netdisco::Web::Plugin;
|
|||||||
use Path::Class 'file';
|
use Path::Class 'file';
|
||||||
use Safe;
|
use Safe;
|
||||||
|
|
||||||
use vars qw/$config @data/;
|
our ($config, @data);
|
||||||
|
|
||||||
foreach my $report (@{setting('reports')}) {
|
foreach my $report (@{setting('reports')}) {
|
||||||
my $r = $report->{tag};
|
my $r = $report->{tag};
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ get '/ajax/content/admin/undiscoveredneighbors' => require_role admin => sub {
|
|||||||
# create a new row object to avoid hitting the DB in get_device()
|
# create a new row object to avoid hitting the DB in get_device()
|
||||||
my $dev = schema('netdisco')->resultset('Device')->new({ip => $r->{remote_ip}});
|
my $dev = schema('netdisco')->resultset('Device')->new({ip => $r->{remote_ip}});
|
||||||
next unless is_discoverable( $dev, $r->{remote_type} );
|
next unless is_discoverable( $dev, $r->{remote_type} );
|
||||||
|
next if (not setting('discover_waps')) and $r->{remote_is_wap};
|
||||||
|
next if (not setting('discover_phones')) and $r->{remote_is_phone};
|
||||||
push @discoverable_results, $r;
|
push @discoverable_results, $r;
|
||||||
}
|
}
|
||||||
return unless scalar @discoverable_results;
|
return unless scalar @discoverable_results;
|
||||||
|
|||||||
@@ -125,18 +125,13 @@ sub make_link_infostring {
|
|||||||
(my $left_name = lc($link->{left_dns} || $link->{left_name} || $link->{left_ip})) =~ s/$domain$//;
|
(my $left_name = lc($link->{left_dns} || $link->{left_name} || $link->{left_ip})) =~ s/$domain$//;
|
||||||
(my $right_name = lc($link->{right_dns} || $link->{right_name} || $link->{right_ip})) =~ s/$domain$//;
|
(my $right_name = lc($link->{right_dns} || $link->{right_name} || $link->{right_ip})) =~ s/$domain$//;
|
||||||
|
|
||||||
if ($link->{aggports} == 1) {
|
my @zipped = List::MoreUtils::zip6
|
||||||
return sprintf '<b>%s:%s</b> (%s)<br><b>%s:%s</b> (%s)',
|
@{$link->{left_port}}, @{$link->{left_descr}},
|
||||||
$left_name, $link->{left_port}->[0],
|
@{$link->{right_port}}, @{$link->{right_descr}};
|
||||||
($link->{left_descr}->[0] || 'no description'),
|
|
||||||
$right_name, $link->{right_port}->[0],
|
return join '<br><br>', map { sprintf '<b>%s:%s</b> (%s)<br><b>%s:%s</b> (%s)',
|
||||||
($link->{right_descr}->[0] || 'no description');
|
$left_name, $_->[0], ($_->[1] || 'no description'),
|
||||||
}
|
$right_name, $_->[2], ($_->[3] || 'no description') } @zipped;
|
||||||
else {
|
|
||||||
return sprintf '<b>%s:(%s)</b><br><b>%s:(%s)</b>',
|
|
||||||
$left_name, join(',', @{$link->{left_port}}),
|
|
||||||
$right_name, join(',', @{$link->{right_port}});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ajax '/ajax/data/device/netmap' => require_login sub {
|
ajax '/ajax/data/device/netmap' => require_login sub {
|
||||||
@@ -179,17 +174,6 @@ ajax '/ajax/data/device/netmap' => require_login sub {
|
|||||||
]) : ())
|
]) : ())
|
||||||
}, { result_class => 'DBIx::Class::ResultClass::HashRefInflator' });
|
}, { result_class => 'DBIx::Class::ResultClass::HashRefInflator' });
|
||||||
|
|
||||||
if ($vlan) {
|
|
||||||
$links = $links->search({
|
|
||||||
-or => [
|
|
||||||
{ 'left_vlans.vlan' => $vlan },
|
|
||||||
{ 'right_vlans.vlan' => $vlan },
|
|
||||||
],
|
|
||||||
}, {
|
|
||||||
join => [qw/left_vlans right_vlans/],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
while (my $link = $links->next) {
|
while (my $link = $links->next) {
|
||||||
push @{$data{'links'}}, {
|
push @{$data{'links'}}, {
|
||||||
FROMID => $link->{left_ip},
|
FROMID => $link->{left_ip},
|
||||||
@@ -217,10 +201,19 @@ ajax '/ajax/data/device/netmap' => require_login sub {
|
|||||||
join => 'throughput',
|
join => 'throughput',
|
||||||
})->with_times;
|
})->with_times;
|
||||||
|
|
||||||
|
# filter by vlan for all or neighbors only
|
||||||
|
if ($vlan) {
|
||||||
|
$devices = $devices->search(
|
||||||
|
{ 'vlans.vlan' => $vlan },
|
||||||
|
{ join => 'vlans' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
DEVICE: while (my $device = $devices->next) {
|
DEVICE: while (my $device = $devices->next) {
|
||||||
# if in neighbors or vlan mode then use %ok_dev to filter
|
# if in neighbors mode then use %ok_dev to filter
|
||||||
next DEVICE if (($mapshow eq 'neighbors') or $vlan)
|
next DEVICE if ($device->ip ne $qdev->ip)
|
||||||
and (not $ok_dev{$device->ip});
|
and ($mapshow eq 'neighbors')
|
||||||
|
and (not $ok_dev{$device->ip}); # showing only neighbors but no link
|
||||||
|
|
||||||
# if location picked then filter
|
# if location picked then filter
|
||||||
next DEVICE if ((scalar @lgrplist) and ((!defined $device->location)
|
next DEVICE if ((scalar @lgrplist) and ((!defined $device->location)
|
||||||
|
|||||||
@@ -25,25 +25,6 @@ get '/ajax/content/device/ports' => require_login sub {
|
|||||||
if ($f) {
|
if ($f) {
|
||||||
if (($prefer eq 'vlan') or (not $prefer and $f =~ m/^\d+$/)) {
|
if (($prefer eq 'vlan') or (not $prefer and $f =~ m/^\d+$/)) {
|
||||||
return unless $f =~ m/^\d+$/;
|
return unless $f =~ m/^\d+$/;
|
||||||
|
|
||||||
if (param('invert')) {
|
|
||||||
$set = $set->search({
|
|
||||||
'me.vlan' => { '!=' => $f },
|
|
||||||
'port_vlans.vlan' => [
|
|
||||||
'-or' => { '!=' => $f }, { '=' => undef }
|
|
||||||
],
|
|
||||||
}, { join => 'port_vlans' });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$set = $set->search({
|
|
||||||
-or => {
|
|
||||||
'me.vlan' => $f,
|
|
||||||
'port_vlans.vlan' => $f,
|
|
||||||
},
|
|
||||||
}, { join => 'port_vlans' });
|
|
||||||
}
|
|
||||||
|
|
||||||
return unless $set->count;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (param('partial')) {
|
if (param('partial')) {
|
||||||
@@ -120,7 +101,7 @@ get '/ajax/content/device/ports' => require_login sub {
|
|||||||
# now begin to join tables depending on the selected columns/options
|
# now begin to join tables depending on the selected columns/options
|
||||||
|
|
||||||
# get vlans on the port
|
# get vlans on the port
|
||||||
# leave this query dormant (lazy) unless c_vmember is set
|
# leave this query dormant (lazy) unless c_vmember is set or vlan filtering
|
||||||
my $vlans = $set->search({}, {
|
my $vlans = $set->search({}, {
|
||||||
select => [
|
select => [
|
||||||
'port',
|
'port',
|
||||||
@@ -131,7 +112,7 @@ get '/ajax/content/device/ports' => require_login sub {
|
|||||||
group_by => 'me.port',
|
group_by => 'me.port',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (param('c_vmember')) {
|
if (param('c_vmember') or ($prefer eq 'vlan') or (not $prefer and $f =~ m/^\d+$/)) {
|
||||||
$vlans = { map {(
|
$vlans = { map {(
|
||||||
$_->port => {
|
$_->port => {
|
||||||
# DBIC smart enough to work out this should be an arrayref :)
|
# DBIC smart enough to work out this should be an arrayref :)
|
||||||
@@ -194,13 +175,37 @@ get '/ajax/content/device/ports' => require_login sub {
|
|||||||
# also get remote LLDP inventory if asked for
|
# also get remote LLDP inventory if asked for
|
||||||
$set = $set->with_remote_inventory if param('n_inventory');
|
$set = $set->with_remote_inventory if param('n_inventory');
|
||||||
|
|
||||||
# sort ports (empty set would be a 'no records' msg)
|
# run query
|
||||||
my $results = [ sort { &App::Netdisco::Util::Web::sort_port($a->port, $b->port) } $set->all ];
|
my @results = $set->all;
|
||||||
return unless scalar @$results;
|
|
||||||
|
# filter for tagged vlan using existing agg query,
|
||||||
|
# which is better than join inflation
|
||||||
|
if (($prefer eq 'vlan') or (not $prefer and $f =~ m/^\d+$/)) {
|
||||||
|
if (param('invert')) {
|
||||||
|
@results = grep {
|
||||||
|
(!defined $_->vlan or $_->vlan ne $f)
|
||||||
|
and
|
||||||
|
(0 == scalar grep {defined and $_ ne $f} @{ $vlans->{$_->port}->{vlan_set} })
|
||||||
|
} @results;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
@results = grep {
|
||||||
|
($_->vlan eq $f)
|
||||||
|
or
|
||||||
|
(scalar grep {defined and $_ eq $f} @{ $vlans->{$_->port}->{vlan_set} })
|
||||||
|
} @results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# sort ports
|
||||||
|
@results = sort { &App::Netdisco::Util::Web::sort_port($a->port, $b->port) } @results;
|
||||||
|
|
||||||
|
# empty set would be a 'no records' msg
|
||||||
|
return unless scalar @results;
|
||||||
|
|
||||||
if (request->is_ajax) {
|
if (request->is_ajax) {
|
||||||
template 'ajax/device/ports.tt', {
|
template 'ajax/device/ports.tt', {
|
||||||
results => $results,
|
results => \@results,
|
||||||
nodes => $nodes_name,
|
nodes => $nodes_name,
|
||||||
ips => $ips_name,
|
ips => $ips_name,
|
||||||
device => $device,
|
device => $device,
|
||||||
@@ -210,7 +215,7 @@ get '/ajax/content/device/ports' => require_login sub {
|
|||||||
else {
|
else {
|
||||||
header( 'Content-Type' => 'text/comma-separated-values' );
|
header( 'Content-Type' => 'text/comma-separated-values' );
|
||||||
template 'ajax/device/ports_csv.tt', {
|
template 'ajax/device/ports_csv.tt', {
|
||||||
results => $results,
|
results => \@results,
|
||||||
nodes => $nodes_name,
|
nodes => $nodes_name,
|
||||||
ips => $ips_name,
|
ips => $ips_name,
|
||||||
device => $device,
|
device => $device,
|
||||||
|
|||||||
36
lib/App/Netdisco/Web/Plugin/Device/Vlans.pm
Normal file
36
lib/App/Netdisco/Web/Plugin/Device/Vlans.pm
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package App::Netdisco::Web::Plugin::Device::Vlans;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Dancer ':syntax';
|
||||||
|
use Dancer::Plugin::Ajax;
|
||||||
|
use Dancer::Plugin::DBIC;
|
||||||
|
use Dancer::Plugin::Auth::Extensible;
|
||||||
|
|
||||||
|
use App::Netdisco::Web::Plugin;
|
||||||
|
|
||||||
|
register_device_tab({ tag => 'vlans', label => 'VLANs', provides_csv => 1 });
|
||||||
|
|
||||||
|
get '/ajax/content/device/vlans' => require_login sub {
|
||||||
|
my $q = param('q');
|
||||||
|
|
||||||
|
my $device = schema('netdisco')->resultset('Device')
|
||||||
|
->search_for_device($q) or send_error('Bad device', 400);
|
||||||
|
my @results = $device->vlans->search( {}, { order_by => 'vlan' } )->hri->all;
|
||||||
|
|
||||||
|
return unless scalar @results;
|
||||||
|
|
||||||
|
if (request->is_ajax) {
|
||||||
|
my $json = to_json( \@results );
|
||||||
|
template 'ajax/device/vlans.tt', { results => $json },
|
||||||
|
{ layout => undef };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
header( 'Content-Type' => 'text/comma-separated-values' );
|
||||||
|
template 'ajax/device/vlans_csv.tt', { results => \@results },
|
||||||
|
{ layout => undef };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
true;
|
||||||
@@ -110,12 +110,12 @@ get '/ajax/content/report/ipinventory' => require_login sub {
|
|||||||
'ip', 'mac', 'dns', 'time_last', 'time_first',
|
'ip', 'mac', 'dns', 'time_last', 'time_first',
|
||||||
'active', 'node', 'age'
|
'active', 'node', 'age'
|
||||||
],
|
],
|
||||||
order_by => [{-asc => 'ip'}, {-desc => 'active'}],
|
order_by => [{-asc => 'ip'}, {-desc => 'active'}, {-asc => 'node'}],
|
||||||
}
|
}
|
||||||
)->as_query;
|
)->as_query;
|
||||||
|
|
||||||
my $rs;
|
my $rs;
|
||||||
if ( $start && $end ) {
|
if ( $start and $end ) {
|
||||||
$start = $start . ' 00:00:00';
|
$start = $start . ' 00:00:00';
|
||||||
$end = $end . ' 23:59:59';
|
$end = $end . ' 23:59:59';
|
||||||
|
|
||||||
|
|||||||
@@ -27,35 +27,48 @@ ajax '/ajax/content/search/node' => require_login sub {
|
|||||||
my @active = (param('archived') ? () : (-bool => 'active'));
|
my @active = (param('archived') ? () : (-bool => 'active'));
|
||||||
|
|
||||||
my (@times, @wifitimes, @porttimes);
|
my (@times, @wifitimes, @porttimes);
|
||||||
if ($start and $end) {
|
if ( $start and $end ) {
|
||||||
$start = $start . ' 00:00:00';
|
$start = $start . ' 00:00:00';
|
||||||
$end = $end . ' 23:59:59';
|
$end = $end . ' 23:59:59';
|
||||||
|
|
||||||
if ($agenot) {
|
if ($agenot) {
|
||||||
@times = (-or => [
|
@times = (-or => [
|
||||||
time_first => [ { '<', $start }, undef ],
|
time_first => [ undef ],
|
||||||
time_last => { '>', $end },
|
time_last => [ { '<', $start }, { '>', $end } ]
|
||||||
]);
|
]);
|
||||||
@wifitimes = (-or => [
|
@wifitimes = (-or => [
|
||||||
time_last => { '<', $start },
|
time_last => [ undef ],
|
||||||
time_last => { '>', $end },
|
time_last => [ { '<', $start }, { '>', $end } ],
|
||||||
]);
|
]);
|
||||||
@porttimes = (-or => [
|
@porttimes = (-or => [
|
||||||
creation => { '<', $start },
|
creation => [ undef ],
|
||||||
creation => { '>', $end },
|
creation => [ { '<', $start }, { '>', $end } ]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@times = (-and => [
|
@times = (-or => [
|
||||||
time_first => { '>=', $start },
|
-and => [
|
||||||
time_last => { '<=', $end },
|
time_first => undef,
|
||||||
|
time_last => undef,
|
||||||
|
],
|
||||||
|
-and => [
|
||||||
|
time_last => { '>=', $start },
|
||||||
|
time_last => { '<=', $end },
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
@wifitimes = (-and => [
|
@wifitimes = (-or => [
|
||||||
time_last => { '>=', $start },
|
time_last => undef,
|
||||||
time_last => { '<=', $end },
|
-and => [
|
||||||
|
time_last => { '>=', $start },
|
||||||
|
time_last => { '<=', $end },
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
@porttimes = (-and => [
|
@porttimes = (-or => [
|
||||||
creation => { '>=', $start },
|
creation => undef,
|
||||||
creation => { '<=', $end },
|
-and => [
|
||||||
|
creation => { '>=', $start },
|
||||||
|
creation => { '<=', $end },
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ ajax '/ajax/data/port/typeahead' => require_login sub {
|
|||||||
if $port;
|
if $port;
|
||||||
|
|
||||||
my $results = [
|
my $results = [
|
||||||
map {{ label => (sprintf "%s (%s)", $_->port, $_->name), value => $_->port }}
|
map {{ label => (sprintf "%s (%s)", $_->port, ($_->name || '')), value => $_->port }}
|
||||||
sort { &App::Netdisco::Util::Web::sort_port($a->port, $b->port) } $set->all
|
sort { &App::Netdisco::Util::Web::sort_port($a->port, $b->port) } $set->all
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
# only enqueue if device is not already discovered,
|
# only enqueue if device is not already discovered,
|
||||||
# discover_* config permits the discovery
|
# discover_* config permits the discovery
|
||||||
foreach my $neighbor (@to_discover) {
|
foreach my $neighbor (@to_discover) {
|
||||||
my ($ip, $remote_type, $remote_id) = @$neighbor;
|
my ($ip, $remote_id) = @$neighbor;
|
||||||
if ($seen_ip{ $ip }++) {
|
if ($seen_ip{ $ip }++) {
|
||||||
debug sprintf
|
debug sprintf
|
||||||
' queue - skip: IP %s is already queued from %s',
|
' queue - skip: IP %s is already queued from %s',
|
||||||
@@ -63,13 +63,6 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
my $newdev = get_device($ip);
|
my $newdev = get_device($ip);
|
||||||
next if $newdev->in_storage;
|
next if $newdev->in_storage;
|
||||||
|
|
||||||
if (not is_discoverable($newdev, $remote_type)) {
|
|
||||||
debug sprintf
|
|
||||||
' queue - skip: %s of type [%s] excluded by discover_* config',
|
|
||||||
$ip, ($remote_type || '');
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
# risk of things going wrong...?
|
# risk of things going wrong...?
|
||||||
# https://quickview.cloudapps.cisco.com/quickview/bug/CSCur12254
|
# https://quickview.cloudapps.cisco.com/quickview/bug/CSCur12254
|
||||||
|
|
||||||
@@ -114,6 +107,7 @@ sub store_neighbors {
|
|||||||
or return (); # already checked!
|
or return (); # already checked!
|
||||||
|
|
||||||
# first allow any manually configured topology to be set
|
# first allow any manually configured topology to be set
|
||||||
|
# and do this before we cache the rows in vars->{'device_ports'}
|
||||||
set_manual_topology($device);
|
set_manual_topology($device);
|
||||||
|
|
||||||
if (!defined $snmp->has_topo) {
|
if (!defined $snmp->has_topo) {
|
||||||
@@ -126,6 +120,12 @@ sub store_neighbors {
|
|||||||
my $c_port = $snmp->c_port;
|
my $c_port = $snmp->c_port;
|
||||||
my $c_id = $snmp->c_id;
|
my $c_id = $snmp->c_id;
|
||||||
my $c_platform = $snmp->c_platform;
|
my $c_platform = $snmp->c_platform;
|
||||||
|
my $c_cap = $snmp->c_cap;
|
||||||
|
|
||||||
|
# cache the device ports to save hitting the database for many single rows
|
||||||
|
vars->{'device_ports'} =
|
||||||
|
{ map {($_->port => $_)} $device->ports->reset->all };
|
||||||
|
my $device_ports = vars->{'device_ports'};
|
||||||
|
|
||||||
# v4 and v6 neighbor tables
|
# v4 and v6 neighbor tables
|
||||||
my $c_ip = ($snmp->c_ip || {});
|
my $c_ip = ($snmp->c_ip || {});
|
||||||
@@ -144,12 +144,12 @@ sub store_neighbors {
|
|||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $port = $interfaces->{ $c_if->{$entry} };
|
# WRT #475 this is SAFE because we check against known ports below
|
||||||
my $portrow = schema('netdisco')->resultset('DevicePort')
|
my $port = $interfaces->{ $c_if->{$entry} } or next;
|
||||||
->single({ip => $device->ip, port => $port});
|
my $portrow = $device_ports->{$port};
|
||||||
|
|
||||||
if (!defined $portrow) {
|
if (!defined $portrow) {
|
||||||
info sprintf ' [%s] neigh - local port %s not in database!',
|
debug sprintf ' [%s] neigh - local port %s already skipped, ignoring',
|
||||||
$device->ip, $port;
|
$device->ip, $port;
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
@@ -161,7 +161,7 @@ sub store_neighbors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($portrow->manual_topo) {
|
if ($portrow->manual_topo) {
|
||||||
info sprintf ' [%s] neigh - %s has manually defined topology',
|
debug sprintf ' [%s] neigh - %s has manually defined topology',
|
||||||
$device->ip, $port;
|
$device->ip, $port;
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
@@ -170,12 +170,13 @@ sub store_neighbors {
|
|||||||
my $remote_port = undef;
|
my $remote_port = undef;
|
||||||
my $remote_type = Encode::decode('UTF-8', $c_platform->{$entry} || '');
|
my $remote_type = Encode::decode('UTF-8', $c_platform->{$entry} || '');
|
||||||
my $remote_id = Encode::decode('UTF-8', $c_id->{$entry});
|
my $remote_id = Encode::decode('UTF-8', $c_id->{$entry});
|
||||||
|
my $remote_cap = $c_cap->{$entry} || [];
|
||||||
|
|
||||||
next unless $remote_ip;
|
next unless $remote_ip;
|
||||||
my $r_netaddr = NetAddr::IP::Lite->new($remote_ip);
|
my $r_netaddr = NetAddr::IP::Lite->new($remote_ip);
|
||||||
|
|
||||||
if ($r_netaddr and ($r_netaddr->addr ne $remote_ip)) {
|
if ($r_netaddr and ($r_netaddr->addr ne $remote_ip)) {
|
||||||
info sprintf ' [%s] neigh - IP on %s: using %s as canonical form of %s',
|
debug sprintf ' [%s] neigh - IP on %s: using %s as canonical form of %s',
|
||||||
$device->ip, $port, $r_netaddr->addr, $remote_ip;
|
$device->ip, $port, $r_netaddr->addr, $remote_ip;
|
||||||
$remote_ip = $r_netaddr->addr;
|
$remote_ip = $r_netaddr->addr;
|
||||||
}
|
}
|
||||||
@@ -189,7 +190,7 @@ sub store_neighbors {
|
|||||||
if ($remote_id) {
|
if ($remote_id) {
|
||||||
my $devices = schema('netdisco')->resultset('Device');
|
my $devices = schema('netdisco')->resultset('Device');
|
||||||
my $neigh = $devices->single({name => $remote_id});
|
my $neigh = $devices->single({name => $remote_id});
|
||||||
info sprintf
|
debug sprintf
|
||||||
' [%s] neigh - bad address %s on port %s, searching for %s instead',
|
' [%s] neigh - bad address %s on port %s, searching for %s instead',
|
||||||
$device->ip, $remote_ip, $port, $remote_id;
|
$device->ip, $remote_ip, $port, $remote_id;
|
||||||
|
|
||||||
@@ -207,7 +208,7 @@ sub store_neighbors {
|
|||||||
(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 = NetAddr::MAC->new(mac => $tmpid);
|
my $mac = NetAddr::MAC->new(mac => $tmpid);
|
||||||
if ($mac and not $mac->errstr) {
|
if ($mac and not $mac->errstr) {
|
||||||
info sprintf
|
debug sprintf
|
||||||
' [%s] neigh - trying to find neighbor %s by MAC %s',
|
' [%s] neigh - trying to find neighbor %s by MAC %s',
|
||||||
$device->ip, $remote_id, $mac->as_ieee;
|
$device->ip, $remote_id, $mac->as_ieee;
|
||||||
$neigh = $devices->single({mac => $mac->as_ieee});
|
$neigh = $devices->single({mac => $mac->as_ieee});
|
||||||
@@ -221,17 +222,17 @@ sub store_neighbors {
|
|||||||
|
|
||||||
if ($neigh) {
|
if ($neigh) {
|
||||||
$remote_ip = $neigh->ip;
|
$remote_ip = $neigh->ip;
|
||||||
info sprintf ' [%s] neigh - found %s with IP %s',
|
debug sprintf ' [%s] neigh - found %s with IP %s',
|
||||||
$device->ip, $remote_id, $remote_ip;
|
$device->ip, $remote_id, $remote_ip;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
info sprintf ' [%s] neigh - could not find %s, skipping',
|
debug sprintf ' [%s] neigh - could not find %s, skipping',
|
||||||
$device->ip, $remote_id;
|
$device->ip, $remote_id;
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
info sprintf ' [%s] neigh - skipping unuseable address %s on port %s',
|
debug sprintf ' [%s] neigh - skipping unuseable address %s on port %s',
|
||||||
$device->ip, $remote_ip, $port;
|
$device->ip, $remote_ip, $port;
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
@@ -240,7 +241,15 @@ sub store_neighbors {
|
|||||||
# what we came here to do.... discover the neighbor
|
# what we came here to do.... discover the neighbor
|
||||||
debug sprintf ' [%s] neigh - %s with ID [%s] on %s',
|
debug sprintf ' [%s] neigh - %s with ID [%s] on %s',
|
||||||
$device->ip, $remote_ip, ($remote_id || ''), $port;
|
$device->ip, $remote_ip, ($remote_id || ''), $port;
|
||||||
push @to_discover, [$remote_ip, $remote_type, $remote_id];
|
|
||||||
|
if (is_discoverable($remote_ip, $remote_type, $remote_cap)) {
|
||||||
|
push @to_discover, [$remote_ip, $remote_id];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debug sprintf
|
||||||
|
' [%s] neigh - skip: %s of type [%s] excluded by discover_* config',
|
||||||
|
$device->ip, $remote_ip, ($remote_type || '');
|
||||||
|
}
|
||||||
|
|
||||||
$remote_port = $c_port->{$entry};
|
$remote_port = $c_port->{$entry};
|
||||||
if (defined $remote_port) {
|
if (defined $remote_port) {
|
||||||
@@ -248,18 +257,18 @@ sub store_neighbors {
|
|||||||
$remote_port =~ s/[^\d\s\/\.,()\w:-]+//gi;
|
$remote_port =~ s/[^\d\s\/\.,()\w:-]+//gi;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
info sprintf ' [%s] neigh - no remote port found for port %s at %s',
|
debug sprintf ' [%s] neigh - no remote port found for port %s at %s',
|
||||||
$device->ip, $port, $remote_ip;
|
$device->ip, $port, $remote_ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
$portrow->update({
|
$portrow = $portrow->update({
|
||||||
remote_ip => $remote_ip,
|
remote_ip => $remote_ip,
|
||||||
remote_port => $remote_port,
|
remote_port => $remote_port,
|
||||||
remote_type => $remote_type,
|
remote_type => $remote_type,
|
||||||
remote_id => $remote_id,
|
remote_id => $remote_id,
|
||||||
is_uplink => \"true",
|
is_uplink => \"true",
|
||||||
manual_topo => \"false",
|
manual_topo => \"false",
|
||||||
});
|
})->discard_changes();
|
||||||
|
|
||||||
# update master of our aggregate to be a neighbor of
|
# update master of our aggregate to be a neighbor of
|
||||||
# the master on our peer device (a lot of iffs to get there...).
|
# the master on our peer device (a lot of iffs to get there...).
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
my $eigrp_peers = $snmp->eigrp_peers || {};
|
my $eigrp_peers = $snmp->eigrp_peers || {};
|
||||||
|
|
||||||
return Status->info(" [$device] neigh - no BGP, OSPF, or EIGRP peers")
|
return Status->info(" [$device] neigh - no BGP, OSPF, or EIGRP peers")
|
||||||
unless ((scalar values %$ospf_peers) or (scalar values %$bgp_peers)
|
unless ((scalar values %$ospf_peers) or (scalar values %$ospf_routers)
|
||||||
or (scalar values %$eigrp_peers));
|
or (scalar values %$bgp_peers) or (scalar values %$eigrp_peers));
|
||||||
|
|
||||||
my $count = 0;
|
my $count = 0;
|
||||||
foreach my $ip ((values %$ospf_peers), (values %$ospf_routers),
|
foreach my $ip ((values %$ospf_peers), (values %$ospf_routers),
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# cache the device ports to save hitting the database for many single rows
|
||||||
|
my $device_ports = vars->{'device_ports'}
|
||||||
|
|| { map {($_->port => $_)} $device->ports->all };
|
||||||
|
|
||||||
my $interfaces = $snmp->interfaces;
|
my $interfaces = $snmp->interfaces;
|
||||||
my $p_ifindex = $snmp->peth_port_ifindex;
|
my $p_ifindex = $snmp->peth_port_ifindex;
|
||||||
my $p_admin = $snmp->peth_port_admin;
|
my $p_admin = $snmp->peth_port_admin;
|
||||||
@@ -42,11 +46,16 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
# build device port power info suitable for DBIC
|
# build device port power info suitable for DBIC
|
||||||
my @portpower;
|
my @portpower;
|
||||||
foreach my $entry (keys %$p_ifindex) {
|
foreach my $entry (keys %$p_ifindex) {
|
||||||
my $port = $interfaces->{ $p_ifindex->{$entry} };
|
# WRT #475 this is SAFE because we check against known ports below
|
||||||
next unless $port;
|
my $port = $interfaces->{ $p_ifindex->{$entry} } or next;
|
||||||
|
|
||||||
|
if (!defined $device_ports->{$port}) {
|
||||||
|
debug sprintf ' [%s] power - local port %s already skipped, ignoring',
|
||||||
|
$device->ip, $port;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
my ($module) = split m/\./, $entry;
|
my ($module) = split m/\./, $entry;
|
||||||
|
|
||||||
push @portpower, {
|
push @portpower, {
|
||||||
port => $port,
|
port => $port,
|
||||||
module => $module,
|
module => $module,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use App::Netdisco::Transport::SNMP ();
|
|||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
|
|
||||||
use Encode;
|
use Encode;
|
||||||
use App::Netdisco::Util::Device 'match_devicetype';
|
use App::Netdisco::Util::Device 'match_to_setting';
|
||||||
|
|
||||||
register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
||||||
my ($job, $workerconf) = @_;
|
my ($job, $workerconf) = @_;
|
||||||
@@ -21,10 +21,20 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
my $interfaces = $snmp->interfaces || {};
|
my $interfaces = $snmp->interfaces || {};
|
||||||
my %properties = ();
|
my %properties = ();
|
||||||
|
|
||||||
|
# cache the device ports to save hitting the database for many single rows
|
||||||
|
my $device_ports = vars->{'device_ports'}
|
||||||
|
|| { map {($_->port => $_)} $device->ports->all };
|
||||||
|
|
||||||
my $raw_speed = $snmp->i_speed_raw || {};
|
my $raw_speed = $snmp->i_speed_raw || {};
|
||||||
|
|
||||||
foreach my $idx (keys %$raw_speed) {
|
foreach my $idx (keys %$raw_speed) {
|
||||||
my $port = $interfaces->{$idx} or next;
|
my $port = $interfaces->{$idx} or next;
|
||||||
|
if (!defined $device_ports->{$port}) {
|
||||||
|
debug sprintf ' [%s] properties/speed - local port %s already skipped, ignoring',
|
||||||
|
$device->ip, $port;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
$properties{ $port }->{raw_speed} = $raw_speed->{$idx};
|
$properties{ $port }->{raw_speed} = $raw_speed->{$idx};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +42,12 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
|
|
||||||
foreach my $idx (keys %$err_cause) {
|
foreach my $idx (keys %$err_cause) {
|
||||||
my $port = $interfaces->{$idx} or next;
|
my $port = $interfaces->{$idx} or next;
|
||||||
|
if (!defined $device_ports->{$port}) {
|
||||||
|
debug sprintf ' [%s] properties/errdis - local port %s already skipped, ignoring',
|
||||||
|
$device->ip, $port;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
$properties{ $port }->{error_disable_cause} = $err_cause->{$idx};
|
$properties{ $port }->{error_disable_cause} = $err_cause->{$idx};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,6 +55,12 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
|
|
||||||
foreach my $idx (keys %$faststart) {
|
foreach my $idx (keys %$faststart) {
|
||||||
my $port = $interfaces->{$idx} or next;
|
my $port = $interfaces->{$idx} or next;
|
||||||
|
if (!defined $device_ports->{$port}) {
|
||||||
|
debug sprintf ' [%s] properties/faststart - local port %s already skipped, ignoring',
|
||||||
|
$device->ip, $port;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
$properties{ $port }->{faststart} = $faststart->{$idx};
|
$properties{ $port }->{faststart} = $faststart->{$idx};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,17 +76,22 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
|
|
||||||
foreach my $idx (keys %$c_if) {
|
foreach my $idx (keys %$c_if) {
|
||||||
my $port = $interfaces->{ $c_if->{$idx} } or next;
|
my $port = $interfaces->{ $c_if->{$idx} } or next;
|
||||||
|
if (!defined $device_ports->{$port}) {
|
||||||
|
debug sprintf ' [%s] properties/lldpcap - local port %s already skipped, ignoring',
|
||||||
|
$device->ip, $port;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
my $remote_cap = $c_cap->{$idx} || [];
|
my $remote_cap = $c_cap->{$idx} || [];
|
||||||
my $remote_type = Encode::decode('UTF-8', $c_platform->{$idx} || '');
|
my $remote_type = Encode::decode('UTF-8', $c_platform->{$idx} || '');
|
||||||
|
|
||||||
$properties{ $port }->{remote_is_wap} = 'true'
|
$properties{ $port }->{remote_is_wap} = 'true'
|
||||||
if scalar grep {match_devicetype($_, 'wap_capabilities')} @$remote_cap
|
if scalar grep {match_to_setting($_, 'wap_capabilities')} @$remote_cap
|
||||||
or match_devicetype($remote_type, 'wap_platforms');
|
or match_to_setting($remote_type, 'wap_platforms');
|
||||||
|
|
||||||
$properties{ $port }->{remote_is_phone} = 'true'
|
$properties{ $port }->{remote_is_phone} = 'true'
|
||||||
if scalar grep {match_devicetype($_, 'phone_capabilities')} @$remote_cap
|
if scalar grep {match_to_setting($_, 'phone_capabilities')} @$remote_cap
|
||||||
or match_devicetype($remote_type, 'phone_platforms');
|
or match_to_setting($remote_type, 'phone_platforms');
|
||||||
|
|
||||||
next unless scalar grep {defined && m/^inventory$/} @{ $rem_media_cap->{$idx} };
|
next unless scalar grep {defined && m/^inventory$/} @{ $rem_media_cap->{$idx} };
|
||||||
|
|
||||||
@@ -74,17 +101,28 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
$properties{ $port }->{remote_serial} = $rem_serial->{ $idx };
|
$properties{ $port }->{remote_serial} = $rem_serial->{ $idx };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach my $idx (keys %$interfaces) {
|
||||||
|
my $port = $interfaces->{$idx} or next;
|
||||||
|
if (!defined $device_ports->{$port}) {
|
||||||
|
debug sprintf ' [%s] properties/ifindex - local port %s already skipped, ignoring',
|
||||||
|
$device->ip, $port;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
$properties{ $port }->{ifindex} = $idx;
|
||||||
|
}
|
||||||
|
|
||||||
return Status->info(" [$device] no port properties to record")
|
return Status->info(" [$device] no port properties to record")
|
||||||
unless scalar keys %properties;
|
unless scalar keys %properties;
|
||||||
|
|
||||||
schema('netdisco')->txn_do(sub {
|
schema('netdisco')->txn_do(sub {
|
||||||
my $gone = $device->properties_ports->delete;
|
my $gone = $device->properties_ports->delete;
|
||||||
debug sprintf ' [%s] props - removed %d ports with properties',
|
debug sprintf ' [%s] properties - removed %d ports with properties',
|
||||||
$device->ip, $gone;
|
$device->ip, $gone;
|
||||||
$device->properties_ports->populate(
|
$device->properties_ports->populate(
|
||||||
[map {{ port => $_, %{ $properties{$_} } }} keys %properties] );
|
[map {{ port => $_, %{ $properties{$_} } }} keys %properties] );
|
||||||
|
|
||||||
return Status->info(sprintf ' [%s] props - added %d new port properties',
|
return Status->info(sprintf ' [%s] properties - added %d new port properties',
|
||||||
$device->ip, scalar keys %properties);
|
$device->ip, scalar keys %properties);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
if (defined $snmp->snmpEngineTime) {
|
if (defined $snmp->snmpEngineTime) {
|
||||||
$dev_uptime_wrapped = int( $snmp->snmpEngineTime * 100 / 2**32 );
|
$dev_uptime_wrapped = int( $snmp->snmpEngineTime * 100 / 2**32 );
|
||||||
if ($dev_uptime_wrapped > 0) {
|
if ($dev_uptime_wrapped > 0) {
|
||||||
info sprintf ' [%s] interface - device uptime wrapped %d times - correcting',
|
debug sprintf ' [%s] interfaces - device uptime wrapped %d times - correcting',
|
||||||
$device->ip, $dev_uptime_wrapped;
|
$device->ip, $dev_uptime_wrapped;
|
||||||
$device->uptime( $dev_uptime + $dev_uptime_wrapped * 2**32 );
|
$device->uptime( $dev_uptime + $dev_uptime_wrapped * 2**32 );
|
||||||
}
|
}
|
||||||
@@ -190,7 +190,7 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
|
|
||||||
my $lc = $i_lastchange->{$entry} || 0;
|
my $lc = $i_lastchange->{$entry} || 0;
|
||||||
if (not $dev_uptime_wrapped and $lc > $dev_uptime) {
|
if (not $dev_uptime_wrapped and $lc > $dev_uptime) {
|
||||||
info sprintf ' [%s] interfaces - device uptime wrapped (%s) - correcting',
|
debug sprintf ' [%s] interfaces - device uptime wrapped (%s) - correcting',
|
||||||
$device->ip, $port;
|
$device->ip, $port;
|
||||||
$device->uptime( $dev_uptime + 2**32 );
|
$device->uptime( $dev_uptime + 2**32 );
|
||||||
$dev_uptime_wrapped = 1;
|
$dev_uptime_wrapped = 1;
|
||||||
@@ -238,6 +238,7 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
# must do this after building %interfaces so that we can set is_master
|
# must do this after building %interfaces so that we can set is_master
|
||||||
foreach my $sidx (keys %$agg_ports) {
|
foreach my $sidx (keys %$agg_ports) {
|
||||||
my $slave = $interfaces->{$sidx} or next;
|
my $slave = $interfaces->{$sidx} or next;
|
||||||
|
next unless defined $agg_ports->{$sidx}; # slave without a master?!
|
||||||
my $master = $interfaces->{ $agg_ports->{$sidx} } or next;
|
my $master = $interfaces->{ $agg_ports->{$sidx} } or next;
|
||||||
next unless exists $interfaces{$slave} and exists $interfaces{$master};
|
next unless exists $interfaces{$slave} and exists $interfaces{$master};
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# cache the device ports to save hitting the database for many single rows
|
||||||
|
my $device_ports = vars->{'device_ports'}
|
||||||
|
|| { map {($_->port => $_)} $device->ports->all };
|
||||||
|
|
||||||
my $i_vlan = $snmp->i_vlan;
|
my $i_vlan = $snmp->i_vlan;
|
||||||
my $i_vlan_membership = $snmp->i_vlan_membership;
|
my $i_vlan_membership = $snmp->i_vlan_membership;
|
||||||
my $i_vlan_type = $snmp->i_vlan_type;
|
my $i_vlan_type = $snmp->i_vlan_type;
|
||||||
@@ -42,8 +46,13 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
my @portvlans = ();
|
my @portvlans = ();
|
||||||
foreach my $entry (keys %$i_vlan_membership) {
|
foreach my $entry (keys %$i_vlan_membership) {
|
||||||
my %port_vseen = ();
|
my %port_vseen = ();
|
||||||
my $port = $interfaces->{$entry};
|
my $port = $interfaces->{$entry} or next;
|
||||||
next unless defined $port;
|
|
||||||
|
if (!defined $device_ports->{$port}) {
|
||||||
|
debug sprintf ' [%s] vlans - local port %s already skipped, ignoring',
|
||||||
|
$device->ip, $port;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
my $type = $i_vlan_type->{$entry};
|
my $type = $i_vlan_type->{$entry};
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
my $ssidlist = $snmp->i_ssidlist;
|
my $ssidlist = $snmp->i_ssidlist;
|
||||||
return unless scalar keys %$ssidlist;
|
return unless scalar keys %$ssidlist;
|
||||||
|
|
||||||
|
# cache the device ports to save hitting the database for many single rows
|
||||||
|
my $device_ports = vars->{'device_ports'}
|
||||||
|
|| { map {($_->port => $_)} $device->ports->all };
|
||||||
|
|
||||||
my $interfaces = $snmp->interfaces;
|
my $interfaces = $snmp->interfaces;
|
||||||
my $ssidbcast = $snmp->i_ssidbcast;
|
my $ssidbcast = $snmp->i_ssidbcast;
|
||||||
my $ssidmac = $snmp->i_ssidmac;
|
my $ssidmac = $snmp->i_ssidmac;
|
||||||
@@ -36,6 +40,12 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!defined $device_ports->{$port}) {
|
||||||
|
debug sprintf ' [%s] wireless - local port %s already skipped, ignoring',
|
||||||
|
$device->ip, $port;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
push @ssids, {
|
push @ssids, {
|
||||||
port => $port,
|
port => $port,
|
||||||
ssid => $ssidlist->{$entry},
|
ssid => $ssidlist->{$entry},
|
||||||
@@ -64,6 +74,12 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!defined $device_ports->{$port}) {
|
||||||
|
debug sprintf ' [%s] wireless - local port %s already skipped, ignoring',
|
||||||
|
$device->ip, $port;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
push @channels, {
|
push @channels, {
|
||||||
port => $port,
|
port => $port,
|
||||||
channel => $channel->{$entry},
|
channel => $channel->{$entry},
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use aliased 'App::Netdisco::Worker::Status';
|
|||||||
use App::Netdisco::Transport::SNMP ();
|
use App::Netdisco::Transport::SNMP ();
|
||||||
use App::Netdisco::Util::Permission 'check_acl_no';
|
use App::Netdisco::Util::Permission 'check_acl_no';
|
||||||
use App::Netdisco::Util::PortMAC 'get_port_macs';
|
use App::Netdisco::Util::PortMAC 'get_port_macs';
|
||||||
use App::Netdisco::Util::Device 'match_devicetype';
|
use App::Netdisco::Util::Device 'match_to_setting';
|
||||||
use App::Netdisco::Util::Node 'check_mac';
|
use App::Netdisco::Util::Node 'check_mac';
|
||||||
use App::Netdisco::Util::SNMP 'snmp_comm_reindex';
|
use App::Netdisco::Util::SNMP 'snmp_comm_reindex';
|
||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
@@ -248,7 +248,6 @@ sub get_vlan_list {
|
|||||||
|
|
||||||
# check in use by a port on this device
|
# check in use by a port on this device
|
||||||
if (!$vlans{$vlan} && !setting('macsuck_all_vlans')) {
|
if (!$vlans{$vlan} && !setting('macsuck_all_vlans')) {
|
||||||
|
|
||||||
debug sprintf
|
debug sprintf
|
||||||
' [%s] macsuck VLAN %s/%s - not in use by any port - skipping.',
|
' [%s] macsuck VLAN %s/%s - not in use by any port - skipping.',
|
||||||
$device->ip, $vlan, $name;
|
$device->ip, $vlan, $name;
|
||||||
@@ -299,6 +298,8 @@ sub walk_fwtable {
|
|||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# WRT #475 this is SAFE because we check against known ports below
|
||||||
|
# but we do need the SNMP interface IDs to get the job done
|
||||||
my $port = $interfaces->{$iid};
|
my $port = $interfaces->{$iid};
|
||||||
|
|
||||||
unless (defined $port) {
|
unless (defined $port) {
|
||||||
@@ -318,6 +319,7 @@ sub walk_fwtable {
|
|||||||
# this uses the cached $ports resultset to limit hits on the db
|
# this uses the cached $ports resultset to limit hits on the db
|
||||||
my $device_port = $device_ports->{$port};
|
my $device_port = $device_ports->{$port};
|
||||||
|
|
||||||
|
# WRT #475 ... see? :-)
|
||||||
unless (defined $device_port) {
|
unless (defined $device_port) {
|
||||||
debug sprintf
|
debug sprintf
|
||||||
' [%s] macsuck %s - port %s is not in database - skipping.',
|
' [%s] macsuck %s - port %s is not in database - skipping.',
|
||||||
@@ -340,7 +342,7 @@ sub walk_fwtable {
|
|||||||
# neighbors otherwise it would kill the DB with device lookups.
|
# neighbors otherwise it would kill the DB with device lookups.
|
||||||
my $neigh_cannot_macsuck = eval { # can fail
|
my $neigh_cannot_macsuck = eval { # can fail
|
||||||
check_acl_no(($device_port->neighbor || "0 but true"), 'macsuck_unsupported') ||
|
check_acl_no(($device_port->neighbor || "0 but true"), 'macsuck_unsupported') ||
|
||||||
match_devicetype($device_port->remote_type, 'macsuck_unsupported_type') };
|
match_to_setting($device_port->remote_type, 'macsuck_unsupported_type') };
|
||||||
|
|
||||||
if ($device_port->is_uplink) {
|
if ($device_port->is_uplink) {
|
||||||
if ($neigh_cannot_macsuck) {
|
if ($neigh_cannot_macsuck) {
|
||||||
|
|||||||
@@ -41,11 +41,11 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
next unless defined $mac; # avoid null entries
|
next unless defined $mac; # avoid null entries
|
||||||
# there can be more rows in txrate than other tables
|
# there can be more rows in txrate than other tables
|
||||||
|
|
||||||
my $txrate = defined $txrates->[$#$txrates]
|
my $txrate = (ref $txrates and defined $txrates->[$#$txrates])
|
||||||
? int($txrates->[$#$txrates])
|
? int($txrates->[$#$txrates])
|
||||||
: undef;
|
: undef;
|
||||||
|
|
||||||
my $maxrate = defined $rates->[$#$rates]
|
my $maxrate = (ref $rates and defined $rates->[$#$rates])
|
||||||
? int($rates->[$#$rates])
|
? int($rates->[$#$rates])
|
||||||
: undef;
|
: undef;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package App::Netdisco::Worker::Plugin::MakeRancidConf;
|
package App::Netdisco::Worker::Plugin::MakeRancidConf;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
use Dancer ':syntax';
|
use Dancer ':syntax';
|
||||||
use Dancer::Plugin::DBIC;
|
use Dancer::Plugin::DBIC;
|
||||||
|
|
||||||
@@ -8,7 +11,7 @@ use aliased 'App::Netdisco::Worker::Status';
|
|||||||
|
|
||||||
use Path::Class;
|
use Path::Class;
|
||||||
use List::Util qw/pairkeys pairfirst/;
|
use List::Util qw/pairkeys pairfirst/;
|
||||||
use File::Slurper 'write_text';
|
use File::Slurper qw/read_lines write_text/;
|
||||||
use App::Netdisco::Util::Permission 'check_acl_no';
|
use App::Netdisco::Util::Permission 'check_acl_no';
|
||||||
|
|
||||||
register_worker({ phase => 'main' }, sub {
|
register_worker({ phase => 'main' }, sub {
|
||||||
@@ -16,14 +19,31 @@ register_worker({ phase => 'main' }, sub {
|
|||||||
my $config = setting('rancid') || {};
|
my $config = setting('rancid') || {};
|
||||||
|
|
||||||
my $domain_suffix = setting('domain_suffix') || '';
|
my $domain_suffix = setting('domain_suffix') || '';
|
||||||
my $delimiter = $config->{delimiter} || ':';
|
my $delimiter = $config->{delimiter} || ';';
|
||||||
my $down_age = $config->{down_age} || '1 day';
|
my $down_age = $config->{down_age} || '1 day';
|
||||||
|
my $default_group = $config->{default_group} || 'default';
|
||||||
|
|
||||||
my $rancidhome = $config->{rancid_home}
|
my $rancidconf = $config->{rancid_conf} || '/etc/rancid';
|
||||||
|
my $rancidcvsroot = $config->{rancid_cvsroot}
|
||||||
|| dir($ENV{NETDISCO_HOME}, 'rancid')->stringify;
|
|| dir($ENV{NETDISCO_HOME}, 'rancid')->stringify;
|
||||||
mkdir $rancidhome if ! -d $rancidhome;
|
mkdir $rancidcvsroot if ! -d $rancidcvsroot;
|
||||||
return Status->error("cannot create or see rancid home: $rancidhome")
|
return Status->error("cannot create or access rancid cvsroot: $rancidcvsroot")
|
||||||
if ! -d $rancidhome;
|
if ! -d $rancidcvsroot;
|
||||||
|
|
||||||
|
my $allowed_types = {};
|
||||||
|
foreach my $type (qw/base conf/) {
|
||||||
|
my $type_file = file($rancidconf, "rancid.types.$type")->stringify;
|
||||||
|
debug sprintf("trying rancid configuration file %s\n", $type_file);
|
||||||
|
next unless -f $type_file;
|
||||||
|
my @lines = read_lines($type_file);
|
||||||
|
foreach my $line (@lines) {
|
||||||
|
next if $line =~ m/^(?:\#|\$)/;
|
||||||
|
$allowed_types->{$1} += 1 if $line =~ m/^([a-z0-9_\-]+);login;.*$/;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status->error("You didn't have any device types configured in your rancid installation.")
|
||||||
|
if ! scalar keys %$allowed_types;
|
||||||
|
|
||||||
my $devices = schema('netdisco')->resultset('Device')->search(undef, {
|
my $devices = schema('netdisco')->resultset('Device')->search(undef, {
|
||||||
'+columns' => { old =>
|
'+columns' => { old =>
|
||||||
@@ -32,24 +52,37 @@ register_worker({ phase => 'main' }, sub {
|
|||||||
|
|
||||||
$config->{groups} ||= { default => 'any' };
|
$config->{groups} ||= { default => 'any' };
|
||||||
$config->{vendormap} ||= {};
|
$config->{vendormap} ||= {};
|
||||||
|
$config->{excluded} ||= {};
|
||||||
|
$config->{by_ip} ||= {};
|
||||||
|
$config->{by_hostname} ||= {};
|
||||||
|
|
||||||
my $routerdb = {};
|
my $routerdb = {};
|
||||||
while (my $d = $devices->next) {
|
while (my $d = $devices->next) {
|
||||||
my $name =
|
|
||||||
check_acl_no($d, $config->{by_ip}) ? $d->ip : ($d->dns || $d->name);
|
if (check_acl_no($d, $config->{excluded})) {
|
||||||
$name =~ s/$domain_suffix$//
|
debug " skipping $d: device excluded of export";
|
||||||
if check_acl_no($d, $config->{by_hostname});
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
my $name = check_acl_no($d, $config->{by_ip}) ? $d->ip : ($d->dns || $d->name);
|
||||||
|
$name =~ s/$domain_suffix$// if check_acl_no($d, $config->{by_hostname});
|
||||||
|
|
||||||
my ($group) =
|
my ($group) =
|
||||||
pairkeys pairfirst { check_acl_no($d, $b) } %{ $config->{groups} };
|
(pairkeys pairfirst { check_acl_no($d, $b) } %{ $config->{groups} }) || $default_group;
|
||||||
|
|
||||||
my ($vendor) =
|
my ($vendor) =
|
||||||
(pairkeys pairfirst { check_acl_no($d, $b) } %{ $config->{vendormap} })
|
(pairkeys pairfirst { check_acl_no($d, $b) } %{ $config->{vendormap} })
|
||||||
|| $d->vendor;
|
|| $d->vendor;
|
||||||
|
|
||||||
if ($vendor =~ m/(?:enterprises\.|netdisco)/) {
|
if (not ($name and $vendor)) {
|
||||||
|
debug " skipping $d: the name or vendor is not defined";
|
||||||
|
next
|
||||||
|
} elsif ($vendor =~ m/(?:enterprises\.|netdisco)/) {
|
||||||
debug " skipping $d with unresolved vendor: $vendor";
|
debug " skipping $d with unresolved vendor: $vendor";
|
||||||
next;
|
next;
|
||||||
|
} elsif (scalar keys %$allowed_types and !exists($allowed_types->{$vendor})) {
|
||||||
|
debug " skipping $d: $vendor doesn't exist in rancid's vendor list";
|
||||||
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
push @{$routerdb->{$group}},
|
push @{$routerdb->{$group}},
|
||||||
@@ -58,12 +91,14 @@ register_worker({ phase => 'main' }, sub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach my $group (keys %$routerdb) {
|
foreach my $group (keys %$routerdb) {
|
||||||
mkdir dir($rancidhome, $group)->stringify;
|
mkdir dir($rancidcvsroot, $group)->stringify;
|
||||||
my $content = join "\n", @{$routerdb->{$group}};
|
my $content = "#\n# Router list file for rancid group $group.\n";
|
||||||
write_text(file($rancidhome, $group, 'router.db')->stringify, "${content}\n");
|
$content .= "# Generate automatically by App::Netdisco::Worker::Plugin::MakeRancidConf\n#\n";
|
||||||
|
$content .= join "\n", sort @{$routerdb->{$group}};
|
||||||
|
write_text(file($rancidcvsroot, $group, 'router.db')->stringify, "${content}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Status->done('Wrote RANCID configuration.');
|
return Status->done('Wrote rancid configuration.');
|
||||||
});
|
});
|
||||||
|
|
||||||
true;
|
true;
|
||||||
@@ -72,17 +107,20 @@ true;
|
|||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
|
||||||
MakeRancidConf - Generate RANCID Configuration
|
MakeRancidConf - Generate rancid Configuration
|
||||||
|
|
||||||
=head1 INTRODUCTION
|
=head1 INTRODUCTION
|
||||||
|
|
||||||
This worker will generate a RANCID configuration for all devices in Netdisco.
|
This worker will generate a rancid configuration for all devices in Netdisco.
|
||||||
|
|
||||||
Optionally you can provide configuration to control the output, however the
|
Optionally you can provide configuration to control the output, however the
|
||||||
defaults are sane, and will create one RANCID group called "C<default>" which
|
defaults are sane for rancid versions 3.x and will create one rancid group
|
||||||
contains all devices. Those devices not discovered successfully within the
|
called C<default> which contains all devices. Those devices not discovered
|
||||||
past day will be marked as "down" for RANCID to skip. Configuration is saved
|
successfully within the past day will be marked as C<down> for rancid to skip.
|
||||||
to the "rancid" subdirectory of Netdisco's home folder.
|
Configuration is saved to the F<~/rancid> subdirectory of Netdisco's home folder.
|
||||||
|
|
||||||
|
Note that this only generates the router.db files, you will still need to
|
||||||
|
configure rancid's F<.cloginrc> and schedule C<rancid-run> to run.
|
||||||
|
|
||||||
You could run this worker at 09:05 each day using the following configuration:
|
You could run this worker at 09:05 each day using the following configuration:
|
||||||
|
|
||||||
@@ -90,95 +128,142 @@ You could run this worker at 09:05 each day using the following configuration:
|
|||||||
makerancidconf:
|
makerancidconf:
|
||||||
when: '5 9 * * *'
|
when: '5 9 * * *'
|
||||||
|
|
||||||
|
Since MakeRancidConf is a worker module it can also be run via C<netdisco-do>:
|
||||||
|
|
||||||
|
netdisco-do makerancidconf
|
||||||
|
|
||||||
=head1 CONFIGURATION
|
=head1 CONFIGURATION
|
||||||
|
|
||||||
Here is a complete example of the configuration, which must be called
|
Here is a complete example of the configuration, which must be called
|
||||||
"C<rancid>". All keys are optional:
|
C<rancid>. All keys are optional:
|
||||||
|
|
||||||
rancid:
|
rancid:
|
||||||
rancid_home: "$ENV{NETDISCO_HOME}/rancid" # default
|
rancid_cvsroot: '$ENV{NETDISCO_HOME}/rancid' # default
|
||||||
down_age: '1 day' # default
|
rancid_conf: '/etc/rancid' # default
|
||||||
delimiter: ':' # default
|
down_age: '1 day' # default
|
||||||
|
delimiter: ';' # default
|
||||||
|
default_group: 'default' # default
|
||||||
|
excluded:
|
||||||
|
excludegroup1: 'host_group1_acl'
|
||||||
|
excludegroup2: 'host_group2_acl'
|
||||||
groups:
|
groups:
|
||||||
groupname1: 'host_group1_acl'
|
groupname1: 'host_group3_acl'
|
||||||
groupname2: 'host_group2_acl'
|
groupname2: 'host_group4_acl'
|
||||||
vendormap:
|
vendormap:
|
||||||
vname1: 'host_group3_acl'
|
vname1: 'host_group5_acl'
|
||||||
vname2: 'host_group4_acl'
|
vname2: 'host_group6_acl'
|
||||||
by_ip: 'host_group5_acl'
|
by_ip: 'host_group7_acl'
|
||||||
by_hostname: 'host_group6_acl'
|
by_hostname: 'host_group8_acl'
|
||||||
|
|
||||||
Note that the default home for writing files is not "C</var/lib/rancid>" so
|
Note that the default directory for writing files is not F</var/lib/rancid> so
|
||||||
you may wish to set this (especially if migrating from the old
|
you may wish to set this in C<rancid_cvsroot>, (especially if migrating from the old
|
||||||
C<netdisco-rancid-export> script).
|
C<netdisco-rancid-export> script).
|
||||||
|
|
||||||
Any values above that are a Host Group ACL will take either a single item or
|
Any values above that are a host group ACL will take either a single item or
|
||||||
list of Network Identifiers or Device Properties. See the L<ACL
|
a list of network identifiers or device properties. See the L<ACL
|
||||||
documentation|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
documentation|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
||||||
wiki page for full details. We advise you to use the "C<host_groups>" setting
|
wiki page for full details. We advise you to use the C<host_groups> setting
|
||||||
and then refer to named entries in that, for example:
|
and then refer to named entries in that, for example:
|
||||||
|
|
||||||
host_groups:
|
host_groups:
|
||||||
coredevices: '192.0.2.0/24'
|
coredevices: '192.0.2.0/24'
|
||||||
edgedevices: '172.16.0.0/16'
|
edgedevices: '172.16.0.0/16'
|
||||||
|
grp-nxos: 'os:nx-os'
|
||||||
|
|
||||||
rancid:
|
rancid:
|
||||||
groups:
|
groups:
|
||||||
core_devices: 'group:coredevices'
|
core_devices: 'group:coredevices'
|
||||||
edge_devices: 'group:edgedevices'
|
edge_devices: 'group:edgedevices'
|
||||||
|
vendormap:
|
||||||
|
cisco-nx: 'group:grp-nxos'
|
||||||
|
by_ip: 'any'
|
||||||
|
|
||||||
=head2 C<rancid_home>
|
Do not forget that rancid also needs configuring when adding a new group,
|
||||||
|
such as scheduling the group to run, adding it to F<rancid.conf>, setting up the
|
||||||
|
email config and creating the repository with C<rancid-cvs>.
|
||||||
|
|
||||||
The location to write RANCID Group configuration files into. A subdirectory
|
=head2 C<rancid_conf>
|
||||||
for each Group will be created.
|
|
||||||
|
The location where the rancid configuration (F<rancid.types.base> and
|
||||||
|
F<rancid.types.conf>) is installed. It will be used to check the existance
|
||||||
|
of device types before exporting the devices to the rancid configuration. if no match
|
||||||
|
is found the device will not be added to rancid.
|
||||||
|
|
||||||
|
=head2 C<rancid_cvsroot>
|
||||||
|
|
||||||
|
The location to write rancid group configuration files (F<router.db>) into. A
|
||||||
|
subdirectory for each group will be created.
|
||||||
|
|
||||||
=head2 C<down_age>
|
=head2 C<down_age>
|
||||||
|
|
||||||
This should be the same or greater than the interval between regular discover
|
This should be the same or greater than the interval between regular discover
|
||||||
jobs on your network. Devices which have not been discovered within this time
|
jobs on your network. Devices which have not been discovered within this time
|
||||||
will be marked as "C<down>" to RANCID.
|
will be marked as C<down> to rancid.
|
||||||
|
|
||||||
The format is any time interval known and understood by PostgreSQL, such as at
|
The format is any time interval known and understood by PostgreSQL, such as at
|
||||||
L<https://www.postgresql.org/docs/8.4/static/functions-datetime.html>.
|
L<https://www.postgresql.org/docs/10/static/functions-datetime.html>.
|
||||||
|
|
||||||
=head2 C<delimiter>
|
=head2 C<delimiter>
|
||||||
|
|
||||||
Set this to the delimiter character if needed to be different from the
|
Set this to the delimiter character for your F<router.db> entries if needed to
|
||||||
default.
|
be different from the default, the default is C<;>.
|
||||||
|
|
||||||
|
=head2 C<default_group>
|
||||||
|
|
||||||
|
Put devices into this group if they do not match any other groups defined.
|
||||||
|
|
||||||
|
=head2 C<excluded>
|
||||||
|
|
||||||
|
This dictionary defines a list of devices that you do not wish to export to
|
||||||
|
rancid configuration.
|
||||||
|
|
||||||
|
The value should be a L<Netdisco ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
||||||
|
to select devices in the Netdisco database.
|
||||||
|
|
||||||
=head2 C<groups>
|
=head2 C<groups>
|
||||||
|
|
||||||
This dictionary maps RANCID Group names with configuration which will match
|
This dictionary maps rancid group names with configuration which will match
|
||||||
devices in the Netdisco database.
|
devices in the Netdisco database.
|
||||||
|
|
||||||
The left hand side (key) should be the RANCID group name, the right hand side
|
The left hand side (key) should be the rancid group name, the right hand side
|
||||||
(value) should be a L<Netdisco
|
(value) should be a L<Netdisco
|
||||||
ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
||||||
to select devices in the Netdisco database.
|
to select devices in the Netdisco database.
|
||||||
|
|
||||||
=head2 C<vendormap>
|
=head2 C<vendormap>
|
||||||
|
|
||||||
If the device Vendor in Netdisco is not the same as the RANCID vendor script,
|
If the device vendor in Netdisco is not the same as the rancid vendor script or
|
||||||
configure a mapping here.
|
device type, configure a mapping here.
|
||||||
|
|
||||||
The left hand side (key) should be the RANCID vendor, the right hand side
|
The left hand side (key) should be the rancid device type, the right hand side
|
||||||
(value) should be a L<Netdisco
|
(value) should be a L<Netdisco
|
||||||
ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
||||||
to select devices in the Netdisco database.
|
to select devices in the Netdisco database.
|
||||||
|
|
||||||
|
Note that vendors might have a large array of operating systems which require
|
||||||
|
different rancid modules. Mapping operating systems to rancid device types is
|
||||||
|
a good solution to use the correct device type. Example:
|
||||||
|
|
||||||
|
host_groups:
|
||||||
|
grp-ciscosb: 'os:ros'
|
||||||
|
|
||||||
|
rancid:
|
||||||
|
vendormap:
|
||||||
|
cisco-sb: 'group:grp-ciscosb'
|
||||||
|
|
||||||
=head2 C<by_ip>
|
=head2 C<by_ip>
|
||||||
|
|
||||||
L<Netdisco
|
L<Netdisco
|
||||||
ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
||||||
to select devices which will be written to the RANCID config as an IP address,
|
to select devices which will be written to the rancid config as an IP address,
|
||||||
instead of the DNS FQDN or SNMP host name.
|
instead of the DNS FQDN or SNMP hostname.
|
||||||
|
|
||||||
=head2 C<by_hostname>
|
=head2 C<by_hostname>
|
||||||
|
|
||||||
L<Netdisco
|
L<Netdisco
|
||||||
ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
|
||||||
to select devices which will have the unqualified host name written to the
|
to select devices which will have the unqualified hostname written to the
|
||||||
RANCID config. This is done simply by stripping the C<domain_suffix>
|
rancid config. This is done simply by stripping the C<domain_suffix>
|
||||||
configuration setting from the device FQDN.
|
configuration setting from the device FQDN.
|
||||||
|
|
||||||
=head1 SEE ALSO
|
=head1 SEE ALSO
|
||||||
|
|||||||
@@ -47,4 +47,3 @@ register_worker({ phase => 'main' }, sub {
|
|||||||
});
|
});
|
||||||
|
|
||||||
true;
|
true;
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ register_worker({ phase => 'check' }, sub {
|
|||||||
or return Status->error(sprintf "Unknown port name [%s] on device %s",
|
or return Status->error(sprintf "Unknown port name [%s] on device %s",
|
||||||
$job->port, $job->device);
|
$job->port, $job->device);
|
||||||
|
|
||||||
my $vlan_reconfig_check = vlan_reconfig_check(vars->{'port'});
|
my $port_reconfig_check = port_reconfig_check(vars->{'port'});
|
||||||
return Status->error("Cannot alter vlan: $vlan_reconfig_check")
|
return Status->error("Cannot alter port: $port_reconfig_check")
|
||||||
if $vlan_reconfig_check;
|
if $port_reconfig_check;
|
||||||
|
|
||||||
return Status->done('PortControl is able to run');
|
return Status->done('PortControl is able to run');
|
||||||
});
|
});
|
||||||
@@ -56,7 +56,7 @@ sub _action {
|
|||||||
my $rv = $snmp->set_i_up_admin($data, $iid);
|
my $rv = $snmp->set_i_up_admin($data, $iid);
|
||||||
|
|
||||||
if (!defined $rv) {
|
if (!defined $rv) {
|
||||||
return Status->error(sprintf 'Failed to set [%s] up_admin to [%s] on $device: %s',
|
return Status->error(sprintf "Failed to set [%s] up_admin to [%s] on $device: %s",
|
||||||
$pn, $data, ($snmp->error || ''));
|
$pn, $data, ($snmp->error || ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ register_worker({ phase => 'check' }, sub {
|
|||||||
or return Status->error(sprintf "Unknown port name [%s] on device %s",
|
or return Status->error(sprintf "Unknown port name [%s] on device %s",
|
||||||
$job->port, $job->device);
|
$job->port, $job->device);
|
||||||
|
|
||||||
my $vlan_reconfig_check = vlan_reconfig_check(vars->{'port'});
|
my $port_reconfig_check = port_reconfig_check(vars->{'port'});
|
||||||
return Status->error("Cannot alter vlan: $vlan_reconfig_check")
|
return Status->error("Cannot alter port: $port_reconfig_check")
|
||||||
if $vlan_reconfig_check;
|
if $port_reconfig_check;
|
||||||
|
|
||||||
return Status->error("No PoE service on port [$pn] on device $device")
|
return Status->error("No PoE service on port [$pn] on device $device")
|
||||||
unless vars->{'port'}->power;
|
unless vars->{'port'}->power;
|
||||||
@@ -40,7 +40,7 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
|
|
||||||
# snmp connect using rw community
|
# snmp connect using rw community
|
||||||
my $snmp = App::Netdisco::Transport::SNMP->writer_for($device)
|
my $snmp = App::Netdisco::Transport::SNMP->writer_for($device)
|
||||||
or return Status->defer("failed to connect to $device to update vlan");
|
or return Status->defer("failed to connect to $device to set power");
|
||||||
|
|
||||||
my $powerid = get_powerid($snmp, vars->{'port'})
|
my $powerid = get_powerid($snmp, vars->{'port'})
|
||||||
or return Status->error("failed to get power ID for [$pn] from $device");
|
or return Status->error("failed to get power ID for [$pn] from $device");
|
||||||
|
|||||||
@@ -18,13 +18,14 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
my ($device, $port, $extra) = map {$job->$_} qw/device port extra/;
|
my ($device, $port, $extra) = map {$job->$_} qw/device port extra/;
|
||||||
|
|
||||||
$extra ||= 'interfaces'; my $class = undef;
|
$extra ||= 'interfaces'; my $class = undef;
|
||||||
($class, $extra) = split(/::([^:]+)$/, $extra);
|
my @values = split /::/, $extra;
|
||||||
if ($class and $extra) {
|
$extra = pop @values;
|
||||||
$class = 'SNMP::Info::'.$class;
|
if (scalar(@values)) {
|
||||||
}
|
$class = "SNMP::Info";
|
||||||
else {
|
foreach my $v (@values) {
|
||||||
$extra = $class;
|
last if ($v eq '');
|
||||||
undef $class;
|
$class = $class.'::'.$v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my $i = App::Netdisco::Transport::SNMP->reader_for($device, $class);
|
my $i = App::Netdisco::Transport::SNMP->reader_for($device, $class);
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ web_plugins:
|
|||||||
- Device::Modules
|
- Device::Modules
|
||||||
- Device::Neighbors
|
- Device::Neighbors
|
||||||
- Device::Addresses
|
- Device::Addresses
|
||||||
|
- Device::Vlans
|
||||||
extra_web_plugins: []
|
extra_web_plugins: []
|
||||||
sidebar_defaults:
|
sidebar_defaults:
|
||||||
search_node:
|
search_node:
|
||||||
@@ -229,9 +230,9 @@ devices_no: []
|
|||||||
devices_only: []
|
devices_only: []
|
||||||
discover_no: []
|
discover_no: []
|
||||||
discover_only: []
|
discover_only: []
|
||||||
discover_no_type:
|
discover_no_type: []
|
||||||
- '(?i)phone'
|
discover_waps: true
|
||||||
- '(?i)(?:wap|wireless)'
|
discover_phones: false
|
||||||
discover_min_age: 0
|
discover_min_age: 0
|
||||||
macsuck_no: []
|
macsuck_no: []
|
||||||
macsuck_only: []
|
macsuck_only: []
|
||||||
|
|||||||
@@ -39,20 +39,18 @@ device_auth:
|
|||||||
|
|
||||||
|
|
||||||
# ¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸
|
# ¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸
|
||||||
|
#
|
||||||
|
# SOME MORE INTERESTING SETTINGS WHERE THE DEFAULTS ARE PROBABLY OKAY
|
||||||
|
#
|
||||||
# ¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸
|
# ¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------
|
# discover Wireless Access Points, but not IP Phones
|
||||||
# OTHER INTERESTING SETTINGS WHERE THE DEFAULTS ARE PROBABLY OKAY
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
|
|
||||||
# do not discover IP Phones or Wireless Access Points.
|
|
||||||
# usually these are visible as device neighbors but don't support
|
# usually these are visible as device neighbors but don't support
|
||||||
# SNMP, which just clogs up the job queue.
|
# SNMP, which just clogs up the job queue.
|
||||||
# ```````````````````````````````````````````````````````````````
|
# ```````````````````````````````````````````````````````````````
|
||||||
#discover_no_type:
|
#discover_waps: true
|
||||||
# - '(?i)phone'
|
#disover_phones: false
|
||||||
# - '(?i)(?:wap|wireless)'
|
|
||||||
|
|
||||||
# this is the schedule for automatically keeping netdisco up-to-date;
|
# this is the schedule for automatically keeping netdisco up-to-date;
|
||||||
# these are good defaults, so only uncomment if needing to change.
|
# these are good defaults, so only uncomment if needing to change.
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE device_port_properties ADD COLUMN "ifindex" bigint;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -32,7 +32,7 @@ $(document).ready(function() {
|
|||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return type === 'display' ?
|
return type === 'display' ?
|
||||||
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '">' + he.encode(data || '') + '</a>' :
|
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '">' + he.encode(data || '') + '</a>' :
|
||||||
data;
|
he.encode(data || '');
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"data": 'name',
|
"data": 'name',
|
||||||
|
|||||||
@@ -50,10 +50,12 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>OS / Version</td>
|
<td>OS / Version</td>
|
||||||
<td>[% d.os | html_entity %] /
|
<td>
|
||||||
<a rel="tooltip" data-placement="top" data-offset="5"
|
<a rel="tooltip" data-placement="top" data-offset="5" data-title="Find Similar Devices"
|
||||||
data-title="Find Similar Devices"
|
href="[% search_device %]&q=[% d.os | uri %]&os=[% d.os | uri %]">[% d.os | html_entity %]</a>
|
||||||
href="[% search_device %]&q=[% d.os_ver | uri %]&os_ver=[% d.os_ver | uri %]">[% d.os_ver | html_entity %]</a>
|
/
|
||||||
|
<a rel="tooltip" data-placement="top" data-offset="5" data-title="Find Similar Devices"
|
||||||
|
href="[% search_device %]&q=[% d.os_ver | uri %]&os_ver=[% d.os_ver | uri %]">[% d.os_ver | html_entity %]</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -12,7 +12,15 @@
|
|||||||
[% th_class = ' class="portsort"' %]
|
[% th_class = ' class="portsort"' %]
|
||||||
[% END %]
|
[% END %]
|
||||||
<th[% th_class %]>
|
<th[% th_class %]>
|
||||||
|
[% IF item.name == 'c_neighbors' %]
|
||||||
|
[% IF params.c_nodes %]
|
||||||
|
Connected Nodes & Devices
|
||||||
|
[% ELSE %]
|
||||||
|
Connected Devices
|
||||||
|
[% END %]
|
||||||
|
[% ELSE %]
|
||||||
[% item.label | html_entity %]
|
[% item.label | html_entity %]
|
||||||
|
[% END %]
|
||||||
</th>
|
</th>
|
||||||
[% END %]
|
[% END %]
|
||||||
</tr>
|
</tr>
|
||||||
@@ -361,8 +369,8 @@
|
|||||||
<i class="icon-link text-warning"
|
<i class="icon-link text-warning"
|
||||||
rel="tooltip" data-placement="top" data-offset="3"
|
rel="tooltip" data-placement="top" data-offset="3"
|
||||||
data-animation="" data-title="Manual Topology"></i>
|
data-animation="" data-title="Manual Topology"></i>
|
||||||
[% END %]
|
|
||||||
</a>
|
</a>
|
||||||
|
[% END %]
|
||||||
</td>
|
</td>
|
||||||
[% END %]
|
[% END %]
|
||||||
|
|
||||||
|
|||||||
31
share/views/ajax/device/vlans.tt
Normal file
31
share/views/ajax/device/vlans.tt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<table id="data-table" class="table table-striped table-bordered" width="100%" cellspacing="0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>VLAN ID</th>
|
||||||
|
<th>VLAN Name</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
var table = $('#data-table').dataTable({
|
||||||
|
"deferRender": true,
|
||||||
|
"data": [% results %],
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"data": 'vlan',
|
||||||
|
"render": function(data, type, row, meta) {
|
||||||
|
return '<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '">' + data + '</a>';
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"data": 'description',
|
||||||
|
"render": function(data, type, row, meta) {
|
||||||
|
return '<a href="[% uri_for('/search') %]?tab=vlan&q=' + encodeURIComponent(data) + '">' + he.encode(data || '') + '</a>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[% INCLUDE 'ajax/datatabledefaults.tt' -%]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
10
share/views/ajax/device/vlans_csv.tt
Normal file
10
share/views/ajax/device/vlans_csv.tt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[% USE CSV -%]
|
||||||
|
[% CSV.dump([ 'VLAN ID' 'VLAN Name' ]) %]
|
||||||
|
|
||||||
|
[% FOREACH row IN results %]
|
||||||
|
[% mylist = [] %]
|
||||||
|
[% mylist.push(row.vlan) %]
|
||||||
|
[% mylist.push(row.description) %]
|
||||||
|
[% CSV.dump(mylist) %]
|
||||||
|
|
||||||
|
[% END %]
|
||||||
@@ -41,8 +41,8 @@ $(document).ready(function() {
|
|||||||
"type": 'portsort',
|
"type": 'portsort',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return type === 'display' ?
|
return type === 'display' ?
|
||||||
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '&c_nodes=on">' + he.encode(data) + '</a>' :
|
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '&c_nodes=on">' + he.encode(data || '') + '</a>' :
|
||||||
data;
|
he.encode(data || '');
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"data": 'ssid',
|
"data": 'ssid',
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ $(document).ready(function() {
|
|||||||
"type": 'portsort',
|
"type": 'portsort',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return type === 'display' ?
|
return type === 'display' ?
|
||||||
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '">' + he.encode(data) + '</a>' :
|
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '">' + he.encode(data || '') + '</a>' :
|
||||||
data;
|
he.encode(data || '');
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"data": 'port_name',
|
"data": 'port_name',
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ $(document).ready(function() {
|
|||||||
"type": 'portsort',
|
"type": 'portsort',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return type === 'display' ?
|
return type === 'display' ?
|
||||||
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.left_dns || row.left_ip) + '&f=' + encodeURIComponent(data) + '&c_duplex=on">' + he.encode(data) + '</a>' :
|
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.left_dns || row.left_ip) + '&f=' + encodeURIComponent(data) + '&c_duplex=on">' + he.encode(data || '') + '</a>' :
|
||||||
data;
|
he.encode(data || '');
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"data": 'left_duplex',
|
"data": 'left_duplex',
|
||||||
@@ -45,8 +45,8 @@ $(document).ready(function() {
|
|||||||
"type": 'portsort',
|
"type": 'portsort',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return type === 'display' ?
|
return type === 'display' ?
|
||||||
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.right_dns || row.right_ip) + '&f=' + encodeURIComponent(data) + '&c_duplex=on">' + he.encode(data) + '</a>' :
|
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.right_dns || row.right_ip) + '&f=' + encodeURIComponent(data) + '&c_duplex=on">' + he.encode(data || '') + '</a>' :
|
||||||
data;
|
he.encode(data || '');
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"data": 'right_duplex',
|
"data": 'right_duplex',
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ $(document).ready(function() {
|
|||||||
"type": 'portsort',
|
"type": 'portsort',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return type === 'display' ?
|
return type === 'display' ?
|
||||||
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '&c_duplex=on">' + he.encode(data) + '</a>' :
|
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '&c_duplex=on">' + he.encode(data || '') + '</a>' :
|
||||||
data;
|
he.encode(data || '');
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"data": 'name',
|
"data": 'name',
|
||||||
|
|||||||
@@ -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>Node</th>
|
<th>IP Address</th>
|
||||||
<th>MAC Address</th>
|
<th>MAC Address</th>
|
||||||
<th class="nd_center-cell">DNS</th>
|
<th class="nd_center-cell">DNS</th>
|
||||||
<th>Last Used</th>
|
<th>Last Used</th>
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ $(document).ready(function() {
|
|||||||
"type": 'portsort',
|
"type": 'portsort',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return type === 'display' ?
|
return type === 'display' ?
|
||||||
'<a href="[% device_ports %]&c_nodes=on&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '">' + he.encode(data) + '</a>' :
|
'<a href="[% device_ports %]&c_nodes=on&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '">' + he.encode(data || '') + '</a>' :
|
||||||
data;
|
he.encode(data || '');
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"data": 'remote_id',
|
"data": 'remote_id',
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ $(document).ready(function() {
|
|||||||
"type": 'portsort',
|
"type": 'portsort',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return type === 'display' ?
|
return type === 'display' ?
|
||||||
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '&c_nodes=on">' + he.encode(data) + '</a>' :
|
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '&c_nodes=on">' + he.encode(data || '') + '</a>' :
|
||||||
data;
|
he.encode(data || '');
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"data": 'description',
|
"data": 'description',
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ $(document).ready(function() {
|
|||||||
"type": 'portsort',
|
"type": 'portsort',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return type === 'display' ?
|
return type === 'display' ?
|
||||||
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '&c_nodes=on">' + he.encode(data) + '</a>' :
|
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '&c_nodes=on">' + he.encode(data || '') + '</a>' :
|
||||||
data;
|
he.encode(data || '');
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"data": 'description',
|
"data": 'description',
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ $(document).ready(function() {
|
|||||||
"type": 'portsort',
|
"type": 'portsort',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return type === 'display' ?
|
return type === 'display' ?
|
||||||
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '&c_nodes=on">' + he.encode(data) + '</a>' :
|
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.ip) + '&f=' + encodeURIComponent(data) + '&c_nodes=on">' + he.encode(data || '') + '</a>' :
|
||||||
data;
|
he.encode(data || '');
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"data": 'description',
|
"data": 'description',
|
||||||
|
|||||||
@@ -20,27 +20,27 @@ $(document).ready(function() {
|
|||||||
{
|
{
|
||||||
"data": 'left_device',
|
"data": 'left_device',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return '<a href="[% device_ports %]&q=' + encodeURIComponent(data) + '">' + he.encode(data) + '</a>'; }
|
return '<a href="[% device_ports %]&q=' + encodeURIComponent(data) + '">' + he.encode(data || '') + '</a>'; }
|
||||||
}, {
|
}, {
|
||||||
"data": 'left_port',
|
"data": 'left_port',
|
||||||
"type": 'portsort',
|
"type": 'portsort',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return type === 'display' ?
|
return type === 'display' ?
|
||||||
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.left_device) + '&f=' + encodeURIComponent(data) + '">' + he.encode(data) + '</a>' :
|
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.left_device) + '&f=' + encodeURIComponent(data) + '">' + he.encode(data || '') + '</a>' :
|
||||||
data; }
|
he.encode(data || ''); }
|
||||||
}, {
|
}, {
|
||||||
"data": 'left_vlans'
|
"data": 'left_vlans'
|
||||||
}, {
|
}, {
|
||||||
"data": 'right_device',
|
"data": 'right_device',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return '<a href="[% device_ports %]&q=' + encodeURIComponent(data) + '">' + he.encode(data) + '</a>'; }
|
return '<a href="[% device_ports %]&q=' + encodeURIComponent(data) + '">' + he.encode(data || '') + '</a>'; }
|
||||||
}, {
|
}, {
|
||||||
"data": 'right_port',
|
"data": 'right_port',
|
||||||
"type": 'portsort',
|
"type": 'portsort',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return type === 'display' ?
|
return type === 'display' ?
|
||||||
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.right_device) + '&f=' + encodeURIComponent(data) + '">' + he.encode(data) + '</a>' :
|
'<a href="[% device_ports %]&q=' + encodeURIComponent(row.right_device) + '&f=' + encodeURIComponent(data) + '">' + he.encode(data || '') + '</a>' :
|
||||||
data; }
|
he.encode(data || ''); }
|
||||||
}, {
|
}, {
|
||||||
"data": 'right_vlans'
|
"data": 'right_vlans'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Port</th>
|
<th>Port</th>
|
||||||
<th>Vlan</th>
|
<th>VLAN</th>
|
||||||
<th>Speed</th>
|
<th>Speed</th>
|
||||||
<th>Last Change</th>
|
<th>Last Change</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[% USE CSV -%]
|
[% USE CSV -%]
|
||||||
[% CSV.dump([ 'Name' 'Port' 'Description' 'Vlan' ]) %]
|
[% CSV.dump([ 'Name' 'Port' 'Description' 'VLAN' ]) %]
|
||||||
|
|
||||||
[% FOREACH row IN results %]
|
[% FOREACH row IN results %]
|
||||||
[% mylist = [] %]
|
[% mylist = [] %]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<table id="vs-data-table" class="table table-striped table-bordered" width="100%" cellspacing="0">
|
<table id="vs-data-table" class="table table-striped table-bordered" width="100%" cellspacing="0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Vlan</th>
|
<th>VLAN</th>
|
||||||
<th>Device</th>
|
<th>Device</th>
|
||||||
<th>Description</th>
|
<th>Description</th>
|
||||||
<th>Model</th>
|
<th>Model</th>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[% USE CSV -%]
|
[% USE CSV -%]
|
||||||
[% CSV.dump([ 'Vlan' 'Device' 'Description' 'Model' 'OS' 'Vendor' ]) %]
|
[% CSV.dump([ 'VLAN' 'Device' 'Description' 'Model' 'OS' 'Vendor' ]) %]
|
||||||
|
|
||||||
[% FOREACH row IN results %]
|
[% FOREACH row IN results %]
|
||||||
[% mylist = [] %]
|
[% mylist = [] %]
|
||||||
|
|||||||
@@ -57,7 +57,6 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th><a href="http://www.postgresql.org">PostgreSQL</a></th>
|
<th><a href="http://www.postgresql.org">PostgreSQL</a></th>
|
||||||
<th>[% stats.pg_ver | html_entity %]</th>
|
<th>[% stats.pg_ver | html_entity %]</th>
|
||||||
</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th><a href="http://www.perl.org">Perl</a></th>
|
<th><a href="http://www.perl.org">Perl</a></th>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
rel="tooltip" data-placement="left" data-offset="5" data-title="Applies to IPv4 Only">
|
rel="tooltip" data-placement="left" data-offset="5" data-title="Applies to IPv4 Only">
|
||||||
<label class="add-on">
|
<label class="add-on">
|
||||||
<input type="checkbox" id="never"
|
<input type="checkbox" id="never"
|
||||||
name="never"[% ' checked="checked"' IF params.never %]/>
|
name="never"[% ' checked="checked"' IF (params.never OR vars.sidebar_defaults.report_ipinventory.never) %]/>
|
||||||
</label>
|
</label>
|
||||||
<label class="nd_checkboxlabel" for="never">
|
<label class="nd_checkboxlabel" for="never">
|
||||||
<span class="nd_searchcheckbox uneditable-input">List IP's Never Seen</span>
|
<span class="nd_searchcheckbox uneditable-input">List IP's Never Seen</span>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
<div class="clearfix input-prepend">
|
<div class="clearfix input-prepend">
|
||||||
<label class="add-on">
|
<label class="add-on">
|
||||||
<input type="checkbox" id="fruonly"
|
<input type="checkbox" id="fruonly"
|
||||||
name="fruonly"[% ' checked="checked"' IF vars.sidebar_defaults.report_moduleinventory.fruonly %]/>
|
name="fruonly"[% ' checked="checked"' IF (params.fruonly OR vars.sidebar_defaults.report_moduleinventory.fruonly) %]/>
|
||||||
</label>
|
</label>
|
||||||
<label class="nd_checkboxlabel" for="fruonly">
|
<label class="nd_checkboxlabel" for="fruonly">
|
||||||
<span class="nd_searchcheckbox uneditable-input">FRU Only</span>
|
<span class="nd_searchcheckbox uneditable-input">FRU Only</span>
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
<div class="clearfix input-prepend">
|
<div class="clearfix input-prepend">
|
||||||
<label class="add-on">
|
<label class="add-on">
|
||||||
<input type="checkbox" id="matchall"
|
<input type="checkbox" id="matchall"
|
||||||
name="matchall"[% ' checked="checked"' IF vars.sidebar_defaults.report_moduleinventory.matchall %]/>
|
name="matchall"[% ' checked="checked"' IF (params.matchall OR vars.sidebar_defaults.report_moduleinventory.matchall) %]/>
|
||||||
</label>
|
</label>
|
||||||
<label class="nd_checkboxlabel" for="matchall">
|
<label class="nd_checkboxlabel" for="matchall">
|
||||||
<span class="nd_searchcheckbox uneditable-input">Match All Options</span>
|
<span class="nd_searchcheckbox uneditable-input">Match All Options</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user