Merge branch 'master' into og-multiple-domain-suffix
This commit is contained in:
37
.github/issue_template.md
vendored
37
.github/issue_template.md
vendored
@@ -1,12 +1,33 @@
|
|||||||
<!--- Provide a general summary of the issue in the Title above -->
|
<!---
|
||||||
|
|
||||||
<!-- stop! If your ticket is about a device not being detected correctly, -->
|
READ THIS FIRST!
|
||||||
<!-- see SNMP::Info: https://github.com/netdisco/snmp-info/issues/new -->
|
----------------
|
||||||
|
|
||||||
<!-- stop! If you have new MIBs to submit, -->
|
STOP! If your ticket is about a device not being detected correctly,
|
||||||
<!-- see netdisco-mibs: https://github.com/netdisco/netdisco-mibs/issues/new -->
|
see SNMP::Info: https://github.com/netdisco/snmp-info/issues/new
|
||||||
|
|
||||||
|
STOP! If you have new MIBs to submit,
|
||||||
|
see netdisco-mibs: https://github.com/netdisco/netdisco-mibs/issues/new
|
||||||
|
|
||||||
|
STOP! If you are running a netdisco docker setup,
|
||||||
|
see netdisco-docker: https://github.com/netdisco/netdisco-docker/issues/new
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
everything else about Netdisco's behaviour is good, here :-D
|
||||||
|
|
||||||
|
the more info you can provide, the easier it is for us the help you, so please
|
||||||
|
fill out as many of the items below as possible.
|
||||||
|
|
||||||
|
Provide a general summary of the issue in the Title above
|
||||||
|
|
||||||
|
when including netdisco config snippets, whitespace matters since it's a yaml file
|
||||||
|
for github issues it really helps if you include the relevant config parts in a codeblock (code fencing)
|
||||||
|
see the "code" subject on https://guides.github.com/features/mastering-markdown/ for that)
|
||||||
|
this should preserve spaces in the issue tracker and make troubleshooting quicker
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
<!-- everything else about Netdisco's behaviour is good, here :-D -->
|
|
||||||
|
|
||||||
## Expected Behavior
|
## Expected Behavior
|
||||||
<!--- If you're describing a bug, tell us what should happen -->
|
<!--- If you're describing a bug, tell us what should happen -->
|
||||||
@@ -37,6 +58,10 @@
|
|||||||
* Netdisco version used:
|
* Netdisco version used:
|
||||||
* SNMP::Info version used:
|
* SNMP::Info version used:
|
||||||
|
|
||||||
|
## Config info (deployment.yml)
|
||||||
|
<!--- if possible include all options you added to your deployment.yml file, since -->
|
||||||
|
<!--- some options can change the behaviour in drastic ways -->
|
||||||
|
|
||||||
## Device information
|
## Device information
|
||||||
<!--- if the issue relates to specific devices their info would be usefull -->
|
<!--- if the issue relates to specific devices their info would be usefull -->
|
||||||
<!--- do note that the following command might contain sensitive info, you can -->
|
<!--- do note that the following command might contain sensitive info, you can -->
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -15,3 +15,7 @@ _build
|
|||||||
blib
|
blib
|
||||||
!.docker/hooks/*
|
!.docker/hooks/*
|
||||||
.idea
|
.idea
|
||||||
|
node_modules/*
|
||||||
|
yarn.lock
|
||||||
|
package.json
|
||||||
|
.stylelintrc
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ language: perl
|
|||||||
perl:
|
perl:
|
||||||
- "5.30"
|
- "5.30"
|
||||||
- "5.10"
|
- "5.10"
|
||||||
|
os: linux
|
||||||
|
dist: trusty
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- libsnmp-dev
|
- libsnmp-dev
|
||||||
- phantomjs
|
- phantomjs
|
||||||
- graphviz
|
- graphviz
|
||||||
hosts:
|
hosts:
|
||||||
- localhost
|
- localhost
|
||||||
branches:
|
branches:
|
||||||
@@ -15,7 +17,7 @@ branches:
|
|||||||
- /^2\.\d{6}$/
|
- /^2\.\d{6}$/
|
||||||
- 'master'
|
- 'master'
|
||||||
install:
|
install:
|
||||||
- cpanm --quiet --notest PkgConfig Test::CChecker Alien::zlib::Static Alien::OpenSSL::Static Alien::SNMP
|
- cpanm --quiet --notest https://github.com/egiles/test-compile/archive/v2.1.2.tar.gz PkgConfig Test::CChecker Alien::zlib::Static Alien::OpenSSL::Static Alien::SNMP
|
||||||
script: |
|
script: |
|
||||||
perl Build.PL && \
|
perl Build.PL && \
|
||||||
./Build && \
|
./Build && \
|
||||||
|
|||||||
1
Build.PL
1
Build.PL
@@ -26,6 +26,7 @@ Module::Build->new(
|
|||||||
'App::cpanminus' => '1.6108',
|
'App::cpanminus' => '1.6108',
|
||||||
'App::local::lib::helper' => '0.07',
|
'App::local::lib::helper' => '0.07',
|
||||||
'Archive::Extract' => '0',
|
'Archive::Extract' => '0',
|
||||||
|
'Authen::Radius' => '0',
|
||||||
'CGI::Expand' => '2.05',
|
'CGI::Expand' => '2.05',
|
||||||
'Data::Printer' => '0',
|
'Data::Printer' => '0',
|
||||||
'DBD::Pg' => '0',
|
'DBD::Pg' => '0',
|
||||||
|
|||||||
24
LICENCE
24
LICENCE
@@ -1,24 +0,0 @@
|
|||||||
Copyright (c) 2012, The Netdisco Developer Team
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of the Netdisco Project nor the
|
|
||||||
names of its contributors may be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE NETDISCO DEVELOPER TEAM BE LIABLE FOR ANY
|
|
||||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
29
LICENSE.md
Normal file
29
LICENSE.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2019, The Netdisco Developer Team.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
6
MANIFEST
6
MANIFEST
@@ -62,6 +62,7 @@ lib/App/Netdisco/DB/Result/Virtual/DevicePoeStatus.pm
|
|||||||
lib/App/Netdisco/DB/Result/Virtual/DevicePortSpeed.pm
|
lib/App/Netdisco/DB/Result/Virtual/DevicePortSpeed.pm
|
||||||
lib/App/Netdisco/DB/Result/Virtual/DuplexMismatch.pm
|
lib/App/Netdisco/DB/Result/Virtual/DuplexMismatch.pm
|
||||||
lib/App/Netdisco/DB/Result/Virtual/GenericReport.pm
|
lib/App/Netdisco/DB/Result/Virtual/GenericReport.pm
|
||||||
|
lib/App/Netdisco/DB/Result/Virtual/LastNode.pm
|
||||||
lib/App/Netdisco/DB/Result/Virtual/NodeIp4.pm
|
lib/App/Netdisco/DB/Result/Virtual/NodeIp4.pm
|
||||||
lib/App/Netdisco/DB/Result/Virtual/NodeIp6.pm
|
lib/App/Netdisco/DB/Result/Virtual/NodeIp6.pm
|
||||||
lib/App/Netdisco/DB/Result/Virtual/NodeMonitor.pm
|
lib/App/Netdisco/DB/Result/Virtual/NodeMonitor.pm
|
||||||
@@ -237,7 +238,7 @@ lib/App/Netdisco/Worker/Plugin/Vlan/Core.pm
|
|||||||
lib/App/Netdisco/Worker/Runner.pm
|
lib/App/Netdisco/Worker/Runner.pm
|
||||||
lib/App/Netdisco/Worker/Status.pm
|
lib/App/Netdisco/Worker/Status.pm
|
||||||
lib/Dancer/Template/NetdiscoTemplateToolkit.pm
|
lib/Dancer/Template/NetdiscoTemplateToolkit.pm
|
||||||
LICENCE
|
LICENSE.md
|
||||||
MANIFEST This list of files
|
MANIFEST This list of files
|
||||||
META.json
|
META.json
|
||||||
META.yml
|
META.yml
|
||||||
@@ -318,6 +319,7 @@ share/public/javascripts/netdisco_portcontrol.js
|
|||||||
share/public/javascripts/portsort.js
|
share/public/javascripts/portsort.js
|
||||||
share/public/javascripts/toastr.js
|
share/public/javascripts/toastr.js
|
||||||
share/public/javascripts/underscore.min.js
|
share/public/javascripts/underscore.min.js
|
||||||
|
share/radius_dictionaries/TODO
|
||||||
share/schema_versions/App-Netdisco-DB-1-2-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-1-2-PostgreSQL.sql
|
||||||
share/schema_versions/App-Netdisco-DB-10-11-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-10-11-PostgreSQL.sql
|
||||||
share/schema_versions/App-Netdisco-DB-11-12-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-11-12-PostgreSQL.sql
|
||||||
@@ -371,6 +373,7 @@ share/schema_versions/App-Netdisco-DB-54-55-PostgreSQL.sql
|
|||||||
share/schema_versions/App-Netdisco-DB-55-56-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-55-56-PostgreSQL.sql
|
||||||
share/schema_versions/App-Netdisco-DB-56-57-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-56-57-PostgreSQL.sql
|
||||||
share/schema_versions/App-Netdisco-DB-57-58-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-57-58-PostgreSQL.sql
|
||||||
|
share/schema_versions/App-Netdisco-DB-58-59-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
|
||||||
@@ -505,6 +508,7 @@ share/views/sidebar/search/device.tt
|
|||||||
share/views/sidebar/search/node.tt
|
share/views/sidebar/search/node.tt
|
||||||
share/views/sidebar/search/port.tt
|
share/views/sidebar/search/port.tt
|
||||||
xt/00-compile.t
|
xt/00-compile.t
|
||||||
|
xt/01-local-pod.t
|
||||||
xt/10-sort_port.t
|
xt/10-sort_port.t
|
||||||
xt/11-portsort.t
|
xt/11-portsort.t
|
||||||
xt/20-checkacl.t
|
xt/20-checkacl.t
|
||||||
|
|||||||
12
META.json
12
META.json
@@ -4,7 +4,7 @@
|
|||||||
"Oliver Gorwits <oliver@cpan.org>"
|
"Oliver Gorwits <oliver@cpan.org>"
|
||||||
],
|
],
|
||||||
"dynamic_config" : 1,
|
"dynamic_config" : 1,
|
||||||
"generated_by" : "Module::Build version 0.4224",
|
"generated_by" : "Module::Build version 0.4229",
|
||||||
"license" : [
|
"license" : [
|
||||||
"bsd"
|
"bsd"
|
||||||
],
|
],
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
"App::cpanminus" : "1.6108",
|
"App::cpanminus" : "1.6108",
|
||||||
"App::local::lib::helper" : "0.07",
|
"App::local::lib::helper" : "0.07",
|
||||||
"Archive::Extract" : "0",
|
"Archive::Extract" : "0",
|
||||||
|
"Authen::Radius" : "0",
|
||||||
"CGI::Expand" : "2.05",
|
"CGI::Expand" : "2.05",
|
||||||
"DBD::Pg" : "0",
|
"DBD::Pg" : "0",
|
||||||
"DBIx::Class" : "0.082841",
|
"DBIx::Class" : "0.082841",
|
||||||
@@ -143,7 +144,7 @@
|
|||||||
},
|
},
|
||||||
"App::Netdisco::DB" : {
|
"App::Netdisco::DB" : {
|
||||||
"file" : "lib/App/Netdisco/DB.pm",
|
"file" : "lib/App/Netdisco/DB.pm",
|
||||||
"version" : "58"
|
"version" : "59"
|
||||||
},
|
},
|
||||||
"App::Netdisco::DB::ExplicitLocking" : {
|
"App::Netdisco::DB::ExplicitLocking" : {
|
||||||
"file" : "lib/App/Netdisco/DB/ExplicitLocking.pm"
|
"file" : "lib/App/Netdisco/DB/ExplicitLocking.pm"
|
||||||
@@ -268,6 +269,9 @@
|
|||||||
"App::Netdisco::DB::Result::Virtual::GenericReport" : {
|
"App::Netdisco::DB::Result::Virtual::GenericReport" : {
|
||||||
"file" : "lib/App/Netdisco/DB/Result/Virtual/GenericReport.pm"
|
"file" : "lib/App/Netdisco/DB/Result/Virtual/GenericReport.pm"
|
||||||
},
|
},
|
||||||
|
"App::Netdisco::DB::Result::Virtual::LastNode" : {
|
||||||
|
"file" : "lib/App/Netdisco/DB/Result/Virtual/LastNode.pm"
|
||||||
|
},
|
||||||
"App::Netdisco::DB::Result::Virtual::NodeIp4" : {
|
"App::Netdisco::DB::Result::Virtual::NodeIp4" : {
|
||||||
"file" : "lib/App/Netdisco/DB/Result/Virtual/NodeIp4.pm"
|
"file" : "lib/App/Netdisco/DB/Result/Virtual/NodeIp4.pm"
|
||||||
},
|
},
|
||||||
@@ -804,7 +808,7 @@
|
|||||||
},
|
},
|
||||||
"homepage" : "http://netdisco.org/",
|
"homepage" : "http://netdisco.org/",
|
||||||
"license" : [
|
"license" : [
|
||||||
"http://opensource.org/licenses/BSD-3-Clause"
|
"http://opensource.org/licenses/bsd-license.php"
|
||||||
],
|
],
|
||||||
"repository" : {
|
"repository" : {
|
||||||
"url" : "https://github.com/netdisco/netdisco"
|
"url" : "https://github.com/netdisco/netdisco"
|
||||||
@@ -813,5 +817,5 @@
|
|||||||
"x_MailingList" : "https://lists.sourceforge.net/lists/listinfo/netdisco-users"
|
"x_MailingList" : "https://lists.sourceforge.net/lists/listinfo/netdisco-users"
|
||||||
},
|
},
|
||||||
"version" : "2.042010",
|
"version" : "2.042010",
|
||||||
"x_serialization_backend" : "JSON::PP version 2.97001"
|
"x_serialization_backend" : "JSON::PP version 4.02"
|
||||||
}
|
}
|
||||||
|
|||||||
9
META.yml
9
META.yml
@@ -14,7 +14,7 @@ configure_requires:
|
|||||||
DBIx::Class: '0.082810'
|
DBIx::Class: '0.082810'
|
||||||
Module::Build: '0.42'
|
Module::Build: '0.42'
|
||||||
dynamic_config: 1
|
dynamic_config: 1
|
||||||
generated_by: 'Module::Build version 0.4224, CPAN::Meta::Converter version 2.150010'
|
generated_by: 'Module::Build version 0.4229, CPAN::Meta::Converter version 2.150010'
|
||||||
license: bsd
|
license: bsd
|
||||||
meta-spec:
|
meta-spec:
|
||||||
url: http://module-build.sourceforge.net/META-spec-v1.4.html
|
url: http://module-build.sourceforge.net/META-spec-v1.4.html
|
||||||
@@ -38,7 +38,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: '58'
|
version: '59'
|
||||||
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:
|
||||||
@@ -121,6 +121,8 @@ provides:
|
|||||||
file: lib/App/Netdisco/DB/Result/Virtual/DuplexMismatch.pm
|
file: lib/App/Netdisco/DB/Result/Virtual/DuplexMismatch.pm
|
||||||
App::Netdisco::DB::Result::Virtual::GenericReport:
|
App::Netdisco::DB::Result::Virtual::GenericReport:
|
||||||
file: lib/App/Netdisco/DB/Result/Virtual/GenericReport.pm
|
file: lib/App/Netdisco/DB/Result/Virtual/GenericReport.pm
|
||||||
|
App::Netdisco::DB::Result::Virtual::LastNode:
|
||||||
|
file: lib/App/Netdisco/DB/Result/Virtual/LastNode.pm
|
||||||
App::Netdisco::DB::Result::Virtual::NodeIp4:
|
App::Netdisco::DB::Result::Virtual::NodeIp4:
|
||||||
file: lib/App/Netdisco/DB/Result/Virtual/NodeIp4.pm
|
file: lib/App/Netdisco/DB/Result/Virtual/NodeIp4.pm
|
||||||
App::Netdisco::DB::Result::Virtual::NodeIp6:
|
App::Netdisco::DB::Result::Virtual::NodeIp6:
|
||||||
@@ -483,6 +485,7 @@ requires:
|
|||||||
App::cpanminus: '1.6108'
|
App::cpanminus: '1.6108'
|
||||||
App::local::lib::helper: '0.07'
|
App::local::lib::helper: '0.07'
|
||||||
Archive::Extract: '0'
|
Archive::Extract: '0'
|
||||||
|
Authen::Radius: '0'
|
||||||
CGI::Expand: '2.05'
|
CGI::Expand: '2.05'
|
||||||
DBD::Pg: '0'
|
DBD::Pg: '0'
|
||||||
DBIx::Class: '0.082841'
|
DBIx::Class: '0.082841'
|
||||||
@@ -556,7 +559,7 @@ resources:
|
|||||||
MailingList: https://lists.sourceforge.net/lists/listinfo/netdisco-users
|
MailingList: https://lists.sourceforge.net/lists/listinfo/netdisco-users
|
||||||
bugtracker: https://github.com/netdisco/netdisco/issues
|
bugtracker: https://github.com/netdisco/netdisco/issues
|
||||||
homepage: http://netdisco.org/
|
homepage: http://netdisco.org/
|
||||||
license: http://opensource.org/licenses/BSD-3-Clause
|
license: http://opensource.org/licenses/bsd-license.php
|
||||||
repository: https://github.com/netdisco/netdisco
|
repository: https://github.com/netdisco/netdisco
|
||||||
version: '2.042010'
|
version: '2.042010'
|
||||||
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
|
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ these is an optional service which the user is asked to confirm.
|
|||||||
Pre-existing requirements are that there be a database table created and a
|
Pre-existing requirements are that there be a database table created and a
|
||||||
user with rights to create tables in that database. Both the table and user
|
user with rights to create tables in that database. Both the table and user
|
||||||
name must match those configured in your environment YAML file (default
|
name must match those configured in your environment YAML file (default
|
||||||
C<~/environments/deployment.yml>).
|
F<~/environments/deployment.yml>).
|
||||||
|
|
||||||
This script will download the latest MAC address vendor prefix data from the
|
This script will download the latest MAC address vendor prefix data from the
|
||||||
Internet, and update the OUI table in the database. Hence Internet access is
|
Internet, and update the OUI table in the database. Hence Internet access is
|
||||||
@@ -80,10 +80,17 @@ required to run the script.
|
|||||||
Similarly the latest Netdisco MIB bundle is also downloaded and placed into
|
Similarly the latest Netdisco MIB bundle is also downloaded and placed into
|
||||||
the user's home directory (or C<$ENV{NETDISCO_HOME}>).
|
the user's home directory (or C<$ENV{NETDISCO_HOME}>).
|
||||||
|
|
||||||
|
If you upgrade Netdisco make sure you run this script again to make sure
|
||||||
|
your config remains compatible.
|
||||||
|
|
||||||
|
Before each upgrade also review the
|
||||||
|
L<Release notes|https://github.com/netdisco/netdisco/wiki/Release-Notes> since
|
||||||
|
additional steps might be required!
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
print color 'bold cyan';
|
print color 'bold cyan';
|
||||||
say 'This is the Netdisco II deployment script.';
|
say 'This is the Netdisco 2 deployment script.';
|
||||||
say '';
|
say '';
|
||||||
say 'Before we continue, the following prerequisites must be in place:';
|
say 'Before we continue, the following prerequisites must be in place:';
|
||||||
say ' * Database added to PostgreSQL for Netdisco';
|
say ' * Database added to PostgreSQL for Netdisco';
|
||||||
@@ -92,6 +99,11 @@ say ' * "~/environments/deployment.yml" file configured with Database dsn/user/p
|
|||||||
say ' * A full backup of any existing Netdisco database data';
|
say ' * A full backup of any existing Netdisco database data';
|
||||||
say ' * Internet access (for OUIs and MIBs)';
|
say ' * Internet access (for OUIs and MIBs)';
|
||||||
say '';
|
say '';
|
||||||
|
say 'If you are upgrading Netdisco 2 read the release notes:';
|
||||||
|
say 'https://github.com/netdisco/netdisco/wiki/Release-Notes';
|
||||||
|
say 'There you will find required and incompatible changes';
|
||||||
|
say 'which are not covered by this script.';
|
||||||
|
say '';
|
||||||
say 'You will be asked to confirm all changes to your system.';
|
say 'You will be asked to confirm all changes to your system.';
|
||||||
say '';
|
say '';
|
||||||
print color 'reset';
|
print color 'reset';
|
||||||
@@ -194,13 +206,13 @@ sub deploy_db {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub get_userpass {
|
sub get_userpass {
|
||||||
my $term = shift;
|
my $upterm = shift;
|
||||||
my $name = $term->get_reply(prompt => 'Username: ');
|
my $name = $upterm->get_reply(prompt => 'Username: ');
|
||||||
my $pass = $term->get_reply(prompt => 'Password: ');
|
my $pass = $upterm->get_reply(prompt => 'Password: ');
|
||||||
|
|
||||||
unless ($name and $pass) {
|
unless ($name and $pass) {
|
||||||
say 'username and password cannot be empty, please try again.';
|
say 'username and password cannot be empty, please try again.';
|
||||||
($name, $pass) = get_userpass($term);
|
($name, $pass) = get_userpass($upterm);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ($name, $pass);
|
return ($name, $pass);
|
||||||
@@ -257,7 +269,7 @@ sub deploy_oui {
|
|||||||
print color 'reset';
|
print color 'reset';
|
||||||
}
|
}
|
||||||
|
|
||||||
# This subroutine is from Wireshark's make-manuf
|
# This subroutine is based on Wireshark's make-manuf
|
||||||
# http://anonsvn.wireshark.org/wireshark/trunk/tools/make-manuf
|
# http://anonsvn.wireshark.org/wireshark/trunk/tools/make-manuf
|
||||||
sub shorten {
|
sub shorten {
|
||||||
my $manuf = shift;
|
my $manuf = shift;
|
||||||
@@ -271,22 +283,27 @@ sub shorten {
|
|||||||
# & isn't needed when Standalone
|
# & isn't needed when Standalone
|
||||||
$manuf =~ s/ \& / /g;
|
$manuf =~ s/ \& / /g;
|
||||||
|
|
||||||
|
# remove junk whitespace
|
||||||
|
$manuf =~ s/\s+/ /g;
|
||||||
|
|
||||||
# Remove any "the", "inc", "plc" ...
|
# Remove any "the", "inc", "plc" ...
|
||||||
$manuf
|
$manuf
|
||||||
=~ s/\s(the|inc|incorporated|plc|systems|corp|corporation|s\/a|a\/s|ab|ag|kg|gmbh|co|company|limited|ltd|holding|spa)(?= )//gi;
|
=~ s/\s(?:the|inc|incorporated|plc|systems|corp|corporation|s\/a|a\/s|ab|ag|kg|gmbh|co|company|limited|ltd|holding|spa)(?= )//gi;
|
||||||
|
|
||||||
# Convert to consistent case
|
# Convert to consistent case
|
||||||
$manuf =~ s/(\w+)/\u\L$1/g;
|
$manuf =~ s/(\w+)/\u\L$1/g;
|
||||||
|
|
||||||
# Remove all spaces
|
|
||||||
$manuf =~ s/\s+//g;
|
|
||||||
|
|
||||||
# Deviating from make-manuf for HP
|
# Deviating from make-manuf for HP
|
||||||
$manuf =~ s/Hewlett[-]?Packard/Hp/;
|
$manuf =~ s/Hewlett[-]?Packard/Hp/;
|
||||||
|
|
||||||
# Truncate all names to a reasonable length, say, 8 characters.
|
# Truncate all names to first two words max 20 chars
|
||||||
# If the string contains UTF-8, this may be substantially more than 8 bytes.
|
if (length($manuf) > 21) {
|
||||||
$manuf = substr( $manuf, 0, 8 );
|
my @twowords = grep {defined} (split ' ', $manuf)[0 .. 1];
|
||||||
|
$manuf = join ' ', @twowords;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove all spaces
|
||||||
|
$manuf =~ s/\s+//g;
|
||||||
|
|
||||||
return encode( "utf8", $manuf );
|
return encode( "utf8", $manuf );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ L<Release Notes|https://github.com/netdisco/netdisco/wiki/Release-Notes>.
|
|||||||
|
|
||||||
Netdisco has several Perl library dependencies which will be automatically
|
Netdisco has several Perl library dependencies which will be automatically
|
||||||
installed. However it's required that you first install the following
|
installed. However it's required that you first install the following
|
||||||
operating system packages:
|
operating system packages, if not the installation will most likely fail
|
||||||
|
further down the road.
|
||||||
|
|
||||||
On Ubuntu/Debian:
|
On Ubuntu/Debian:
|
||||||
|
|
||||||
@@ -100,7 +101,7 @@ will take about 250MB including MIB files.
|
|||||||
root:~# useradd -m -p x -s /bin/bash netdisco
|
root:~# useradd -m -p x -s /bin/bash netdisco
|
||||||
|
|
||||||
Netdisco uses the PostgreSQL database server. Install PostgreSQL (at least
|
Netdisco uses the PostgreSQL database server. Install PostgreSQL (at least
|
||||||
version 8.4) and then change to the PostgreSQL superuser (usually
|
version 9.4) and then change to the PostgreSQL superuser (usually
|
||||||
C<postgres>). Create a new database and PostgreSQL user for the Netdisco
|
C<postgres>). Create a new database and PostgreSQL user for the Netdisco
|
||||||
application:
|
application:
|
||||||
|
|
||||||
@@ -115,14 +116,25 @@ application:
|
|||||||
You may wish to L<amend the PostgreSQL
|
You may wish to L<amend the PostgreSQL
|
||||||
configuration|https://github.com/netdisco/netdisco/wiki/Install-Tips#enable-md5-authentication-to-postgresql>
|
configuration|https://github.com/netdisco/netdisco/wiki/Install-Tips#enable-md5-authentication-to-postgresql>
|
||||||
so that local connections are working. The default PostgreSQL configuration
|
so that local connections are working. The default PostgreSQL configuration
|
||||||
also needs tuning for modern server hardware. We recommend that you use the
|
can also use tuning for modern server hardware. We recommend that you use one of the following
|
||||||
C<pgtune> Python program to auto-tune your C<postgresql.conf> file:
|
tools to tune your C<postgresql.conf> file:
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
=item *
|
=item L<postgresqltuner|https://github.com/jfcoz/postgresqltuner>
|
||||||
|
|
||||||
L<https://github.com/elitwin/pgtune>
|
Script that will check your operating system resources and settings as well as your
|
||||||
|
running PostgreSQL database and will make recommendations based on actual load. Works
|
||||||
|
on new netdisco installs but will make the best suggestions once the database contains
|
||||||
|
a bigger dataset.
|
||||||
|
|
||||||
|
=item L<pgtune (fork)|https://pgtune.leopard.in.ua>
|
||||||
|
|
||||||
|
A web based application which will recommend which parameters to change.
|
||||||
|
|
||||||
|
=item L<pgtune|https://github.com/elitwin/pgtune>
|
||||||
|
|
||||||
|
Program to auto-tune your C<postgresql.conf>, regretfully not updated in a while.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
@@ -229,7 +241,7 @@ If you're running a version of Netdisco prior to 2.x then you should follow
|
|||||||
the full installation instructions, above. This process is for upgrading
|
the full installation instructions, above. This process is for upgrading
|
||||||
version 2.x only.
|
version 2.x only.
|
||||||
|
|
||||||
Before upgrading please review the latest L<Release Notes|https://github.com/netdisco/netdisco/wiki/Release-Notes>.
|
Before upgrading always review the latest L<Release Notes|https://github.com/netdisco/netdisco/wiki/Release-Notes>.
|
||||||
Then the process below should be run for each installation:
|
Then the process below should be run for each installation:
|
||||||
|
|
||||||
# upgrade Netdisco
|
# upgrade Netdisco
|
||||||
@@ -251,7 +263,7 @@ Then the process below should be run for each installation:
|
|||||||
|
|
||||||
The main black navigation bar has a search box which is smart enough to work
|
The main black navigation bar has a search box which is smart enough to work
|
||||||
out what you're looking for in most cases. For example device names, node IP
|
out what you're looking for in most cases. For example device names, node IP
|
||||||
or MAC addreses, VLAN numbers, and so on.
|
or MAC addresses, VLAN numbers, and so on.
|
||||||
|
|
||||||
=head2 Command-Line Device and Port Actions
|
=head2 Command-Line Device and Port Actions
|
||||||
|
|
||||||
@@ -332,7 +344,7 @@ built upon.
|
|||||||
|
|
||||||
=head1 COPYRIGHT AND LICENSE
|
=head1 COPYRIGHT AND LICENSE
|
||||||
|
|
||||||
This software is copyright (c) 2011-2018 by The Netdisco Developer Team.
|
This software is copyright (c) 2011-2019 by The Netdisco Developer Team.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ sub display_name {
|
|||||||
|
|
||||||
=head2 cancel
|
=head2 cancel
|
||||||
|
|
||||||
Log a status and prevent other stages from runnning.
|
Log a status and prevent other stages from running.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ __PACKAGE__->load_namespaces(
|
|||||||
);
|
);
|
||||||
|
|
||||||
our # try to hide from kwalitee
|
our # try to hide from kwalitee
|
||||||
$VERSION = 58; # schema version used for upgrades, keep as integer
|
$VERSION = 59; # schema version used for upgrades, keep as integer
|
||||||
|
|
||||||
use Path::Class;
|
use Path::Class;
|
||||||
use File::ShareDir 'dist_dir';
|
use File::ShareDir 'dist_dir';
|
||||||
|
|||||||
@@ -242,6 +242,23 @@ __PACKAGE__->belongs_to( neighbor_alias => 'App::Netdisco::DB::Result::DeviceIp'
|
|||||||
{ join_type => 'LEFT' },
|
{ join_type => 'LEFT' },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
=head2 last_node
|
||||||
|
|
||||||
|
This relationship will return the last node that was seen on the port.
|
||||||
|
|
||||||
|
The JOIN is of type "LEFT" in case there isn't any such node.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->belongs_to(
|
||||||
|
last_node => 'App::Netdisco::DB::Result::Virtual::LastNode', {
|
||||||
|
'foreign.switch' => 'self.ip',
|
||||||
|
'foreign.port' => 'self.port',
|
||||||
|
}, {
|
||||||
|
join_type => 'LEFT',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
=head2 vlans
|
=head2 vlans
|
||||||
|
|
||||||
As compared to C<port_vlans>, this relationship returns a set of Device VLAN
|
As compared to C<port_vlans>, this relationship returns a set of Device VLAN
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ __PACKAGE__->add_columns(
|
|||||||
{ data_type => "boolean", default_value => \"false", is_nullable => 1 },
|
{ data_type => "boolean", default_value => \"false", is_nullable => 1 },
|
||||||
"ldap",
|
"ldap",
|
||||||
{ data_type => "boolean", default_value => \"false", is_nullable => 1 },
|
{ data_type => "boolean", default_value => \"false", is_nullable => 1 },
|
||||||
|
"radius",
|
||||||
|
{ data_type => "boolean", default_value => \"false", is_nullable => 1 },
|
||||||
"admin",
|
"admin",
|
||||||
{ data_type => "boolean", default_value => \"false", is_nullable => 1 },
|
{ data_type => "boolean", default_value => \"false", is_nullable => 1 },
|
||||||
"fullname",
|
"fullname",
|
||||||
|
|||||||
54
lib/App/Netdisco/DB/Result/Virtual/LastNode.pm
Normal file
54
lib/App/Netdisco/DB/Result/Virtual/LastNode.pm
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package App::Netdisco::DB::Result::Virtual::LastNode;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use base 'DBIx::Class::Core';
|
||||||
|
|
||||||
|
__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
|
||||||
|
|
||||||
|
__PACKAGE__->table('last_node');
|
||||||
|
__PACKAGE__->result_source_instance->is_virtual(1);
|
||||||
|
__PACKAGE__->result_source_instance->view_definition(<<ENDSQL
|
||||||
|
SELECT DISTINCT ON (switch, port) * FROM node
|
||||||
|
ORDER BY switch, port, time_last desc
|
||||||
|
ENDSQL
|
||||||
|
);
|
||||||
|
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
"mac",
|
||||||
|
{ data_type => "macaddr", is_nullable => 0 },
|
||||||
|
"switch",
|
||||||
|
{ data_type => "inet", is_nullable => 0 },
|
||||||
|
"port",
|
||||||
|
{ data_type => "text", is_nullable => 0 },
|
||||||
|
"active",
|
||||||
|
{ data_type => "boolean", is_nullable => 1 },
|
||||||
|
"oui",
|
||||||
|
{ data_type => "varchar", is_nullable => 1, size => 8 },
|
||||||
|
"time_first",
|
||||||
|
{
|
||||||
|
data_type => "timestamp",
|
||||||
|
default_value => \"current_timestamp",
|
||||||
|
is_nullable => 1,
|
||||||
|
original => { default_value => \"now()" },
|
||||||
|
},
|
||||||
|
"time_recent",
|
||||||
|
{
|
||||||
|
data_type => "timestamp",
|
||||||
|
default_value => \"current_timestamp",
|
||||||
|
is_nullable => 1,
|
||||||
|
original => { default_value => \"now()" },
|
||||||
|
},
|
||||||
|
"time_last",
|
||||||
|
{
|
||||||
|
data_type => "timestamp",
|
||||||
|
default_value => \"current_timestamp",
|
||||||
|
is_nullable => 1,
|
||||||
|
original => { default_value => \"now()" },
|
||||||
|
},
|
||||||
|
"vlan",
|
||||||
|
{ data_type => "text", is_nullable => 0, default_value => '0' },
|
||||||
|
);
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -7,6 +7,7 @@ use base 'DBIx::Class::Core';
|
|||||||
|
|
||||||
__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
|
__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
|
||||||
|
|
||||||
|
# NOTE this query is in `git grep 'THREE PLACES'`
|
||||||
__PACKAGE__->table('port_utilization');
|
__PACKAGE__->table('port_utilization');
|
||||||
__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
|
||||||
@@ -17,11 +18,23 @@ __PACKAGE__->result_source_instance->view_definition(<<ENDSQL
|
|||||||
ELSE 0 END) as ports_in_use,
|
ELSE 0 END) as ports_in_use,
|
||||||
sum(CASE WHEN (dp.type != 'propVirtual' AND dp.up_admin != 'up') THEN 1
|
sum(CASE WHEN (dp.type != 'propVirtual' AND dp.up_admin != 'up') THEN 1
|
||||||
ELSE 0 END) as ports_shutdown,
|
ELSE 0 END) as ports_shutdown,
|
||||||
sum(CASE WHEN (dp.type != 'propVirtual' AND dp.up_admin = 'up' AND dp.up != 'up'
|
sum(CASE
|
||||||
AND ( age(now(), to_timestamp(extract(epoch from d.last_discover) - (d.uptime - dp.lastchange)/100)) > ?::interval )) THEN 1
|
WHEN ( dp.type != 'propVirtual' AND dp.up_admin = 'up' AND dp.up != 'up'
|
||||||
ELSE 0 END) as ports_free
|
AND (age(now(), to_timestamp(extract(epoch from d.last_discover) - (d.uptime/100))) < ?::interval)
|
||||||
FROM device d LEFT JOIN device_port dp
|
AND (last_node.time_last IS NULL OR (age(now(), last_node.time_last)) > ?::interval) )
|
||||||
|
THEN 1
|
||||||
|
WHEN ( dp.type != 'propVirtual' AND dp.up_admin = 'up' AND dp.up != 'up'
|
||||||
|
AND (age(now(), to_timestamp(extract(epoch from d.last_discover) - (d.uptime - dp.lastchange)/100)) > ?::interval) )
|
||||||
|
THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END) as ports_free
|
||||||
|
FROM device d
|
||||||
|
LEFT JOIN device_port dp
|
||||||
ON d.ip = dp.ip
|
ON d.ip = dp.ip
|
||||||
|
LEFT JOIN
|
||||||
|
( SELECT DISTINCT ON (switch, port) * FROM node
|
||||||
|
ORDER BY switch, port, time_last desc ) AS last_node
|
||||||
|
ON dp.port = last_node.port AND dp.ip = last_node.switch
|
||||||
GROUP BY d.dns, d.ip
|
GROUP BY d.dns, d.ip
|
||||||
ORDER BY d.dns, d.ip
|
ORDER BY d.dns, d.ip
|
||||||
ENDSQL
|
ENDSQL
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ __PACKAGE__->result_source_instance->view_definition(<<ENDSQL
|
|||||||
SELECT username, 'ldap' AS role FROM users
|
SELECT username, 'ldap' AS role FROM users
|
||||||
WHERE ldap
|
WHERE ldap
|
||||||
UNION
|
UNION
|
||||||
|
SELECT username, 'radius' AS role FROM users
|
||||||
|
WHERE radius
|
||||||
|
UNION
|
||||||
SELECT username, 'api' AS role FROM users
|
SELECT username, 'api' AS role FROM users
|
||||||
WHERE token IS NOT NULL AND token_from IS NOT NULL
|
WHERE token IS NOT NULL AND token_from IS NOT NULL
|
||||||
ENDSQL
|
ENDSQL
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ sub get_distinct_col {
|
|||||||
|
|
||||||
Returns a ResultSet for DataTables Server-side processing which populates
|
Returns a ResultSet for DataTables Server-side processing which populates
|
||||||
the displayed table. Evaluates the supplied query parameters for filtering,
|
the displayed table. Evaluates the supplied query parameters for filtering,
|
||||||
paging, and ordering information. Note: query paramters are expected to be
|
paging, and ordering information. Note: query parameters are expected to be
|
||||||
passed as a reference to an expanded hash of hashes.
|
passed as a reference to an expanded hash of hashes.
|
||||||
|
|
||||||
Filtering if present, will generate simple LIKE matching conditions for each
|
Filtering if present, will generate simple LIKE matching conditions for each
|
||||||
@@ -75,7 +75,7 @@ sub get_datatables_data {
|
|||||||
Returns the total records, after filtering (i.e. the total number of
|
Returns the total records, after filtering (i.e. the total number of
|
||||||
records after filtering has been applied - not just the number of records
|
records after filtering has been applied - not just the number of records
|
||||||
being returned for this page of data) for a datatables ResultSet and
|
being returned for this page of data) for a datatables ResultSet and
|
||||||
query parameters. Note: query paramters are expected to be passed as a
|
query parameters. Note: query parameters are expected to be passed as a
|
||||||
reference to an expanded hash of hashes.
|
reference to an expanded hash of hashes.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ __PACKAGE__->load_components(qw/
|
|||||||
|
|
||||||
=head2 skipped( $backend?, $max_deferrals?, $retry_after? )
|
=head2 skipped( $backend?, $max_deferrals?, $retry_after? )
|
||||||
|
|
||||||
Retuns a correlated subquery for the set of C<device_skip> entries that apply
|
Returns a correlated subquery for the set of C<device_skip> entries that apply
|
||||||
to some jobs. They match the device IP, current backend, and job action.
|
to some jobs. They match the device IP, current backend, and job action.
|
||||||
|
|
||||||
Pass the C<backend> FQDN (or the current host will be used as a default), the
|
Pass the C<backend> FQDN (or the current host will be used as a default), the
|
||||||
|
|||||||
@@ -187,11 +187,11 @@ Will match exactly the C<model> field.
|
|||||||
|
|
||||||
=item os
|
=item os
|
||||||
|
|
||||||
Will match exactly the C<os> field, which is the operating sytem.
|
Will match exactly the C<os> field, which is the operating system.
|
||||||
|
|
||||||
=item os_ver
|
=item os_ver
|
||||||
|
|
||||||
Will match exactly the C<os_ver> field, which is the operating sytem software version.
|
Will match exactly the C<os_ver> field, which is the operating system software version.
|
||||||
|
|
||||||
=item vendor
|
=item vendor
|
||||||
|
|
||||||
@@ -226,21 +226,20 @@ sub search_by_field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# For Search on Layers
|
# For Search on Layers
|
||||||
my @layer_search = ( '_', '_', '_', '_', '_', '_', '_' );
|
|
||||||
# @layer_search is computer indexed, left->right
|
|
||||||
my $layers = $p->{layers};
|
my $layers = $p->{layers};
|
||||||
|
my @layer_select = ();
|
||||||
if ( defined $layers && ref $layers ) {
|
if ( defined $layers && ref $layers ) {
|
||||||
foreach my $layer (@$layers) {
|
foreach my $layer (@$layers) {
|
||||||
next unless defined $layer and length($layer);
|
next unless defined $layer and length($layer);
|
||||||
next if ( $layer < 1 || $layer > 7 );
|
next if ( $layer < 1 || $layer > 7 );
|
||||||
$layer_search[ $layer - 1 ] = 1;
|
push @layer_select,
|
||||||
|
\[ 'substring(me.layers,9-?, 1)::int = 1', $layer ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elsif ( defined $layers ) {
|
elsif ( defined $layers ) {
|
||||||
$layer_search[ $layers - 1 ] = 1;
|
push @layer_select,
|
||||||
|
\[ 'substring(me.layers,9-?, 1)::int = 1', $layers ];
|
||||||
}
|
}
|
||||||
# the database field is in order 87654321
|
|
||||||
my $layer_string = join( '', reverse @layer_search );
|
|
||||||
|
|
||||||
return $rs
|
return $rs
|
||||||
->search_rs({}, $attrs)
|
->search_rs({}, $attrs)
|
||||||
@@ -252,8 +251,6 @@ sub search_by_field {
|
|||||||
{ '-ilike' => "\%$p->{location}\%" }) : ()),
|
{ '-ilike' => "\%$p->{location}\%" }) : ()),
|
||||||
($p->{description} ? ('me.description' =>
|
($p->{description} ? ('me.description' =>
|
||||||
{ '-ilike' => "\%$p->{description}\%" }) : ()),
|
{ '-ilike' => "\%$p->{description}\%" }) : ()),
|
||||||
($p->{layers} ? ('me.layers' =>
|
|
||||||
{ '-ilike' => "\%$layer_string" }) : ()),
|
|
||||||
|
|
||||||
($p->{model} ? ('me.model' =>
|
($p->{model} ? ('me.model' =>
|
||||||
{ '-in' => $p->{model} }) : ()),
|
{ '-in' => $p->{model} }) : ()),
|
||||||
@@ -264,6 +261,8 @@ sub search_by_field {
|
|||||||
($p->{vendor} ? ('me.vendor' =>
|
($p->{vendor} ? ('me.vendor' =>
|
||||||
{ '-in' => $p->{vendor} }) : ()),
|
{ '-in' => $p->{vendor} }) : ()),
|
||||||
|
|
||||||
|
($p->{layers} ? (-or => \@layer_select) : ()),
|
||||||
|
|
||||||
($p->{dns} ? (
|
($p->{dns} ? (
|
||||||
-or => [
|
-or => [
|
||||||
'me.dns' => { '-ilike' => "\%$p->{dns}\%" },
|
'me.dns' => { '-ilike' => "\%$p->{dns}\%" },
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ sub with_times {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
=head2 with_free_ports
|
=head2 with_is_free
|
||||||
|
|
||||||
This is a modifier for any C<search()> (including the helpers below) which
|
This is a modifier for any C<search()> (including the helpers below) which
|
||||||
will add the following additional synthesized columns to the result set:
|
will add the following additional synthesized columns to the result set:
|
||||||
@@ -67,12 +67,13 @@ sub with_is_free {
|
|||||||
->search({},
|
->search({},
|
||||||
{
|
{
|
||||||
'+columns' => { is_free =>
|
'+columns' => { is_free =>
|
||||||
\["me.up != 'up' and "
|
# NOTE this query is in `git grep 'THREE PLACES'`
|
||||||
."age(now(), to_timestamp(extract(epoch from device.last_discover) "
|
\["me.up_admin = 'up' AND me.up != 'up' AND me.type != 'propVirtual' AND "
|
||||||
."- (device.uptime - me.lastchange)/100)) "
|
."((age(now(), to_timestamp(extract(epoch from device.last_discover) - (device.uptime/100))) < ?::interval "
|
||||||
."> ?::interval",
|
."AND (last_node.time_last IS NULL OR age(now(), last_node.time_last) > ?::interval)) "
|
||||||
[{} => $interval]] },
|
."OR age(now(), to_timestamp(extract(epoch from device.last_discover) - (device.uptime - me.lastchange)/100)) > ?::interval)",
|
||||||
join => 'device',
|
[{} => $interval],[ {} => $interval],[ {} => $interval]] },
|
||||||
|
join => [qw/device last_node/],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,14 +97,23 @@ sub only_free_ports {
|
|||||||
->search_rs($cond, $attrs)
|
->search_rs($cond, $attrs)
|
||||||
->search(
|
->search(
|
||||||
{
|
{
|
||||||
'me.up' => { '!=' => 'up' },
|
# NOTE this query is in `git grep 'THREE PLACES'`
|
||||||
},{
|
'me.up_admin' => 'up',
|
||||||
where =>
|
'me.up' => { '!=' => 'up' },
|
||||||
\["age(now(), to_timestamp(extract(epoch from device.last_discover) "
|
'me.type' => { '!=' => 'propVirtual' },
|
||||||
."- (device.uptime - me.lastchange)/100)) "
|
-or => [
|
||||||
."> ?::interval",
|
-and => [
|
||||||
|
\["age(now(), to_timestamp(extract(epoch from device.last_discover) - (device.uptime/100))) < ?::interval",
|
||||||
|
[{} => $interval]],
|
||||||
|
-or => [
|
||||||
|
'last_node.time_last' => undef,
|
||||||
|
\["age(now(), last_node.time_last) > ?::interval", [{} => $interval]],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
\["age(now(), to_timestamp(extract(epoch from device.last_discover) - (device.uptime - me.lastchange)/100)) > ?::interval",
|
||||||
[{} => $interval]],
|
[{} => $interval]],
|
||||||
join => 'device' },
|
],
|
||||||
|
},{ join => [qw/device last_node/] },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,19 @@ sub jq_warm_thrusters {
|
|||||||
actionset => $actionset{$_},
|
actionset => $actionset{$_},
|
||||||
}, { key => 'primary' }) for keys %actionset;
|
}, { key => 'primary' }) for keys %actionset;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
# fix up the pseudo devices which need layer 3
|
||||||
|
# TODO remove this after next release
|
||||||
|
schema('netdisco')->txn_do(sub {
|
||||||
|
my @hosts = grep { defined }
|
||||||
|
map { schema('netdisco')->resultset('Device')->search_for_device($_->{only}) }
|
||||||
|
grep { exists $_->{only} and ref '' eq ref $_->{only} }
|
||||||
|
grep { exists $_->{driver} and $_->{driver} eq 'cli' }
|
||||||
|
@{ setting('device_auth') };
|
||||||
|
|
||||||
|
$_->update({ layers => \[q{overlay(layers placing '1' from 6 for 1)}] })
|
||||||
|
for @hosts;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sub jq_getsome {
|
sub jq_getsome {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package App::Netdisco::SSHCollector::Platform::ACE;
|
package App::Netdisco::SSHCollector::Platform::ACE;
|
||||||
|
|
||||||
# vim: set expandtab tabstop=8 softtabstop=4 shiftwidth=4:
|
|
||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
|
||||||
App::Netdisco::SSHCollector::Platform::ACE
|
App::Netdisco::SSHCollector::Platform::ACE
|
||||||
@@ -13,7 +11,7 @@ virtual contexts with individual ARP tables. Contexts are enumerated
|
|||||||
with C<show context>, afterwards the commands C<changeto CONTEXTNAME> and
|
with C<show context>, afterwards the commands C<changeto CONTEXTNAME> and
|
||||||
C<show arp> must be executed for every context.
|
C<show arp> must be executed for every context.
|
||||||
|
|
||||||
The IOS shell does not permit to combine mulitple commands in a single
|
The IOS shell does not permit to combine multiple commands in a single
|
||||||
line, and Net::OpenSSH uses individual connections for individual commands,
|
line, and Net::OpenSSH uses individual connections for individual commands,
|
||||||
so we need to use Expect to execute the changeto and show commands in
|
so we need to use Expect to execute the changeto and show commands in
|
||||||
the same context.
|
the same context.
|
||||||
@@ -36,7 +34,7 @@ use Moo;
|
|||||||
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
||||||
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
||||||
|
|
||||||
Returns a list of hashrefs in the format C<{ mac => MACADDR, ip => IPADDR }>.
|
Returns a list of hashrefs in the format C<{ mac =E<gt> MACADDR, ip =E<gt> IPADDR }>.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ C<enable> status after login:
|
|||||||
To use an C<enable> password separate from the login password, add an
|
To use an C<enable> password separate from the login password, add an
|
||||||
C<enable_password> under C<device_auth> tag in your configuration file:
|
C<enable_password> under C<device_auth> tag in your configuration file:
|
||||||
|
|
||||||
device_auth:
|
device_auth:
|
||||||
- tag: sshasa
|
- tag: sshasa
|
||||||
driver: cli
|
driver: cli
|
||||||
platform: ASA
|
platform: ASA
|
||||||
only: '192.0.2.1'
|
only: '192.0.2.1'
|
||||||
username: oliver
|
username: oliver
|
||||||
password: letmein
|
password: letmein
|
||||||
enable_password: myenablepass
|
enable_password: myenablepass
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ use Moo;
|
|||||||
Retrieve ARP and neighbor entries from device. C<$host> is the hostname or IP
|
Retrieve ARP and neighbor entries from device. C<$host> is the hostname or IP
|
||||||
address of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
address of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
||||||
|
|
||||||
Returns a list of hashrefs in the format C<{ mac => MACADDR, ip => IPADDR }>.
|
Returns a list of hashrefs in the format C<{ mac =E<gt> MACADDR, ip =E<gt> IPADDR }>.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ use Moo;
|
|||||||
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
||||||
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
||||||
|
|
||||||
Returns a list of hashrefs in the format C<{ mac => MACADDR, ip => IPADDR }>.
|
Returns a list of hashrefs in the format C<{ mac =E<gt> MACADDR, ip =E<gt> IPADDR }>.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ This collector uses "C<arp>" as the command for the arp utility on your
|
|||||||
system. Clish "C<show arp>" does not work correctly in versions prior to R77.30.
|
system. Clish "C<show arp>" does not work correctly in versions prior to R77.30.
|
||||||
Config example:
|
Config example:
|
||||||
|
|
||||||
device_auth:
|
device_auth:
|
||||||
- tag: sshcpvsx
|
- tag: sshcpvsx
|
||||||
driver: cli
|
driver: cli
|
||||||
platform: CPVSX
|
platform: CPVSX
|
||||||
only: '192.0.2.1'
|
only: '192.0.2.1'
|
||||||
username: oliver
|
username: oliver
|
||||||
password: letmein
|
password: letmein
|
||||||
expert_password: letmein2
|
expert_password: letmein2
|
||||||
|
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ This collector uses "C<arp>" as the command for the arp utility on your
|
|||||||
system. If you wish to specify an absolute path, then add an C<arp_command>
|
system. If you wish to specify an absolute path, then add an C<arp_command>
|
||||||
item to your configuration:
|
item to your configuration:
|
||||||
|
|
||||||
device_auth:
|
device_auth:
|
||||||
- tag: sshfreebsd
|
- tag: sshfreebsd
|
||||||
driver: cli
|
driver: cli
|
||||||
platform: FreeBSD
|
platform: FreeBSD
|
||||||
only: '192.0.2.1'
|
only: '192.0.2.1'
|
||||||
username: oliver
|
username: oliver
|
||||||
password: letmein
|
password: letmein
|
||||||
arp_command: '/usr/sbin/arp'
|
arp_command: '/usr/sbin/arp'
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ use Moo;
|
|||||||
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
||||||
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
||||||
|
|
||||||
Returns a list of hashrefs in the format C<{ mac => MACADDR, ip => IPADDR }>.
|
Returns a list of hashrefs in the format C<{ mac =E<gt> MACADDR, ip =E<gt> IPADDR }>.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|||||||
@@ -7,21 +7,21 @@ App::Netdisco::SSHCollector::Platform::GAIAEmbedded
|
|||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
Collect ARP entries from Checkpoint GAIA embedded Systems
|
Collect ARP entries from Checkpoint GAIA embedded Systems
|
||||||
To get this Plugin to work you have to add an User like 'netdisco' with
|
To get this Plugin to work you have to add a user like 'netdisco' with
|
||||||
'Network admin' right in the GAIA embedded OS
|
'Network admin' rights in the GAIA embedded OS.
|
||||||
|
|
||||||
This collector uses "C<arp>" as the command for the arp utility on your
|
This collector uses "C<arp>" as the command for the arp utility on your
|
||||||
system. If you wish to specify an absolute path, then add an C<arp_command>
|
system. If you wish to specify an absolute path, then add an C<arp_command>
|
||||||
item to your configuration:
|
item to your configuration:
|
||||||
|
|
||||||
device_auth:
|
device_auth:
|
||||||
- tag: sshgaia
|
- tag: sshgaia
|
||||||
driver: cli
|
driver: cli
|
||||||
platform: GAIAEmbedded
|
platform: GAIAEmbedded
|
||||||
only: '192.0.2.1'
|
only: '192.0.2.1'
|
||||||
username: oliver
|
username: oliver
|
||||||
password: letmein
|
password: letmein
|
||||||
arp_command: 'arp'
|
arp_command: 'arp'
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ use Moo;
|
|||||||
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
||||||
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
||||||
|
|
||||||
Returns a list of hashrefs in the format C<{ mac => MACADDR, ip => IPADDR }>.
|
Returns a list of hashrefs in the format C<{ mac =E<gt> MACADDR, ip =E<gt> IPADDR }>.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use Moo;
|
|||||||
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
||||||
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
||||||
|
|
||||||
Returns a list of hashrefs in the format C<{ mac => MACADDR, ip => IPADDR }>.
|
Returns a list of hashrefs in the format C<{ mac =E<gt> MACADDR, ip =E<gt> IPADDR }>.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use Moo;
|
|||||||
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
||||||
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
||||||
|
|
||||||
Returns a list of hashrefs in the format C<{ mac => MACADDR, ip => IPADDR }>.
|
Returns a list of hashrefs in the format C<{ mac =E<gt> MACADDR, ip =E<gt> IPADDR }>.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ This collector uses "C<arp>" as the command for the arp utility on your
|
|||||||
system. If you wish to specify an absolute path, then add an C<arp_command>
|
system. If you wish to specify an absolute path, then add an C<arp_command>
|
||||||
item to your configuration:
|
item to your configuration:
|
||||||
|
|
||||||
device_auth:
|
device_auth:
|
||||||
- tag: sshlinux
|
- tag: sshlinux
|
||||||
driver: cli
|
driver: cli
|
||||||
platform: Linux
|
platform: Linux
|
||||||
only: '192.0.2.1'
|
only: '192.0.2.1'
|
||||||
username: oliver
|
username: oliver
|
||||||
password: letmein
|
password: letmein
|
||||||
arp_command: '/usr/sbin/arp'
|
arp_command: '/usr/sbin/arp'
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ use Moo;
|
|||||||
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
Retrieve ARP entries from device. C<$host> is the hostname or IP address
|
||||||
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
of the device. C<$ssh> is a Net::OpenSSH connection to the device.
|
||||||
|
|
||||||
Returns a list of hashrefs in the format C<{ mac => MACADDR, ip => IPADDR }>.
|
Returns a list of hashrefs in the format C<{ mac =E<gt> MACADDR, ip =E<gt> IPADDR }>.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|||||||
@@ -58,8 +58,11 @@ Returns C<undef> if the connection fails.
|
|||||||
sub reader_for {
|
sub reader_for {
|
||||||
my ($class, $ip, $useclass) = @_;
|
my ($class, $ip, $useclass) = @_;
|
||||||
my $device = get_device($ip) or return undef;
|
my $device = get_device($ip) or return undef;
|
||||||
|
return undef if $device->in_storage and $device->is_pseudo;
|
||||||
|
|
||||||
my $readers = $class->instance->readers or return undef;
|
my $readers = $class->instance->readers or return undef;
|
||||||
return $readers->{$device->ip} if exists $readers->{$device->ip};
|
return $readers->{$device->ip} if exists $readers->{$device->ip};
|
||||||
|
|
||||||
debug sprintf 'snmp reader cache warm: [%s]', $device->ip;
|
debug sprintf 'snmp reader cache warm: [%s]', $device->ip;
|
||||||
return ($readers->{$device->ip}
|
return ($readers->{$device->ip}
|
||||||
= _snmp_connect_generic('read', $device, $useclass));
|
= _snmp_connect_generic('read', $device, $useclass));
|
||||||
@@ -104,8 +107,11 @@ Returns C<undef> if the connection fails.
|
|||||||
sub writer_for {
|
sub writer_for {
|
||||||
my ($class, $ip, $useclass) = @_;
|
my ($class, $ip, $useclass) = @_;
|
||||||
my $device = get_device($ip) or return undef;
|
my $device = get_device($ip) or return undef;
|
||||||
|
return undef if $device->in_storage and $device->is_pseudo;
|
||||||
|
|
||||||
my $writers = $class->instance->writers or return undef;
|
my $writers = $class->instance->writers or return undef;
|
||||||
return $writers->{$device->ip} if exists $writers->{$device->ip};
|
return $writers->{$device->ip} if exists $writers->{$device->ip};
|
||||||
|
|
||||||
debug sprintf 'snmp writer cache warm: [%s]', $device->ip;
|
debug sprintf 'snmp writer cache warm: [%s]', $device->ip;
|
||||||
return ($writers->{$device->ip}
|
return ($writers->{$device->ip}
|
||||||
= _snmp_connect_generic('write', $device, $useclass));
|
= _snmp_connect_generic('write', $device, $useclass));
|
||||||
|
|||||||
@@ -158,6 +158,8 @@ If C<$device_type> is also given, then C<discover_no_type> will be checked.
|
|||||||
Also respects C<discover_phones> and C<discover_waps> if either are set to
|
Also respects C<discover_phones> and C<discover_waps> if either are set to
|
||||||
false.
|
false.
|
||||||
|
|
||||||
|
Also checks if the device is a pseudo device (vendor is C<netdisco>).
|
||||||
|
|
||||||
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
|
||||||
@@ -168,6 +170,9 @@ sub is_discoverable {
|
|||||||
$remote_type ||= '';
|
$remote_type ||= '';
|
||||||
$remote_cap ||= [];
|
$remote_cap ||= [];
|
||||||
|
|
||||||
|
return _bail_msg("is_discoverable: $device is pseudo-device")
|
||||||
|
if $device->is_pseudo;
|
||||||
|
|
||||||
return _bail_msg("is_discoverable: $device matches wap_platforms but discover_waps is not enabled")
|
return _bail_msg("is_discoverable: $device matches wap_platforms but discover_waps is not enabled")
|
||||||
if ((not setting('discover_waps')) and
|
if ((not setting('discover_waps')) and
|
||||||
(match_to_setting($remote_type, 'wap_platforms') or
|
(match_to_setting($remote_type, 'wap_platforms') or
|
||||||
@@ -192,9 +197,8 @@ sub is_discoverable {
|
|||||||
|
|
||||||
=head2 is_discoverable_now( $ip, $device_type? )
|
=head2 is_discoverable_now( $ip, $device_type? )
|
||||||
|
|
||||||
Same as C<is_discoverable>, but also checks the last_discover field if the
|
Same as C<is_discoverable>, but also compares the C<last_discover> field
|
||||||
device is in storage, and returns false if that host has been too recently
|
of the C<device> to the C<discover_min_age> configuration.
|
||||||
discovered.
|
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
@@ -222,6 +226,8 @@ the local configuration to arpnip the device.
|
|||||||
The configuration items C<arpnip_no> and C<arpnip_only> are checked
|
The configuration items C<arpnip_no> and C<arpnip_only> are checked
|
||||||
against the given IP.
|
against the given IP.
|
||||||
|
|
||||||
|
Also checks if the device reports layer 3 capability.
|
||||||
|
|
||||||
Returns false if the host is not permitted to arpnip the target device.
|
Returns false if the host is not permitted to arpnip the target device.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
@@ -230,6 +236,9 @@ sub is_arpnipable {
|
|||||||
my $ip = shift;
|
my $ip = shift;
|
||||||
my $device = get_device($ip) or return 0;
|
my $device = get_device($ip) or return 0;
|
||||||
|
|
||||||
|
return _bail_msg("is_arpnipable: $device has no layer 3 capability")
|
||||||
|
unless $device->has_layer(3);
|
||||||
|
|
||||||
return _bail_msg("is_arpnipable: $device matched arpnip_no")
|
return _bail_msg("is_arpnipable: $device matched arpnip_no")
|
||||||
if check_acl_no($device, 'arpnip_no');
|
if check_acl_no($device, 'arpnip_no');
|
||||||
|
|
||||||
@@ -241,9 +250,8 @@ sub is_arpnipable {
|
|||||||
|
|
||||||
=head2 is_arpnipable_now( $ip )
|
=head2 is_arpnipable_now( $ip )
|
||||||
|
|
||||||
Same as C<is_arpnipable>, but also checks the last_arpnip field if the
|
Same as C<is_arpnipable>, but also compares the C<last_arpnip> field
|
||||||
device is in storage, and returns false if that host has been too recently
|
of the C<device> to the C<arpnip_min_age> configuration.
|
||||||
arpnipped.
|
|
||||||
|
|
||||||
Returns false if the host is not permitted to arpnip the target device.
|
Returns false if the host is not permitted to arpnip the target device.
|
||||||
|
|
||||||
@@ -271,6 +279,8 @@ the local configuration to macsuck the device.
|
|||||||
The configuration items C<macsuck_no> and C<macsuck_only> are checked
|
The configuration items C<macsuck_no> and C<macsuck_only> are checked
|
||||||
against the given IP.
|
against the given IP.
|
||||||
|
|
||||||
|
Also checks if the device reports layer 2 capability.
|
||||||
|
|
||||||
Returns false if the host is not permitted to macsuck the target device.
|
Returns false if the host is not permitted to macsuck the target device.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
@@ -279,6 +289,9 @@ sub is_macsuckable {
|
|||||||
my $ip = shift;
|
my $ip = shift;
|
||||||
my $device = get_device($ip) or return 0;
|
my $device = get_device($ip) or return 0;
|
||||||
|
|
||||||
|
return _bail_msg("is_macsuckable: $device has no layer 2 capability")
|
||||||
|
unless $device->has_layer(2);
|
||||||
|
|
||||||
return _bail_msg("is_macsuckable: $device matched macsuck_no")
|
return _bail_msg("is_macsuckable: $device matched macsuck_no")
|
||||||
if check_acl_no($device, 'macsuck_no');
|
if check_acl_no($device, 'macsuck_no');
|
||||||
|
|
||||||
@@ -290,9 +303,8 @@ sub is_macsuckable {
|
|||||||
|
|
||||||
=head2 is_macsuckable_now( $ip )
|
=head2 is_macsuckable_now( $ip )
|
||||||
|
|
||||||
Same as C<is_macsuckable>, but also checks the last_macsuck field if the
|
Same as C<is_macsuckable>, but also compares the C<last_macsuck> field
|
||||||
device is in storage, and returns false if that host has been too recently
|
of the C<device> to the C<macsuck_min_age> configuration.
|
||||||
macsucked.
|
|
||||||
|
|
||||||
Returns false if the host is not permitted to macsuck the target device.
|
Returns false if the host is not permitted to macsuck the target device.
|
||||||
|
|
||||||
|
|||||||
@@ -59,13 +59,20 @@ ajax qr{/ajax/control/admin/(?:\w+/)?delete} => require_role setting('defanged_a
|
|||||||
get '/admin/*' => require_role admin => sub {
|
get '/admin/*' => require_role admin => sub {
|
||||||
my ($tag) = splat;
|
my ($tag) = splat;
|
||||||
|
|
||||||
# trick the ajax into working as if this were a tabbed page
|
if (exists setting('_admin_tasks')->{ $tag }) {
|
||||||
params->{tab} = $tag;
|
# trick the ajax into working as if this were a tabbed page
|
||||||
|
params->{tab} = $tag;
|
||||||
|
|
||||||
var(nav => 'admin');
|
var(nav => 'admin');
|
||||||
template 'admintask', {
|
template 'admintask', {
|
||||||
task => setting('_admin_tasks')->{ $tag },
|
task => setting('_admin_tasks')->{ $tag },
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var('notfound' => true);
|
||||||
|
status 'not_found';
|
||||||
|
template 'index';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
true;
|
true;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use Dancer::Plugin::DBIC;
|
|||||||
use Dancer::Plugin::Passphrase;
|
use Dancer::Plugin::Passphrase;
|
||||||
use Digest::MD5;
|
use Digest::MD5;
|
||||||
use Net::LDAP;
|
use Net::LDAP;
|
||||||
|
use Authen::Radius;
|
||||||
use Try::Tiny;
|
use Try::Tiny;
|
||||||
|
|
||||||
sub authenticate_user {
|
sub authenticate_user {
|
||||||
@@ -103,9 +104,20 @@ sub match_password {
|
|||||||
my $settings = $self->realm_settings;
|
my $settings = $self->realm_settings;
|
||||||
my $username_column = $settings->{users_username_column} || 'username';
|
my $username_column = $settings->{users_username_column} || 'username';
|
||||||
|
|
||||||
return $user->ldap
|
my $pwmatch_result = 0;
|
||||||
? $self->match_with_ldap($password, $user->$username_column)
|
my $username = $user->$username_column;
|
||||||
: $self->match_with_local_pass($password, $user);
|
|
||||||
|
if ($user->ldap) {
|
||||||
|
$pwmatch_result = $self->match_with_ldap($password, $username);
|
||||||
|
}
|
||||||
|
elsif ($user->radius) {
|
||||||
|
$pwmatch_result = $self->match_with_radius($password, $username);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$pwmatch_result = $self->match_with_local_pass($password, $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pwmatch_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub match_with_local_pass {
|
sub match_with_local_pass {
|
||||||
@@ -215,4 +227,28 @@ sub _ldap_search {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub match_with_radius {
|
||||||
|
my($self, $pass, $user) = @_;
|
||||||
|
return unless setting('radius') and ref {} eq ref setting('radius');
|
||||||
|
|
||||||
|
my $conf = setting('radius');
|
||||||
|
my $radius = Authen::Radius->new(Host => $conf->{server}, Secret => $conf->{secret});
|
||||||
|
# my $dict_dir = Path::Class::Dir->new( dist_dir('App-Netdisco') )
|
||||||
|
# ->subdir('radius_dictionaries')->stringify;
|
||||||
|
Authen::Radius->load_dictionary(); # put $dict_dir in here once it's useful
|
||||||
|
|
||||||
|
$radius->add_attributes(
|
||||||
|
{ Name => 'User-Name', Value => $user },
|
||||||
|
{ Name => 'User-Password', Value => $pass },
|
||||||
|
{ Name => 'h323-return-code', Value => '0' }, # Cisco AV pair
|
||||||
|
{ Name => 'Digest-Attributes', Value => { Method => 'REGISTER' } }
|
||||||
|
);
|
||||||
|
$radius->send_packet(ACCESS_REQUEST);
|
||||||
|
|
||||||
|
my $type = $radius->recv_packet();
|
||||||
|
my $radius_return = ($type eq ACCESS_ACCEPT) ? 1 : 0;
|
||||||
|
|
||||||
|
return $radius_return;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ ajax '/ajax/control/admin/pseudodevice/add' => require_role admin => sub {
|
|||||||
ip => param('ip'),
|
ip => param('ip'),
|
||||||
dns => param('dns'),
|
dns => param('dns'),
|
||||||
vendor => 'netdisco',
|
vendor => 'netdisco',
|
||||||
layers => '00000100',
|
layers => param('layers'),
|
||||||
last_discover => \'now()',
|
last_discover => \'now()',
|
||||||
});
|
});
|
||||||
return unless $device;
|
return unless $device;
|
||||||
@@ -87,6 +87,9 @@ ajax '/ajax/control/admin/pseudodevice/update' => require_role admin => sub {
|
|||||||
})->delete;
|
})->delete;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# also set layers
|
||||||
|
$device->update({layers => param('layers')});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ ajax '/ajax/control/admin/users/add' => require_role setting('defanged_admin') =
|
|||||||
password => _make_password(param('password')),
|
password => _make_password(param('password')),
|
||||||
fullname => param('fullname'),
|
fullname => param('fullname'),
|
||||||
ldap => (param('ldap') ? \'true' : \'false'),
|
ldap => (param('ldap') ? \'true' : \'false'),
|
||||||
|
radius => (param('radius') ? \'true' : \'false'),
|
||||||
port_control => (param('port_control') ? \'true' : \'false'),
|
port_control => (param('port_control') ? \'true' : \'false'),
|
||||||
admin => (param('admin') ? \'true' : \'false'),
|
admin => (param('admin') ? \'true' : \'false'),
|
||||||
note => param('note'),
|
note => param('note'),
|
||||||
@@ -71,6 +72,7 @@ ajax '/ajax/control/admin/users/update' => require_role setting('defanged_admin'
|
|||||||
: ()),
|
: ()),
|
||||||
fullname => param('fullname'),
|
fullname => param('fullname'),
|
||||||
ldap => (param('ldap') ? \'true' : \'false'),
|
ldap => (param('ldap') ? \'true' : \'false'),
|
||||||
|
radius => (param('radius') ? \'true' : \'false'),
|
||||||
port_control => (param('port_control') ? \'true' : \'false'),
|
port_control => (param('port_control') ? \'true' : \'false'),
|
||||||
admin => (param('admin') ? \'true' : \'false'),
|
admin => (param('admin') ? \'true' : \'false'),
|
||||||
note => param('note'),
|
note => param('note'),
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ get '/ajax/content/device/ports' => require_login sub {
|
|||||||
# change wildcard chars to SQL
|
# change wildcard chars to SQL
|
||||||
$f =~ s/\*/%/g;
|
$f =~ s/\*/%/g;
|
||||||
$f =~ s/\?/_/g;
|
$f =~ s/\?/_/g;
|
||||||
# set wilcards at param boundaries
|
# set wildcards at param boundaries
|
||||||
if ($f !~ m/[%_]/) {
|
if ($f !~ m/[%_]/) {
|
||||||
$f =~ s/^\%*/%/;
|
$f =~ s/^\%*/%/;
|
||||||
$f =~ s/\%*$/%/;
|
$f =~ s/\%*$/%/;
|
||||||
@@ -82,6 +82,8 @@ get '/ajax/content/device/ports' => require_login sub {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
delete $port_state{free};
|
delete $port_state{free};
|
||||||
|
# showing free ports requires showing down ports
|
||||||
|
++$port_state{down};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scalar keys %port_state < 3) {
|
if (scalar keys %port_state < 3) {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ get '/ajax/content/report/nodevendor/data' => require_login sub {
|
|||||||
my $match = $vendor eq 'blank' ? undef : $vendor;
|
my $match = $vendor eq 'blank' ? undef : $vendor;
|
||||||
|
|
||||||
$rs = $rs->search( { 'oui.abbrev' => $match },
|
$rs = $rs->search( { 'oui.abbrev' => $match },
|
||||||
{ '+columns' => [qw/ device.dns device.name oui.abbrev /],
|
{ '+columns' => [qw/ device.dns device.name oui.abbrev oui.company /],
|
||||||
join => [qw/ oui device /],
|
join => [qw/ oui device /],
|
||||||
collapse => 1,
|
collapse => 1,
|
||||||
});
|
});
|
||||||
@@ -86,7 +86,7 @@ get '/ajax/content/report/nodevendor' => require_login sub {
|
|||||||
my $match = $vendor eq 'blank' ? undef : $vendor;
|
my $match = $vendor eq 'blank' ? undef : $vendor;
|
||||||
|
|
||||||
$rs = $rs->search( { 'oui.abbrev' => $match },
|
$rs = $rs->search( { 'oui.abbrev' => $match },
|
||||||
{ '+columns' => [qw/ device.dns device.name oui.abbrev /],
|
{ '+columns' => [qw/ device.dns device.name oui.abbrev oui.company /],
|
||||||
join => [qw/ oui device /],
|
join => [qw/ oui device /],
|
||||||
collapse => 1,
|
collapse => 1,
|
||||||
});
|
});
|
||||||
@@ -102,9 +102,9 @@ get '/ajax/content/report/nodevendor' => require_login sub {
|
|||||||
$rs = $rs->search(
|
$rs = $rs->search(
|
||||||
{ },
|
{ },
|
||||||
{ join => 'oui',
|
{ join => 'oui',
|
||||||
select => [ 'oui.abbrev', { count => {distinct => 'me.mac'}} ],
|
select => [ 'oui.abbrev', 'oui.company', { count => {distinct => 'me.mac'}} ],
|
||||||
as => [qw/ vendor count /],
|
as => [qw/ abbrev vendor count /],
|
||||||
group_by => [qw/ oui.abbrev /]
|
group_by => [qw/ oui.abbrev oui.company /]
|
||||||
}
|
}
|
||||||
)->order_by( { -desc => 'count' } );
|
)->order_by( { -desc => 'count' } );
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ get '/ajax/content/report/portutilization' => require_login sub {
|
|||||||
my $age_num = param('age_num') || 3;
|
my $age_num = param('age_num') || 3;
|
||||||
my $age_unit = param('age_unit') || 'months';
|
my $age_unit = param('age_unit') || 'months';
|
||||||
my @results = schema('netdisco')->resultset('Virtual::PortUtilization')
|
my @results = schema('netdisco')->resultset('Virtual::PortUtilization')
|
||||||
->search(undef, { bind => [ "$age_num $age_unit" ] })->hri->all;
|
->search(undef, { bind => [ "$age_num $age_unit", "$age_num $age_unit", "$age_num $age_unit" ] })->hri->all;
|
||||||
|
|
||||||
if (request->is_ajax) {
|
if (request->is_ajax) {
|
||||||
my $json = to_json (\@results);
|
my $json = to_json (\@results);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use Dancer::Plugin::DBIC;
|
|||||||
use Dancer::Plugin::Auth::Extensible;
|
use Dancer::Plugin::Auth::Extensible;
|
||||||
|
|
||||||
use NetAddr::IP::Lite ':lower';
|
use NetAddr::IP::Lite ':lower';
|
||||||
|
use Regexp::Common 'net';
|
||||||
use NetAddr::MAC ();
|
use NetAddr::MAC ();
|
||||||
|
|
||||||
use App::Netdisco::Web::Plugin;
|
use App::Netdisco::Web::Plugin;
|
||||||
@@ -23,10 +24,14 @@ ajax '/ajax/content/search/node' => require_login sub {
|
|||||||
my ( $start, $end ) = param('daterange') =~ m/(\d+-\d+-\d+)/gmx;
|
my ( $start, $end ) = param('daterange') =~ m/(\d+-\d+-\d+)/gmx;
|
||||||
|
|
||||||
my $mac = NetAddr::MAC->new(mac => $node);
|
my $mac = NetAddr::MAC->new(mac => $node);
|
||||||
undef $mac if ($mac and $mac->as_ieee and ($mac->as_ieee eq '00:00:00:00'));
|
undef $mac if
|
||||||
my @active = (param('archived') ? () : (-bool => 'active'));
|
($mac and $mac->as_ieee
|
||||||
|
and (($mac->as_ieee eq '00:00:00:00:00:00')
|
||||||
|
or ($mac->as_ieee !~ m/$RE{net}{MAC}/)));
|
||||||
|
|
||||||
|
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';
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use Dancer::Plugin::DBIC;
|
|||||||
use Dancer::Plugin::Auth::Extensible;
|
use Dancer::Plugin::Auth::Extensible;
|
||||||
|
|
||||||
use App::Netdisco::Util::Web 'sql_match';
|
use App::Netdisco::Util::Web 'sql_match';
|
||||||
|
use Regexp::Common 'net';
|
||||||
use NetAddr::MAC ();
|
use NetAddr::MAC ();
|
||||||
|
|
||||||
hook 'before_template' => sub {
|
hook 'before_template' => sub {
|
||||||
@@ -39,7 +40,11 @@ get '/search' => require_login sub {
|
|||||||
my $nd = $s->resultset('Device')->search_fuzzy($q);
|
my $nd = $s->resultset('Device')->search_fuzzy($q);
|
||||||
my ($likeval, $likeclause) = sql_match($q);
|
my ($likeval, $likeclause) = sql_match($q);
|
||||||
my $mac = NetAddr::MAC->new($q);
|
my $mac = NetAddr::MAC->new($q);
|
||||||
undef $mac if ($mac and $mac->as_ieee and ($mac->as_ieee eq '00:00:00:00'));
|
|
||||||
|
undef $mac if
|
||||||
|
($mac and $mac->as_ieee
|
||||||
|
and (($mac->as_ieee eq '00:00:00:00:00:00')
|
||||||
|
or ($mac->as_ieee !~ m/$RE{net}{MAC}/)));
|
||||||
|
|
||||||
if ($nd and $nd->count) {
|
if ($nd and $nd->count) {
|
||||||
if ($nd->count == 1) {
|
if ($nd->count == 1) {
|
||||||
|
|||||||
@@ -16,9 +16,6 @@ register_worker({ phase => 'check' }, sub {
|
|||||||
return Status->error("arpnip skipped: $device not yet discovered")
|
return Status->error("arpnip skipped: $device not yet discovered")
|
||||||
unless $device->in_storage;
|
unless $device->in_storage;
|
||||||
|
|
||||||
return Status->info("arpnip skipped: $device has no layer 3 capability")
|
|
||||||
unless $device->has_layer(3);
|
|
||||||
|
|
||||||
return Status->info("arpnip skipped: $device is not arpnipable")
|
return Status->info("arpnip skipped: $device is not arpnipable")
|
||||||
unless is_arpnipable_now($device);
|
unless is_arpnipable_now($device);
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
push @{ vars->{'v6arps'} },
|
push @{ vars->{'v6arps'} },
|
||||||
@{get_arps_snmp($device, $snmp->ipv6_n2p_mac, $snmp->ipv6_n2p_addr) };
|
@{get_arps_snmp($device, $snmp->ipv6_n2p_mac, $snmp->ipv6_n2p_addr) };
|
||||||
|
|
||||||
|
$device->update({layers => \[q{overlay(layers placing '1' from 6 for 1)}]});
|
||||||
return Status->done("Gathered arp caches from $device");
|
return Status->done("Gathered arp caches from $device");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,24 +83,25 @@ sub get_arps_snmp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
register_worker({ phase => 'main', driver => 'cli' }, sub {
|
register_worker({ phase => 'main', driver => 'cli' }, sub {
|
||||||
my ($job, $workerconf) = @_;
|
my ($job, $workerconf) = @_;
|
||||||
|
|
||||||
my $device = $job->device;
|
my $device = $job->device;
|
||||||
my $cli = App::Netdisco::Transport::SSH->session_for($device)
|
my $cli = App::Netdisco::Transport::SSH->session_for($device)
|
||||||
or return Status->defer("arpnip failed: could not SSH connect to $device");
|
or return Status->defer("arpnip failed: could not SSH connect to $device");
|
||||||
|
|
||||||
# should be both v4 and v6
|
# should be both v4 and v6
|
||||||
my @arps = @{ get_arps_cli($device, [$cli->arpnip]) };
|
my @arps = @{ get_arps_cli($device, [$cli->arpnip]) };
|
||||||
|
|
||||||
# cache v4 arp table
|
# cache v4 arp table
|
||||||
push @{ vars->{'v4arps'} },
|
push @{ vars->{'v4arps'} },
|
||||||
grep { NetAddr::IP::Lite->new($_->{ip})->bits == 32 } @arps;
|
grep { NetAddr::IP::Lite->new($_->{ip})->bits == 32 } @arps;
|
||||||
|
|
||||||
# cache v6 neighbor cache
|
# cache v6 neighbor cache
|
||||||
push @{ vars->{'v6arps'} },
|
push @{ vars->{'v6arps'} },
|
||||||
grep { NetAddr::IP::Lite->new($_->{ip})->bits == 128 } @arps;
|
grep { NetAddr::IP::Lite->new($_->{ip})->bits == 128 } @arps;
|
||||||
|
|
||||||
return Status->done("Gathered arp caches from $device");
|
$device->update({layers => \[q{overlay(layers placing '1' from 6 for 1)}]});
|
||||||
|
return Status->done("Gathered arp caches from $device");
|
||||||
});
|
});
|
||||||
|
|
||||||
sub get_arps_cli {
|
sub get_arps_cli {
|
||||||
|
|||||||
@@ -16,9 +16,6 @@ register_worker({ phase => 'check' }, sub {
|
|||||||
return Status->error("discover failed: no device param (need -d ?)")
|
return Status->error("discover failed: no device param (need -d ?)")
|
||||||
if $device->ip eq '0.0.0.0';
|
if $device->ip eq '0.0.0.0';
|
||||||
|
|
||||||
return Status->info("discover skipped: $device is pseudo-device")
|
|
||||||
if $device->is_pseudo;
|
|
||||||
|
|
||||||
# runner has already called get_device to promote $job->device
|
# runner has already called get_device to promote $job->device
|
||||||
return $job->cancel("fresh discover cancelled: $device already known")
|
return $job->cancel("fresh discover cancelled: $device already known")
|
||||||
if $device->in_storage
|
if $device->in_storage
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ port relationships.
|
|||||||
The Device database object can be a fresh L<DBIx::Class::Row> object which is
|
The Device database object can be a fresh L<DBIx::Class::Row> object which is
|
||||||
not yet stored to the database.
|
not yet stored to the database.
|
||||||
|
|
||||||
A list of discovererd neighbors will be returned as [C<$ip>, C<$type>] tuples.
|
A list of discovered neighbors will be returned as [C<$ip>, C<$type>] tuples.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,6 @@ register_worker({ phase => 'check' }, sub {
|
|||||||
return Status->error("macsuck skipped: $device not yet discovered")
|
return Status->error("macsuck skipped: $device not yet discovered")
|
||||||
unless $device->in_storage;
|
unless $device->in_storage;
|
||||||
|
|
||||||
return Status->info("macsuck skipped: $device is pseudo-device")
|
|
||||||
if $device->is_pseudo;
|
|
||||||
|
|
||||||
return Status->info("macsuck skipped: $device has no layer 2 capability")
|
|
||||||
unless $device->has_layer(2);
|
|
||||||
|
|
||||||
return Status->info("macsuck skipped: $device is not macsuckable")
|
return Status->info("macsuck skipped: $device is not macsuckable")
|
||||||
unless is_macsuckable_now($device);
|
unless is_macsuckable_now($device);
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
debug sprintf ' [%s] macsuck - %s updated forwarding table entries',
|
debug sprintf ' [%s] macsuck - %s updated forwarding table entries',
|
||||||
$device->ip, $total_nodes;
|
$device->ip, $total_nodes;
|
||||||
|
|
||||||
# a use for $now ... need to archive dissapeared nodes
|
# a use for $now ... need to archive disappeared nodes
|
||||||
my $archived = 0;
|
my $archived = 0;
|
||||||
|
|
||||||
if (setting('node_freshness')) {
|
if (setting('node_freshness')) {
|
||||||
@@ -105,7 +105,7 @@ All four fields in the tuple are required. If you don't know the VLAN ID,
|
|||||||
Netdisco supports using ID "0".
|
Netdisco supports using ID "0".
|
||||||
|
|
||||||
Optionally, a fifth argument can be the literal string passed to the time_last
|
Optionally, a fifth argument can be the literal string passed to the time_last
|
||||||
field of the database record. If not provided, it defauls to C<now()>.
|
field of the database record. If not provided, it defaults to C<now()>.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ email config and creating the repository with C<rancid-cvs>.
|
|||||||
=head2 C<rancid_conf>
|
=head2 C<rancid_conf>
|
||||||
|
|
||||||
The location where the rancid configuration (F<rancid.types.base> and
|
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
|
F<rancid.types.conf>) is installed. It will be used to check the existence
|
||||||
of device types before exporting the devices to the rancid configuration. If no match
|
of device types before exporting the devices to the rancid configuration. If no match
|
||||||
is found the device will not be added to rancid.
|
is found the device will not be added to rancid.
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ database:
|
|||||||
# RECOMMENDED SETTINGS
|
# RECOMMENDED SETTINGS
|
||||||
# --------------------
|
# --------------------
|
||||||
|
|
||||||
# SNMP community string(s)
|
# Device authentication settings
|
||||||
# ````````````````````````
|
# define snmp communities and ssh credentials here
|
||||||
|
# ````````````````````````````````````````````````
|
||||||
device_auth:
|
device_auth:
|
||||||
- tag: 'default_v2_readonly'
|
- tag: 'default_v2_readonly'
|
||||||
community: 'public'
|
community: 'public'
|
||||||
@@ -50,7 +51,7 @@ device_auth:
|
|||||||
# SNMP, which just clogs up the job queue.
|
# SNMP, which just clogs up the job queue.
|
||||||
# ```````````````````````````````````````````````````````````````
|
# ```````````````````````````````````````````````````````````````
|
||||||
#discover_waps: true
|
#discover_waps: true
|
||||||
#disover_phones: false
|
#discover_phones: false
|
||||||
|
|
||||||
# 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.
|
||||||
|
|||||||
@@ -245,6 +245,13 @@ td > form.nd_inline-form {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* badge for pseudo devices layer three toggle */
|
||||||
|
.nd_layer-three-link {
|
||||||
|
text-decoration: none !important;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
/* for the job control admin page play/pause links */
|
/* for the job control admin page play/pause links */
|
||||||
#nd_countdown-refresh:hover, #nd_countdown-control:hover {
|
#nd_countdown-refresh:hover, #nd_countdown-control:hover {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
@@ -359,7 +366,7 @@ td > form.nd_inline-form {
|
|||||||
.container-fluid > .nd_sidebar {
|
.container-fluid > .nd_sidebar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
width: 200px;
|
width: 205px;
|
||||||
left: auto;
|
left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
0
share/radius_dictionaries/TODO
Normal file
0
share/radius_dictionaries/TODO
Normal file
11
share/schema_versions/App-Netdisco-DB-58-59-PostgreSQL.sql
Normal file
11
share/schema_versions/App-Netdisco-DB-58-59-PostgreSQL.sql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE users ADD COLUMN "radius" boolean DEFAULT false;
|
||||||
|
|
||||||
|
UPDATE device SET layers = NULL WHERE vendor = 'netdisco';
|
||||||
|
|
||||||
|
UPDATE device SET layers = '00000000' WHERE layers IS NULL;
|
||||||
|
|
||||||
|
ALTER TABLE device ALTER layers SET DEFAULT '00000000';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
<th class="nd_center-cell">Device Name</th>
|
<th class="nd_center-cell">Device Name</th>
|
||||||
<th class="nd_center-cell">Device IP</th>
|
<th class="nd_center-cell">Device IP</th>
|
||||||
<th class="nd_center-cell">Number of Ports</th>
|
<th class="nd_center-cell">Number of Ports</th>
|
||||||
|
<th class="nd_center-cell">Services</th>
|
||||||
<th class="nd_center-cell">Action</th>
|
<th class="nd_center-cell">Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -11,7 +12,12 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="nd_center-cell"><input data-form="add" name="dns" type="text"></td>
|
<td class="nd_center-cell"><input data-form="add" name="dns" type="text"></td>
|
||||||
<td class="nd_center-cell"><input data-form="add" name="ip" type="text"></td>
|
<td class="nd_center-cell"><input data-form="add" name="ip" type="text"></td>
|
||||||
<td class="nd_center-cell"><input data-form="add" name="ports" type="number"></td>
|
<td class="nd_center-cell"><input data-form="add" name="ports" type="number" value="1"></td>
|
||||||
|
<td class="nd_center-cell">
|
||||||
|
<span class="badge"> </span><span class="badge"> </span>
|
||||||
|
<a class="nd_layer-three-link" href="#" rel="tooltip" data-placement="bottom" data-offset="3" data-title="Enable Arpnip"><span class="badge">3</span></a><span class="badge"> </span><span class="badge"> </span><span class="badge"> </span><span class="badge"> </span>
|
||||||
|
<input data-form="add" name="layers" type="hidden" value="00000000">
|
||||||
|
</td>
|
||||||
<td class="nd_center-cell">
|
<td class="nd_center-cell">
|
||||||
<button class="btn btn-small nd_adminbutton" name="add" type="submit"><i class="icon-plus-sign"></i> Add</button>
|
<button class="btn btn-small nd_adminbutton" name="add" type="submit"><i class="icon-plus-sign"></i> Add</button>
|
||||||
</td>
|
</td>
|
||||||
@@ -26,6 +32,11 @@
|
|||||||
<td class="nd_center-cell">
|
<td class="nd_center-cell">
|
||||||
<input data-form="update" name="ports" type="number" value="[% row.port_count | html_entity %]">
|
<input data-form="update" name="ports" type="number" value="[% row.port_count | html_entity %]">
|
||||||
</td>
|
</td>
|
||||||
|
<td class="nd_center-cell">
|
||||||
|
<span class="badge"> </span><span class="badge"> </span>
|
||||||
|
<a class="nd_layer-three-link" href="#" rel="tooltip" data-placement="bottom" data-offset="3" data-title="Enable Arpnip"><span class="badge[% ' badge-success' IF row.layers.substr(5,1) %]">3</span></a><span class="badge"> </span><span class="badge"> </span><span class="badge"> </span><span class="badge"> </span>
|
||||||
|
<input data-form="update" name="layers" type="hidden" value="[% row.layers | html_entity %]">
|
||||||
|
</td>
|
||||||
<td class="nd_center-cell">
|
<td class="nd_center-cell">
|
||||||
<input data-form="update" name="dns" type="hidden" value="[% row.dns | html_entity %]">
|
<input data-form="update" name="dns" type="hidden" value="[% row.dns | html_entity %]">
|
||||||
<input data-form="update" name="ip" type="hidden" value="[% row.ip | html_entity %]">
|
<input data-form="update" name="ip" type="hidden" value="[% row.ip | html_entity %]">
|
||||||
@@ -68,6 +79,17 @@ $(document).ready(function() {
|
|||||||
} ],
|
} ],
|
||||||
[% INCLUDE 'ajax/datatabledefaults.tt' -%]
|
[% INCLUDE 'ajax/datatabledefaults.tt' -%]
|
||||||
} );
|
} );
|
||||||
|
$('.nd_layer-three-link').click(function() {
|
||||||
|
var badge = $(this).children('span').first();
|
||||||
|
var layers = $(this).parent().children('input').first();
|
||||||
|
$(badge).toggleClass('badge-success');
|
||||||
|
if ($(badge).hasClass('badge-success')) {
|
||||||
|
$(layers).attr('value', '00000100');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$(layers).attr('value', '00000000');
|
||||||
|
}
|
||||||
|
});
|
||||||
} );
|
} );
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<th class="nd_center-cell">Username</th>
|
<th class="nd_center-cell">Username</th>
|
||||||
<th class="nd_center-cell">Password</th>
|
<th class="nd_center-cell">Password</th>
|
||||||
<th class="nd_center-cell">LDAP Auth</th>
|
<th class="nd_center-cell">LDAP Auth</th>
|
||||||
|
<th class="nd_center-cell">RADIUS Auth</th>
|
||||||
<th class="nd_center-cell">Port Control</th>
|
<th class="nd_center-cell">Port Control</th>
|
||||||
<th class="nd_center-cell">Administrator</th>
|
<th class="nd_center-cell">Administrator</th>
|
||||||
<th class="nd_center-cell">Created</th>
|
<th class="nd_center-cell">Created</th>
|
||||||
@@ -16,15 +17,16 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="nd_center-cell"><input data-form="add" name="fullname" type="text"></td>
|
<td class="nd_center-cell"><input data-form="add" name="fullname" type="text"></td>
|
||||||
<td class="nd_center-cell"><input data-form="add" name="username" type="text"></td>
|
<td class="nd_center-cell"><input class="span2" data-form="add" name="username" type="text"></td>
|
||||||
<td class="nd_center-cell"><input data-form="add" name="password" type="password"></td>
|
<td class="nd_center-cell"><input class="span2" data-form="add" name="password" type="password"></td>
|
||||||
<td class="nd_center-cell"><input data-form="add" type="checkbox" name="ldap"></td>
|
<td class="nd_center-cell"><input data-form="add" type="checkbox" name="ldap"></td>
|
||||||
|
<td class="nd_center-cell"><input data-form="add" type="checkbox" name="radius"></td>
|
||||||
<td class="nd_center-cell"><input data-form="add" type="checkbox" name="port_control"></td>
|
<td class="nd_center-cell"><input data-form="add" type="checkbox" name="port_control"></td>
|
||||||
<td class="nd_center-cell"><input data-form="add" type="checkbox" name="admin"></td>
|
<td class="nd_center-cell"><input data-form="add" type="checkbox" name="admin"></td>
|
||||||
<td class="nd_center-cell"></td>
|
<td class="nd_center-cell"></td>
|
||||||
<td class="nd_center-cell"></td>
|
<td class="nd_center-cell"></td>
|
||||||
<td class="nd_center-cell"><input data-form="add" name="note" type="text"></td>
|
<td class="nd_center-cell"><input class="span2" data-form="add" name="note" type="text"></td>
|
||||||
<td class="nd_center-cell">
|
<td nowrap class="nd_center-cell">
|
||||||
<button class="btn btn-small nd_adminbutton" name="add" type="submit"><i class="icon-plus-sign"></i> Add</button>
|
<button class="btn btn-small nd_adminbutton" name="add" type="submit"><i class="icon-plus-sign"></i> Add</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -37,14 +39,17 @@
|
|||||||
<input data-form="update" name="fullname" type="text" value="[% row.fullname | html_entity %]">
|
<input data-form="update" name="fullname" type="text" value="[% row.fullname | html_entity %]">
|
||||||
</td>
|
</td>
|
||||||
<td class="nd_center-cell">
|
<td class="nd_center-cell">
|
||||||
<input data-form="update" name="username" type="text" value="[% row.username | html_entity %]">
|
<input class="span2" data-form="update" name="username" type="text" value="[% row.username | html_entity %]">
|
||||||
</td>
|
</td>
|
||||||
<td class="nd_center-cell">
|
<td class="nd_center-cell">
|
||||||
<input data-form="update" name="password" type="password" value="********">
|
<input class="span2" data-form="update" name="password" type="password" value="********">
|
||||||
</td>
|
</td>
|
||||||
<td class="nd_center-cell">
|
<td class="nd_center-cell">
|
||||||
<input data-form="update" name="ldap" type="checkbox" [% ' checked="checked"' IF row.ldap %]>
|
<input data-form="update" name="ldap" type="checkbox" [% ' checked="checked"' IF row.ldap %]>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="nd_center-cell">
|
||||||
|
<input data-form="update" name="radius" type="checkbox" [% ' checked="checked"' IF row.radius %]>
|
||||||
|
</td>
|
||||||
<td class="nd_center-cell">
|
<td class="nd_center-cell">
|
||||||
<input data-form="update" name="port_control" type="checkbox" [% ' checked="checked"' IF row.port_control %]>
|
<input data-form="update" name="port_control" type="checkbox" [% ' checked="checked"' IF row.port_control %]>
|
||||||
</td>
|
</td>
|
||||||
@@ -54,10 +59,10 @@
|
|||||||
<td class="nd_center-cell">[% row.created | html_entity %]</td>
|
<td class="nd_center-cell">[% row.created | html_entity %]</td>
|
||||||
<td class="nd_center-cell">[% row.last_seen | html_entity %]</td>
|
<td class="nd_center-cell">[% row.last_seen | html_entity %]</td>
|
||||||
<td class="nd_center-cell">
|
<td class="nd_center-cell">
|
||||||
<input data-form="update" name="note" type="text" value="[% row.note | html_entity %]">
|
<input class="span2" data-form="update" name="note" type="text" value="[% row.note | html_entity %]">
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="nd_center-cell">
|
<td nowrap class="nd_center-cell">
|
||||||
<button class="btn nd_adminbutton" name="update" type="submit"><i class="icon-save text-warning"></i></button>
|
<button class="btn nd_adminbutton" name="update" type="submit"><i class="icon-save text-warning"></i></button>
|
||||||
|
|
||||||
<button class="btn" data-toggle="modal"
|
<button class="btn" data-toggle="modal"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[% USE CSV -%]
|
[% USE CSV -%]
|
||||||
[% CSV.dump([ 'Full Name' 'Username'
|
[% CSV.dump([ 'Full Name' 'Username'
|
||||||
'LDAP Auth' 'Port Control' 'Administrator' 'Created'
|
'LDAP Auth' 'RADIUS Auth' 'Port Control' 'Administrator' 'Created'
|
||||||
'Last Login' 'Note']) %]
|
'Last Login' 'Note']) %]
|
||||||
|
|
||||||
[% FOREACH row IN results %]
|
[% FOREACH row IN results %]
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
[% mylist.push(row.fullname) %]
|
[% mylist.push(row.fullname) %]
|
||||||
[% mylist.push(row.username) %]
|
[% mylist.push(row.username) %]
|
||||||
[% mylist.push(row.ldap) %]
|
[% mylist.push(row.ldap) %]
|
||||||
|
[% mylist.push(row.radius) %]
|
||||||
[% mylist.push(row.port_control) %]
|
[% mylist.push(row.port_control) %]
|
||||||
[% mylist.push(row.admin) %]
|
[% mylist.push(row.admin) %]
|
||||||
[% mylist.push(row.created) %]
|
[% mylist.push(row.created) %]
|
||||||
|
|||||||
@@ -37,9 +37,13 @@
|
|||||||
[% ELSIF row.error_disable_cause %]
|
[% ELSIF row.error_disable_cause %]
|
||||||
<i class="icon-exclamation-sign text-error icon-large"></i>
|
<i class="icon-exclamation-sign text-error icon-large"></i>
|
||||||
[% ELSIF row.has_column_loaded('is_free') AND row.is_free %]
|
[% ELSIF row.has_column_loaded('is_free') AND row.is_free %]
|
||||||
<i class="icon-arrow-down text-success icon-large"></i>
|
<i class="icon-circle-arrow-down text-success icon-large"></i>
|
||||||
[% ELSIF row.up_admin == 'up' AND (row.up != 'up' AND row.up != 'dormant') %]
|
[% ELSIF row.up_admin == 'up' AND (row.up != 'up' AND row.up != 'dormant') %]
|
||||||
<i class="icon-arrow-down text-error icon-large"></i>
|
[% IF params.port_state == 'free' %]
|
||||||
|
<i class="icon-circle-arrow-down text-success icon-large"></i>
|
||||||
|
[% ELSE %]
|
||||||
|
<i class="icon-arrow-down text-error icon-large"></i>
|
||||||
|
[% END %]
|
||||||
[% ELSE %]
|
[% ELSE %]
|
||||||
<i class="icon-angle-up text-success icon-large"></i>
|
<i class="icon-angle-up text-success icon-large"></i>
|
||||||
[% END %]
|
[% END %]
|
||||||
@@ -244,7 +248,7 @@
|
|||||||
<i class="icon-off nd_power-on"></i>
|
<i class="icon-off nd_power-on"></i>
|
||||||
[% END %]
|
[% END %]
|
||||||
<span>
|
<span>
|
||||||
[% IF row.power.power > 0 %]
|
[% IF row.power.power AND row.power.power > 0 %]
|
||||||
[% row.power.power | html_entity %] mW
|
[% row.power.power | html_entity %] mW
|
||||||
[% ELSE %]
|
[% ELSE %]
|
||||||
([% row.power.status | html_entity %])
|
([% row.power.status | html_entity %])
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ $(document).ready(function() {
|
|||||||
}, {
|
}, {
|
||||||
"data": 'oui.abbrev',
|
"data": 'oui.abbrev',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return '<a href="[% uri_for('/report/nodevendor') %]?vendor=' + encodeURIComponent(data || 'blank') + '">' + he.encode(data ||'(Unknown Vendor)') + '</a>';
|
return '<a href="[% uri_for('/report/nodevendor') %]?vendor=' + encodeURIComponent(row.oui.abbrev || 'blank') + '">' + he.encode(row.oui.company ||'(Unknown Vendor)') + '</a>';
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"data": 'port',
|
"data": 'port',
|
||||||
@@ -71,7 +71,7 @@ $(document).ready(function() {
|
|||||||
{
|
{
|
||||||
"data": 'vendor',
|
"data": 'vendor',
|
||||||
"render": function(data, type, row, meta) {
|
"render": function(data, type, row, meta) {
|
||||||
return '<a href="[% uri_for('/report/nodevendor') %]?vendor=' + encodeURIComponent(data || 'blank') + '">' + he.encode(data ||'(Unknown Vendor)') + '</a>';
|
return '<a href="[% uri_for('/report/nodevendor') %]?vendor=' + encodeURIComponent(row.abbrev || 'blank') + '">' + he.encode(row.vendor ||'(Unknown Vendor)') + '</a>';
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"data": 'count',
|
"data": 'count',
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
[% USE CSV -%]
|
[% USE CSV -%]
|
||||||
[% IF opt %]
|
[% IF opt %]
|
||||||
[% CSV.dump(['MAC' 'Vendor' 'Company' 'Device' 'Port']) %]
|
[% CSV.dump(['MAC' 'Company' 'Device' 'Port']) %]
|
||||||
|
|
||||||
[% FOREACH row IN results %]
|
[% FOREACH row IN results %]
|
||||||
[% mylist = [] %]
|
[% mylist = [] %]
|
||||||
[% device = row.device.dns || row.device.name || row.switch %]
|
[% device = row.device.dns || row.device.name || row.switch %]
|
||||||
[% FOREACH col IN [ row.mac.upper row.oui.abbrev row.oui.company device row.port ] %]
|
[% FOREACH col IN [ row.mac.upper row.oui.company device row.port ] %]
|
||||||
[% mylist.push(col) %]
|
[% mylist.push(col) %]
|
||||||
[% END %]
|
[% END %]
|
||||||
[% CSV.dump(mylist) %]
|
[% CSV.dump(mylist) %]
|
||||||
|
|||||||
@@ -71,8 +71,9 @@
|
|||||||
,minLength: 0
|
,minLength: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
// activate modals
|
// activate modals and tooltips
|
||||||
$('.nd_modal').modal({show: false});
|
$('.nd_modal').modal({show: false});
|
||||||
|
$("[rel=tooltip]").tooltip({live: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
// on load, establish global delegations for now and future
|
// on load, establish global delegations for now and future
|
||||||
|
|||||||
@@ -181,7 +181,7 @@
|
|||||||
[% session.logged_in_fullname || session.logged_in_user | html_entity %] <b class="caret"></b>
|
[% session.logged_in_fullname || session.logged_in_user | html_entity %] <b class="caret"></b>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
[% IF NOT user_has_role('ldap') %]
|
[% IF NOT ( user_has_role('ldap') OR user_has_role('radius') ) %]
|
||||||
<li><a href="[% uri_for('/password') %]">Change Password</a></li>
|
<li><a href="[% uri_for('/password') %]">Change Password</a></li>
|
||||||
[% END %]
|
[% END %]
|
||||||
[% IF NOT settings.no_auth %]
|
[% IF NOT settings.no_auth %]
|
||||||
|
|||||||
@@ -34,10 +34,12 @@
|
|||||||
<ul class="icons-ul"><!-- nd_inputs-list unstyled"> -->
|
<ul class="icons-ul"><!-- nd_inputs-list unstyled"> -->
|
||||||
<li><i class="icon-li icon-angle-up text-success"></i> Link Up</li>
|
<li><i class="icon-li icon-angle-up text-success"></i> Link Up</li>
|
||||||
<li><i class="icon-li icon-arrow-down text-error"></i> Link Down</li>
|
<li><i class="icon-li icon-arrow-down text-error"></i> Link Down</li>
|
||||||
<li><i class="icon-li icon-arrow-down text-success"></i> Port Free</li>
|
<li><i class="icon-li icon-circle-arrow-down text-success"></i> Port Free</li>
|
||||||
<li><i class="icon-li icon-remove"></i> Admin Disabled</li>
|
<li><i class="icon-li icon-remove"></i> Admin Disabled</li>
|
||||||
<li><i class="icon-li icon-exclamation-sign text-error"></i> Error Disabled</li>
|
<li><i class="icon-li icon-exclamation-sign text-error"></i> Error Disabled</li>
|
||||||
<li><i class="icon-li icon-ban-circle text-info"></i> Blocking</li>
|
<li><i class="icon-li icon-ban-circle text-info"></i> Blocking</li>
|
||||||
|
<li><i class="icon-li icon-off"></i> PoE Disabled</li>
|
||||||
|
<li><i class="icon-li icon-off nd_power-on"></i> PoE Enabled</li>
|
||||||
<li><i class="icon-li icon-link text-warning"></i> Manual Topology</li>
|
<li><i class="icon-li icon-link text-warning"></i> Manual Topology</li>
|
||||||
<li><i class="icon-li icon-link"></i> Neighbor Device</li>
|
<li><i class="icon-li icon-link"></i> Neighbor Device</li>
|
||||||
<li><i class="icon-li icon-unlink text-error"></i> Neighbor Inacessible</li>
|
<li><i class="icon-li icon-unlink text-error"></i> Neighbor Inacessible</li>
|
||||||
|
|||||||
8
xt/01-local-pod.t
Normal file
8
xt/01-local-pod.t
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Test::More;
|
||||||
|
use Test::Pod;
|
||||||
|
|
||||||
|
all_pod_files_ok();
|
||||||
Reference in New Issue
Block a user