Feature to gather SNMP Walk, use as Pseudo Device, and Browse Objects
* fix anomalous name * add gather worker * fix encoding of binary storage * store results back to job * now parsing mbis report to translate * fix the broken report parser * rename gather to snapshot * implement walk code copied from SNMP::Info * can now bulkwalk and parse mibs report and store resolved walk in cache * add func/glob aliasing broken * better aliasing * implement aliasing from globals and funcs * fix regexp for matching netdisco-mibs report * fake cache entry for all ND2 methods called, add comments * also save to logs/snapshots/IP * add doc for netdisco-do * add is_pseudo column to device table * support for loading cache for pseudo devices * check for hrSystemUptime as well as sysUpTime for snmp connect * display pseudo devices with yellow pill for name * color all cells for layers for pseudo * no need to b64 encode binary data in scalars as we b64 whole thing after * tweaked uptime check * store snapshot to database instead of Job * expose snapshots in device details tab * small ux improvements on snap download * fixes for errors in subnet mask searching * hide snapshot management for pseudo devices * update to use new netdisco-mibs object cache * update for new format oids file * start of work on loading walk into db for browsing * store values and meta * add auto increment col and oid index to browser * start web plugin for browser * add virtual search for oid children * have all oid in separte table (60 seconds load on my laptop) * rename table and add relation * store oid as int array * fix sql for children * make jstree start working * working very slow tree expand * fix to work when first displaying tree * store both oid and oid_parts * simplify SQL to speed up (more complicated perl) * fix sql bug, add better index, prettify tree * render the snmp node detail * add node template, make scrollable, pretty print data values (insecure) * store munge hint * some dubious code to munge the data * make sure to filter by IP on device_browser * make safer the rendering of value data (but need to come back to key ordering) * fix sorting on object values * limit the opening of child nodes to keep response good and unclutter * factor out the munge and make safer * reject unknown mungers * show the munger and option (not working) to change * additional js for munge select * complete custom munge * change so that saving to database is only at CLI and on request * hide snmp tab if no browser rows in the db * add helpful message when no browser rows for the device * stub handler for search and add recurse control * working search * minor ui fixes * implement typeahead for leaf search * limit rows in typeahead * make sure device_browser is visited in delete and renumber * add requirements for this branch * update manifest * make sure node search and typeahead are restricted to current device only
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
share/public/javascripts/*.map binary
|
share/public/javascripts/*.map binary
|
||||||
share/public/javascripts/*.min.js binary
|
share/public/javascripts/*.min.js binary
|
||||||
share/public/javascripts/jquery-history.js binary
|
share/public/javascripts/jquery-history.js binary
|
||||||
|
share/public/css/smoothness/jquery-ui.custom.min.css binary
|
||||||
|
share/public/javascripts/jstree/jstree.min.js binary
|
||||||
|
share/public/css/toastr.css binary
|
||||||
share/public/css/*.min.css binary
|
share/public/css/*.min.css binary
|
||||||
share/public/swagger-ui/* binary
|
share/public/swagger-ui/* binary
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ Module::Build->new(
|
|||||||
'Dancer::Plugin::Swagger' => '0',
|
'Dancer::Plugin::Swagger' => '0',
|
||||||
'Dancer::Session::Cookie' => '0.27',
|
'Dancer::Session::Cookie' => '0.27',
|
||||||
'Expect' => '0',
|
'Expect' => '0',
|
||||||
|
'File::Path' => '0',
|
||||||
|
'File::Spec::Functions' => '0',
|
||||||
'File::ShareDir' => '1.03',
|
'File::ShareDir' => '1.03',
|
||||||
'File::Slurper' => '0.009',
|
'File::Slurper' => '0.009',
|
||||||
'Guard' => '1.022',
|
'Guard' => '1.022',
|
||||||
@@ -51,6 +53,7 @@ Module::Build->new(
|
|||||||
'IO::Socket::INET6' => '2.72',
|
'IO::Socket::INET6' => '2.72',
|
||||||
'IO::Socket::SSL' => '2.048',
|
'IO::Socket::SSL' => '2.048',
|
||||||
'JSON' => '2.90',
|
'JSON' => '2.90',
|
||||||
|
'JSON::PP' => '0',
|
||||||
'JSON::XS' => '3.01',
|
'JSON::XS' => '3.01',
|
||||||
'List::Util' => '1.49',
|
'List::Util' => '1.49',
|
||||||
'List::MoreUtils' => '0.428',
|
'List::MoreUtils' => '0.428',
|
||||||
@@ -86,6 +89,7 @@ Module::Build->new(
|
|||||||
'SNMP::Info' => '3.81',
|
'SNMP::Info' => '3.81',
|
||||||
'SQL::Abstract' => '1.85',
|
'SQL::Abstract' => '1.85',
|
||||||
'SQL::Translator' => '0.11024',
|
'SQL::Translator' => '0.11024',
|
||||||
|
'Sub::Util' => '1.40',
|
||||||
'Template' => '2.24',
|
'Template' => '2.24',
|
||||||
'Template::AutoFilter' => '0',
|
'Template::AutoFilter' => '0',
|
||||||
'Template::Plugin::CSV' => '0.04',
|
'Template::Plugin::CSV' => '0.04',
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ lib/App/Netdisco/DB/Result.pm
|
|||||||
lib/App/Netdisco/DB/Result/Admin.pm
|
lib/App/Netdisco/DB/Result/Admin.pm
|
||||||
lib/App/Netdisco/DB/Result/Community.pm
|
lib/App/Netdisco/DB/Result/Community.pm
|
||||||
lib/App/Netdisco/DB/Result/Device.pm
|
lib/App/Netdisco/DB/Result/Device.pm
|
||||||
|
lib/App/Netdisco/DB/Result/DeviceBrowser.pm
|
||||||
lib/App/Netdisco/DB/Result/DeviceIp.pm
|
lib/App/Netdisco/DB/Result/DeviceIp.pm
|
||||||
lib/App/Netdisco/DB/Result/DeviceModule.pm
|
lib/App/Netdisco/DB/Result/DeviceModule.pm
|
||||||
lib/App/Netdisco/DB/Result/DevicePort.pm
|
lib/App/Netdisco/DB/Result/DevicePort.pm
|
||||||
@@ -37,6 +38,7 @@ lib/App/Netdisco/DB/Result/DevicePortVlan.pm
|
|||||||
lib/App/Netdisco/DB/Result/DevicePortWireless.pm
|
lib/App/Netdisco/DB/Result/DevicePortWireless.pm
|
||||||
lib/App/Netdisco/DB/Result/DevicePower.pm
|
lib/App/Netdisco/DB/Result/DevicePower.pm
|
||||||
lib/App/Netdisco/DB/Result/DeviceSkip.pm
|
lib/App/Netdisco/DB/Result/DeviceSkip.pm
|
||||||
|
lib/App/Netdisco/DB/Result/DeviceSnapshot.pm
|
||||||
lib/App/Netdisco/DB/Result/DeviceVlan.pm
|
lib/App/Netdisco/DB/Result/DeviceVlan.pm
|
||||||
lib/App/Netdisco/DB/Result/Log.pm
|
lib/App/Netdisco/DB/Result/Log.pm
|
||||||
lib/App/Netdisco/DB/Result/NetmapPositions.pm
|
lib/App/Netdisco/DB/Result/NetmapPositions.pm
|
||||||
@@ -48,6 +50,7 @@ lib/App/Netdisco/DB/Result/NodeWireless.pm
|
|||||||
lib/App/Netdisco/DB/Result/Oui.pm
|
lib/App/Netdisco/DB/Result/Oui.pm
|
||||||
lib/App/Netdisco/DB/Result/Process.pm
|
lib/App/Netdisco/DB/Result/Process.pm
|
||||||
lib/App/Netdisco/DB/Result/Session.pm
|
lib/App/Netdisco/DB/Result/Session.pm
|
||||||
|
lib/App/Netdisco/DB/Result/SNMPObject.pm
|
||||||
lib/App/Netdisco/DB/Result/Statistics.pm
|
lib/App/Netdisco/DB/Result/Statistics.pm
|
||||||
lib/App/Netdisco/DB/Result/Subnet.pm
|
lib/App/Netdisco/DB/Result/Subnet.pm
|
||||||
lib/App/Netdisco/DB/Result/Topology.pm
|
lib/App/Netdisco/DB/Result/Topology.pm
|
||||||
@@ -62,6 +65,7 @@ lib/App/Netdisco/DB/Result/Virtual/DeviceLinks.pm
|
|||||||
lib/App/Netdisco/DB/Result/Virtual/DevicePoeStatus.pm
|
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/FilteredSNMPObject.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/LastNode.pm
|
||||||
lib/App/Netdisco/DB/Result/Virtual/NodeIp4.pm
|
lib/App/Netdisco/DB/Result/Virtual/NodeIp4.pm
|
||||||
@@ -69,6 +73,7 @@ lib/App/Netdisco/DB/Result/Virtual/NodeIp6.pm
|
|||||||
lib/App/Netdisco/DB/Result/Virtual/NodeMonitor.pm
|
lib/App/Netdisco/DB/Result/Virtual/NodeMonitor.pm
|
||||||
lib/App/Netdisco/DB/Result/Virtual/NodesDiscovered.pm
|
lib/App/Netdisco/DB/Result/Virtual/NodesDiscovered.pm
|
||||||
lib/App/Netdisco/DB/Result/Virtual/NodeWithAge.pm
|
lib/App/Netdisco/DB/Result/Virtual/NodeWithAge.pm
|
||||||
|
lib/App/Netdisco/DB/Result/Virtual/OidChildren.pm
|
||||||
lib/App/Netdisco/DB/Result/Virtual/OrphanedDevices.pm
|
lib/App/Netdisco/DB/Result/Virtual/OrphanedDevices.pm
|
||||||
lib/App/Netdisco/DB/Result/Virtual/PollerPerformance.pm
|
lib/App/Netdisco/DB/Result/Virtual/PollerPerformance.pm
|
||||||
lib/App/Netdisco/DB/Result/Virtual/PortMacs.pm
|
lib/App/Netdisco/DB/Result/Virtual/PortMacs.pm
|
||||||
@@ -83,6 +88,7 @@ lib/App/Netdisco/DB/Result/Virtual/UserRole.pm
|
|||||||
lib/App/Netdisco/DB/ResultSet.pm
|
lib/App/Netdisco/DB/ResultSet.pm
|
||||||
lib/App/Netdisco/DB/ResultSet/Admin.pm
|
lib/App/Netdisco/DB/ResultSet/Admin.pm
|
||||||
lib/App/Netdisco/DB/ResultSet/Device.pm
|
lib/App/Netdisco/DB/ResultSet/Device.pm
|
||||||
|
lib/App/Netdisco/DB/ResultSet/DeviceBrowser.pm
|
||||||
lib/App/Netdisco/DB/ResultSet/DeviceModule.pm
|
lib/App/Netdisco/DB/ResultSet/DeviceModule.pm
|
||||||
lib/App/Netdisco/DB/ResultSet/DevicePort.pm
|
lib/App/Netdisco/DB/ResultSet/DevicePort.pm
|
||||||
lib/App/Netdisco/DB/ResultSet/DevicePortLog.pm
|
lib/App/Netdisco/DB/ResultSet/DevicePortLog.pm
|
||||||
@@ -159,6 +165,7 @@ lib/App/Netdisco/Web/Plugin/Device/Details.pm
|
|||||||
lib/App/Netdisco/Web/Plugin/Device/Modules.pm
|
lib/App/Netdisco/Web/Plugin/Device/Modules.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm
|
lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Device/Ports.pm
|
lib/App/Netdisco/Web/Plugin/Device/Ports.pm
|
||||||
|
lib/App/Netdisco/Web/Plugin/Device/SNMP.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Device/Vlans.pm
|
lib/App/Netdisco/Web/Plugin/Device/Vlans.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Inventory.pm
|
lib/App/Netdisco/Web/Plugin/Inventory.pm
|
||||||
lib/App/Netdisco/Web/Plugin/Report/ApChannelDist.pm
|
lib/App/Netdisco/Web/Plugin/Report/ApChannelDist.pm
|
||||||
@@ -228,6 +235,7 @@ lib/App/Netdisco/Worker/Plugin/Graph.pm
|
|||||||
lib/App/Netdisco/Worker/Plugin/Hook.pm
|
lib/App/Netdisco/Worker/Plugin/Hook.pm
|
||||||
lib/App/Netdisco/Worker/Plugin/Hook/Exec.pm
|
lib/App/Netdisco/Worker/Plugin/Hook/Exec.pm
|
||||||
lib/App/Netdisco/Worker/Plugin/Hook/HTTP.pm
|
lib/App/Netdisco/Worker/Plugin/Hook/HTTP.pm
|
||||||
|
lib/App/Netdisco/Worker/Plugin/LoadMIBs.pm
|
||||||
lib/App/Netdisco/Worker/Plugin/Location.pm
|
lib/App/Netdisco/Worker/Plugin/Location.pm
|
||||||
lib/App/Netdisco/Worker/Plugin/Macsuck.pm
|
lib/App/Netdisco/Worker/Plugin/Macsuck.pm
|
||||||
lib/App/Netdisco/Worker/Plugin/Macsuck/Hooks.pm
|
lib/App/Netdisco/Worker/Plugin/Macsuck/Hooks.pm
|
||||||
@@ -245,6 +253,7 @@ lib/App/Netdisco/Worker/Plugin/Power.pm
|
|||||||
lib/App/Netdisco/Worker/Plugin/Psql.pm
|
lib/App/Netdisco/Worker/Plugin/Psql.pm
|
||||||
lib/App/Netdisco/Worker/Plugin/Renumber.pm
|
lib/App/Netdisco/Worker/Plugin/Renumber.pm
|
||||||
lib/App/Netdisco/Worker/Plugin/Show.pm
|
lib/App/Netdisco/Worker/Plugin/Show.pm
|
||||||
|
lib/App/Netdisco/Worker/Plugin/Snapshot.pm
|
||||||
lib/App/Netdisco/Worker/Plugin/Stats.pm
|
lib/App/Netdisco/Worker/Plugin/Stats.pm
|
||||||
lib/App/Netdisco/Worker/Plugin/Vlan.pm
|
lib/App/Netdisco/Worker/Plugin/Vlan.pm
|
||||||
lib/App/Netdisco/Worker/Plugin/Vlan/Core.pm
|
lib/App/Netdisco/Worker/Plugin/Vlan/Core.pm
|
||||||
@@ -343,6 +352,24 @@ share/public/javascripts/jquery.cookie.js
|
|||||||
share/public/javascripts/jquery.dataTables.min.js
|
share/public/javascripts/jquery.dataTables.min.js
|
||||||
share/public/javascripts/jquery.floatThead.js
|
share/public/javascripts/jquery.floatThead.js
|
||||||
share/public/javascripts/jquery.qtip.min.js
|
share/public/javascripts/jquery.qtip.min.js
|
||||||
|
share/public/javascripts/jstree/jstree.min.js
|
||||||
|
share/public/javascripts/jstree/themes/proton/30px.png
|
||||||
|
share/public/javascripts/jstree/themes/proton/32px.png
|
||||||
|
share/public/javascripts/jstree/themes/proton/fonts/titillium/titilliumweb-bold-webfont.eot
|
||||||
|
share/public/javascripts/jstree/themes/proton/fonts/titillium/titilliumweb-bold-webfont.svg
|
||||||
|
share/public/javascripts/jstree/themes/proton/fonts/titillium/titilliumweb-bold-webfont.ttf
|
||||||
|
share/public/javascripts/jstree/themes/proton/fonts/titillium/titilliumweb-bold-webfont.woff
|
||||||
|
share/public/javascripts/jstree/themes/proton/fonts/titillium/titilliumweb-extralight-webfont.eot
|
||||||
|
share/public/javascripts/jstree/themes/proton/fonts/titillium/titilliumweb-extralight-webfont.svg
|
||||||
|
share/public/javascripts/jstree/themes/proton/fonts/titillium/titilliumweb-extralight-webfont.ttf
|
||||||
|
share/public/javascripts/jstree/themes/proton/fonts/titillium/titilliumweb-extralight-webfont.woff
|
||||||
|
share/public/javascripts/jstree/themes/proton/fonts/titillium/titilliumweb-regular-webfont.eot
|
||||||
|
share/public/javascripts/jstree/themes/proton/fonts/titillium/titilliumweb-regular-webfont.svg
|
||||||
|
share/public/javascripts/jstree/themes/proton/fonts/titillium/titilliumweb-regular-webfont.ttf
|
||||||
|
share/public/javascripts/jstree/themes/proton/fonts/titillium/titilliumweb-regular-webfont.woff
|
||||||
|
share/public/javascripts/jstree/themes/proton/style.css
|
||||||
|
share/public/javascripts/jstree/themes/proton/style.min.css
|
||||||
|
share/public/javascripts/jstree/themes/proton/throbber.gif
|
||||||
share/public/javascripts/moment.min.js
|
share/public/javascripts/moment.min.js
|
||||||
share/public/javascripts/natural.js
|
share/public/javascripts/natural.js
|
||||||
share/public/javascripts/netdisco.js
|
share/public/javascripts/netdisco.js
|
||||||
@@ -429,6 +456,10 @@ share/schema_versions/App-Netdisco-DB-62-63-PostgreSQL.sql
|
|||||||
share/schema_versions/App-Netdisco-DB-63-64-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-63-64-PostgreSQL.sql
|
||||||
share/schema_versions/App-Netdisco-DB-64-65-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-64-65-PostgreSQL.sql
|
||||||
share/schema_versions/App-Netdisco-DB-65-66-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-65-66-PostgreSQL.sql
|
||||||
|
share/schema_versions/App-Netdisco-DB-66-67-PostgreSQL.sql
|
||||||
|
share/schema_versions/App-Netdisco-DB-67-68-PostgreSQL.sql
|
||||||
|
share/schema_versions/App-Netdisco-DB-68-69-PostgreSQL.sql
|
||||||
|
share/schema_versions/App-Netdisco-DB-69-70-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
|
||||||
share/schema_versions/App-Netdisco-DB-9-10-PostgreSQL.sql
|
share/schema_versions/App-Netdisco-DB-9-10-PostgreSQL.sql
|
||||||
@@ -456,6 +487,8 @@ share/views/ajax/device/modules.tt
|
|||||||
share/views/ajax/device/netmap.tt
|
share/views/ajax/device/netmap.tt
|
||||||
share/views/ajax/device/ports.tt
|
share/views/ajax/device/ports.tt
|
||||||
share/views/ajax/device/ports_csv.tt
|
share/views/ajax/device/ports_csv.tt
|
||||||
|
share/views/ajax/device/snmp.tt
|
||||||
|
share/views/ajax/device/snmpnode.tt
|
||||||
share/views/ajax/device/vlans.tt
|
share/views/ajax/device/vlans.tt
|
||||||
share/views/ajax/device/vlans_csv.tt
|
share/views/ajax/device/vlans_csv.tt
|
||||||
share/views/ajax/report/apchanneldist.tt
|
share/views/ajax/report/apchanneldist.tt
|
||||||
|
|||||||
@@ -422,6 +422,24 @@ Pass a device in C<-d> to display them:
|
|||||||
|
|
||||||
~/bin/netdisco-do dumpconfig -d 192.0.2.1 -e device_auth
|
~/bin/netdisco-do dumpconfig -d 192.0.2.1 -e device_auth
|
||||||
|
|
||||||
|
=head2 snapshot
|
||||||
|
|
||||||
|
Performs an snmp walk from L<.1.3.6.1> on the device and builds a data
|
||||||
|
structure which SNMP::Info can use to mimic the device. The structure is
|
||||||
|
saved into the L<device_snapshot> database table.
|
||||||
|
|
||||||
|
Pass a value to the L<-p> parameter (mnemonic: persist) and the base64 encoded
|
||||||
|
data will also be saved to L<NETDISCO_HOME/logs/snapshots/IP> (where L<IP> is
|
||||||
|
the canonical IP of the device passed). Netdisco will load this for any pseudo
|
||||||
|
device with the same canonical IP.
|
||||||
|
|
||||||
|
~/bin/netdisco-do snapshot -d 192.0.2.1 -p yes
|
||||||
|
|
||||||
|
Pass a value to the L<-e> parameter (mnemonic: explore> and the data is also
|
||||||
|
saved into the Netdisco database for web browsing (under Device->SNMP tab).
|
||||||
|
|
||||||
|
~/bin/netdisco-do snapshot -d 192.0.2.1 -e yes
|
||||||
|
|
||||||
=head1 DEBUG OPTIONS
|
=head1 DEBUG OPTIONS
|
||||||
|
|
||||||
The flag "C<-R>" will cause any changes to the database to be rolled back
|
The flag "C<-R>" will cause any changes to the database to be rolled back
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ __PACKAGE__->load_namespaces(
|
|||||||
);
|
);
|
||||||
|
|
||||||
our # try to hide from kwalitee
|
our # try to hide from kwalitee
|
||||||
$VERSION = 66; # schema version used for upgrades, keep as integer
|
$VERSION = 70; # schema version used for upgrades, keep as integer
|
||||||
|
|
||||||
use Path::Class;
|
use Path::Class;
|
||||||
use File::ShareDir 'dist_dir';
|
use File::ShareDir 'dist_dir';
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ __PACKAGE__->add_columns(
|
|||||||
{ data_type => "timestamp", is_nullable => 1 },
|
{ data_type => "timestamp", is_nullable => 1 },
|
||||||
"last_arpnip",
|
"last_arpnip",
|
||||||
{ data_type => "timestamp", is_nullable => 1 },
|
{ data_type => "timestamp", is_nullable => 1 },
|
||||||
|
"is_pseudo",
|
||||||
|
{ data_type => "boolean", is_nullable => 0, default_value => \"false" },
|
||||||
);
|
);
|
||||||
__PACKAGE__->set_primary_key("ip");
|
__PACKAGE__->set_primary_key("ip");
|
||||||
|
|
||||||
@@ -172,6 +174,14 @@ Returns the set of power modules on this Device.
|
|||||||
|
|
||||||
__PACKAGE__->has_many( power_modules => 'App::Netdisco::DB::Result::DevicePower', 'ip' );
|
__PACKAGE__->has_many( power_modules => 'App::Netdisco::DB::Result::DevicePower', 'ip' );
|
||||||
|
|
||||||
|
=head2 oids
|
||||||
|
|
||||||
|
Returns the oids walked on this Device.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->has_many( oids => 'App::Netdisco::DB::Result::DeviceBrowser', 'ip' );
|
||||||
|
|
||||||
=head2 port_vlans
|
=head2 port_vlans
|
||||||
|
|
||||||
Returns the set of VLANs known to be configured on Ports on this Device,
|
Returns the set of VLANs known to be configured on Ports on this Device,
|
||||||
@@ -256,6 +266,15 @@ Returns the row from the community string table, if one exists.
|
|||||||
__PACKAGE__->might_have(
|
__PACKAGE__->might_have(
|
||||||
community => 'App::Netdisco::DB::Result::Community', 'ip');
|
community => 'App::Netdisco::DB::Result::Community', 'ip');
|
||||||
|
|
||||||
|
=head2 snapshot
|
||||||
|
|
||||||
|
Returns the row from the snapshot table, if one exists.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->might_have(
|
||||||
|
snapshot => 'App::Netdisco::DB::Result::DeviceSnapshot', 'ip');
|
||||||
|
|
||||||
=head2 throughput
|
=head2 throughput
|
||||||
|
|
||||||
Returns a sum of speeds on all ports on the device.
|
Returns a sum of speeds on all ports on the device.
|
||||||
@@ -267,17 +286,6 @@ __PACKAGE__->has_one(
|
|||||||
|
|
||||||
=head1 ADDITIONAL METHODS
|
=head1 ADDITIONAL METHODS
|
||||||
|
|
||||||
=head2 is_pseudo
|
|
||||||
|
|
||||||
Returns true if the vendor of the device is "netdisco".
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub is_pseudo {
|
|
||||||
my $device = shift;
|
|
||||||
return (defined $device->vendor and $device->vendor eq 'netdisco');
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 has_layer( $number )
|
=head2 has_layer( $number )
|
||||||
|
|
||||||
Returns true if the device provided sysServices and supports the given layer.
|
Returns true if the device provided sysServices and supports the given layer.
|
||||||
@@ -314,8 +322,12 @@ sub renumber {
|
|||||||
|
|
||||||
# Community is not included as SNMP::test_connection will take care of it
|
# Community is not included as SNMP::test_connection will take care of it
|
||||||
foreach my $set (qw/
|
foreach my $set (qw/
|
||||||
|
DeviceBrowser
|
||||||
DeviceIp
|
DeviceIp
|
||||||
DeviceModule
|
DeviceModule
|
||||||
|
DevicePower
|
||||||
|
DeviceSnapshot
|
||||||
|
DeviceVlan
|
||||||
DevicePort
|
DevicePort
|
||||||
DevicePortLog
|
DevicePortLog
|
||||||
DevicePortPower
|
DevicePortPower
|
||||||
@@ -323,8 +335,6 @@ sub renumber {
|
|||||||
DevicePortSsid
|
DevicePortSsid
|
||||||
DevicePortVlan
|
DevicePortVlan
|
||||||
DevicePortWireless
|
DevicePortWireless
|
||||||
DevicePower
|
|
||||||
DeviceVlan
|
|
||||||
/) {
|
/) {
|
||||||
$schema->resultset($set)
|
$schema->resultset($set)
|
||||||
->search({ip => $old_ip})
|
->search({ip => $old_ip})
|
||||||
@@ -353,6 +363,11 @@ sub renumber {
|
|||||||
->search({dev2 => $old_ip})
|
->search({dev2 => $old_ip})
|
||||||
->update({dev2 => $new_ip});
|
->update({dev2 => $new_ip});
|
||||||
|
|
||||||
|
$schema->resultset('Admin')->search({
|
||||||
|
device => $old_ip,
|
||||||
|
status => { '-not_like' => 'queued-%' },
|
||||||
|
})->delete;
|
||||||
|
|
||||||
$device->update({
|
$device->update({
|
||||||
ip => $new_ip,
|
ip => $new_ip,
|
||||||
dns => hostname_from_ip($new_ip),
|
dns => hostname_from_ip($new_ip),
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
use utf8;
|
||||||
|
package App::Netdisco::DB::Result::DeviceBrowser;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use base 'App::Netdisco::DB::Result';
|
||||||
|
__PACKAGE__->table("device_browser");
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
"ip",
|
||||||
|
{ data_type => "inet", is_nullable => 0 },
|
||||||
|
"oid",
|
||||||
|
{ data_type => "text", is_nullable => 0 },
|
||||||
|
"oid_parts",
|
||||||
|
{ data_type => "integer[]", is_nullable => 0 },
|
||||||
|
"leaf",
|
||||||
|
{ data_type => "text", is_nullable => 0 },
|
||||||
|
"munge",
|
||||||
|
{ data_type => "text", is_nullable => 1 },
|
||||||
|
"value",
|
||||||
|
{ data_type => "text", is_nullable => 1 },
|
||||||
|
);
|
||||||
|
__PACKAGE__->set_primary_key("ip", "oid");
|
||||||
|
|
||||||
|
=head1 RELATIONSHIPS
|
||||||
|
|
||||||
|
=head2 snmp_object
|
||||||
|
|
||||||
|
Returns the SNMP Object table entry to which the given row is related. The
|
||||||
|
idea is that you always get the SNMP Object row data even if the Device
|
||||||
|
Browser table doesn't have any walked data.
|
||||||
|
|
||||||
|
However you probably want to use the C<snmp_object> method in the
|
||||||
|
C<DeviceBrowser> ResultSet instead, so you can pass the IP address.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->belongs_to(
|
||||||
|
snmp_object => 'App::Netdisco::DB::Result::SNMPObject',
|
||||||
|
sub {
|
||||||
|
my $args = shift;
|
||||||
|
return {
|
||||||
|
"$args->{self_alias}.oid" => { -ident => "$args->{foreign_alias}.oid" },
|
||||||
|
"$args->{self_alias}.ip" => { '=' => \'?' },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{ join_type => 'RIGHT' }
|
||||||
|
);
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
use utf8;
|
||||||
|
package App::Netdisco::DB::Result::DeviceSnapshot;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use base 'App::Netdisco::DB::Result';
|
||||||
|
__PACKAGE__->table("device_snapshot");
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
"ip",
|
||||||
|
{ data_type => "inet", is_nullable => 0 },
|
||||||
|
"cache",
|
||||||
|
{ data_type => "text", is_nullable => 1 },
|
||||||
|
);
|
||||||
|
__PACKAGE__->set_primary_key("ip");
|
||||||
|
|
||||||
|
=head1 RELATIONSHIPS
|
||||||
|
|
||||||
|
=head2 device
|
||||||
|
|
||||||
|
Returns the entry from the C<device> table on which this snapshot was created.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->belongs_to( device => 'App::Netdisco::DB::Result::Device', 'ip' );
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
use utf8;
|
||||||
|
package App::Netdisco::DB::Result::SNMPObject;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use base 'App::Netdisco::DB::Result';
|
||||||
|
__PACKAGE__->table("snmp_object");
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
"oid",
|
||||||
|
{ data_type => "text", is_nullable => 0 },
|
||||||
|
"oid_parts",
|
||||||
|
{ data_type => "integer[]", is_nullable => 0 },
|
||||||
|
"mib",
|
||||||
|
{ data_type => "text", is_nullable => 0 },
|
||||||
|
"leaf",
|
||||||
|
{ data_type => "text", is_nullable => 0 },
|
||||||
|
"type",
|
||||||
|
{ data_type => "text", is_nullable => 1 },
|
||||||
|
"access",
|
||||||
|
{ data_type => "text", is_nullable => 1 },
|
||||||
|
"index",
|
||||||
|
{ data_type => "text[]", is_nullable => 1, default_value => \"'{}'::text[]" },
|
||||||
|
);
|
||||||
|
__PACKAGE__->set_primary_key("oid");
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
use utf8;
|
||||||
|
package App::Netdisco::DB::Result::Virtual::FilteredSNMPObject;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use base 'DBIx::Class::Core';
|
||||||
|
|
||||||
|
__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
|
||||||
|
|
||||||
|
__PACKAGE__->table("filtered_snmp_object");
|
||||||
|
__PACKAGE__->result_source_instance->is_virtual(1);
|
||||||
|
__PACKAGE__->result_source_instance->view_definition(<<ENDSQL
|
||||||
|
|
||||||
|
SELECT oid, oid_parts, mib, leaf, type, access, index
|
||||||
|
FROM snmp_object
|
||||||
|
WHERE oid LIKE ?::text || '.%'
|
||||||
|
AND oid_parts[?] = ANY (?)
|
||||||
|
AND array_length(oid_parts,1) = ?
|
||||||
|
|
||||||
|
ENDSQL
|
||||||
|
);
|
||||||
|
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
'oid' => { data_type => 'text' },
|
||||||
|
'oid_parts' => { data_type => 'integer[]' },
|
||||||
|
'mib' => { data_type => 'text' },
|
||||||
|
'leaf' => { data_type => 'text' },
|
||||||
|
'type' => { data_type => 'text' },
|
||||||
|
'access' => { data_type => 'text' },
|
||||||
|
'index' => { data_type => 'text[]' },
|
||||||
|
);
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
use utf8;
|
||||||
|
package App::Netdisco::DB::Result::Virtual::OidChildren;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use base 'DBIx::Class::Core';
|
||||||
|
|
||||||
|
__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
|
||||||
|
|
||||||
|
__PACKAGE__->table("oid_children");
|
||||||
|
__PACKAGE__->result_source_instance->is_virtual(1);
|
||||||
|
__PACKAGE__->result_source_instance->view_definition(<<ENDSQL
|
||||||
|
|
||||||
|
SELECT DISTINCT(db.oid_parts[?]) AS part, count(distinct(db2.oid_parts[?])) as children
|
||||||
|
FROM device_browser db
|
||||||
|
|
||||||
|
LEFT JOIN device_browser db2
|
||||||
|
ON (db2.oid LIKE ? || '.%'
|
||||||
|
AND db2.oid_parts[?] = db.oid_parts[?]
|
||||||
|
AND db2.ip = db.ip)
|
||||||
|
|
||||||
|
WHERE db.ip = ?
|
||||||
|
AND db.oid LIKE ? || '.%'
|
||||||
|
|
||||||
|
GROUP BY db.oid_parts
|
||||||
|
|
||||||
|
ENDSQL
|
||||||
|
);
|
||||||
|
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
'part' => { data_type => 'integer' },
|
||||||
|
'children' => { data_type => 'integer' },
|
||||||
|
);
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -704,11 +704,13 @@ sub delete {
|
|||||||
$ip ||= 'netdisco';
|
$ip ||= 'netdisco';
|
||||||
|
|
||||||
foreach my $set (qw/
|
foreach my $set (qw/
|
||||||
DeviceIp
|
|
||||||
DeviceVlan
|
|
||||||
DevicePower
|
|
||||||
DeviceModule
|
|
||||||
Community
|
Community
|
||||||
|
DeviceBrowser
|
||||||
|
DeviceIp
|
||||||
|
DeviceModule
|
||||||
|
DevicePower
|
||||||
|
DeviceSnapshot
|
||||||
|
DeviceVlan
|
||||||
/) {
|
/) {
|
||||||
my $gone = $schema->resultset($set)->search(
|
my $gone = $schema->resultset($set)->search(
|
||||||
{ ip => { '-in' => $devices->as_query } },
|
{ ip => { '-in' => $devices->as_query } },
|
||||||
@@ -746,3 +748,35 @@ sub delete {
|
|||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
__END__
|
||||||
|
list of tables in the db that use the device:
|
||||||
|
|
||||||
|
# use 'ip' as PK
|
||||||
|
community
|
||||||
|
device_browser
|
||||||
|
device_ip
|
||||||
|
device_module
|
||||||
|
device_power
|
||||||
|
device_snapshot
|
||||||
|
device_vlan
|
||||||
|
|
||||||
|
# use 'device' as PK
|
||||||
|
admin
|
||||||
|
device_skip
|
||||||
|
topology
|
||||||
|
|
||||||
|
# special to let nodes be kept
|
||||||
|
device_port
|
||||||
|
|
||||||
|
# defer to port resultset class
|
||||||
|
device_port_power
|
||||||
|
device_port_properties
|
||||||
|
device_port_ssid
|
||||||
|
device_port_vlan
|
||||||
|
device_port_wireless
|
||||||
|
device_port_log
|
||||||
|
|
||||||
|
# dbic does this one itself
|
||||||
|
device
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package App::Netdisco::DB::ResultSet::DeviceBrowser;
|
||||||
|
use base 'App::Netdisco::DB::ResultSet';
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
=head1 ADDITIONAL METHODS
|
||||||
|
|
||||||
|
=head2 with_snmp_object( $ip )
|
||||||
|
|
||||||
|
Returns a correlated subquery for the set of C<snmp_object> entry for
|
||||||
|
the walked data row.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub with_snmp_object {
|
||||||
|
my ($rs, $ip) = @_;
|
||||||
|
$ip ||= '255.255.255.255';
|
||||||
|
|
||||||
|
return $rs->search(undef,{
|
||||||
|
# NOTE: bind param list order is significant
|
||||||
|
join => ['snmp_object'],
|
||||||
|
bind => [$ip],
|
||||||
|
prefetch => 'snmp_object',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -254,9 +254,9 @@ sub delete {
|
|||||||
foreach my $set (qw/
|
foreach my $set (qw/
|
||||||
DevicePortPower
|
DevicePortPower
|
||||||
DevicePortProperties
|
DevicePortProperties
|
||||||
|
DevicePortSsid
|
||||||
DevicePortVlan
|
DevicePortVlan
|
||||||
DevicePortWireless
|
DevicePortWireless
|
||||||
DevicePortSsid
|
|
||||||
/) {
|
/) {
|
||||||
my $gone = $schema->resultset($set)->search(
|
my $gone = $schema->resultset($set)->search(
|
||||||
{ ip => { '-in' => $ports->as_query }},
|
{ ip => { '-in' => $ports->as_query }},
|
||||||
|
|||||||
@@ -10,7 +10,12 @@ use App::Netdisco::Util::Permission ':all';
|
|||||||
use SNMP::Info;
|
use SNMP::Info;
|
||||||
use Try::Tiny;
|
use Try::Tiny;
|
||||||
use Module::Load ();
|
use Module::Load ();
|
||||||
|
use Storable 'thaw';
|
||||||
|
use File::Slurper 'read_text';
|
||||||
|
use MIME::Base64 'decode_base64';
|
||||||
use Path::Class 'dir';
|
use Path::Class 'dir';
|
||||||
|
use File::Path 'make_path';
|
||||||
|
use File::Spec::Functions qw(catdir catfile);
|
||||||
use NetAddr::IP::Lite ':lower';
|
use NetAddr::IP::Lite ':lower';
|
||||||
use List::Util qw/pairkeys pairfirst/;
|
use List::Util qw/pairkeys pairfirst/;
|
||||||
|
|
||||||
@@ -58,7 +63,9 @@ 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 $pseudo_cache = catfile( catdir(($ENV{NETDISCO_HOME} || $ENV{HOME}), 'logs', 'snapshots'), $device->ip );
|
||||||
|
return undef if $device->in_storage and $device->is_pseudo and ! -f $pseudo_cache;
|
||||||
|
|
||||||
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};
|
||||||
@@ -107,6 +114,7 @@ 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;
|
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;
|
||||||
@@ -155,6 +163,13 @@ sub _snmp_connect_generic {
|
|||||||
$snmp_args{BulkWalk} = 0;
|
$snmp_args{BulkWalk} = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# support for offline cache
|
||||||
|
if ($device->is_pseudo) {
|
||||||
|
my $pseudo_cache = catfile( catdir(($ENV{NETDISCO_HOME} || $ENV{HOME}), 'logs', 'snapshots'), $device->ip );
|
||||||
|
$snmp_args{Cache} = thaw( decode_base64( read_text($pseudo_cache) ) );
|
||||||
|
$snmp_args{Offline} = 1;
|
||||||
|
}
|
||||||
|
|
||||||
# get the community string(s)
|
# get the community string(s)
|
||||||
my @communities = get_communities($device, $mode);
|
my @communities = get_communities($device, $mode);
|
||||||
|
|
||||||
@@ -242,7 +257,7 @@ sub _try_read {
|
|||||||
|
|
||||||
return undef unless (
|
return undef unless (
|
||||||
(not defined $info->error)
|
(not defined $info->error)
|
||||||
and defined $info->uptime
|
and (defined $info->uptime or defined $info->hrSystemUptime or defined $info->sysUpTime)
|
||||||
and ($info->layers or $info->description)
|
and ($info->layers or $info->description)
|
||||||
and $info->class
|
and $info->class
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ use Dancer qw/:syntax :script/;
|
|||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
|
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
|
||||||
|
|
||||||
|
use File::Spec::Functions qw(catdir catfile);
|
||||||
|
use File::Path 'make_path';
|
||||||
|
|
||||||
use base 'Exporter';
|
use base 'Exporter';
|
||||||
our @EXPORT = ();
|
our @EXPORT = ();
|
||||||
our @EXPORT_OK = qw/
|
our @EXPORT_OK = qw/
|
||||||
@@ -158,7 +161,7 @@ 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>).
|
Also checks if the device is a pseudo device and no offline cache exists.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
@@ -170,8 +173,9 @@ sub is_discoverable {
|
|||||||
$remote_type ||= '';
|
$remote_type ||= '';
|
||||||
$remote_cap ||= [];
|
$remote_cap ||= [];
|
||||||
|
|
||||||
return _bail_msg("is_discoverable: $device is pseudo-device")
|
my $pseudo_cache = catfile( catdir(($ENV{NETDISCO_HOME} || $ENV{HOME}), 'logs', 'snapshots'), $device->ip );
|
||||||
if $device->is_pseudo;
|
return _bail_msg("is_discoverable: $device is pseudo-device without offline cache")
|
||||||
|
if $device->is_pseudo and ! -f $pseudo_cache;
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
package App::Netdisco::Util::SNMP;
|
package App::Netdisco::Util::SNMP;
|
||||||
|
|
||||||
use Dancer qw/:syntax :script/;
|
use Dancer qw/:syntax :script !to_json !from_json/;
|
||||||
use App::Netdisco::Util::DeviceAuth 'get_external_credentials';
|
use App::Netdisco::Util::DeviceAuth 'get_external_credentials';
|
||||||
|
|
||||||
|
use MIME::Base64 'decode_base64';
|
||||||
|
use Storable 'thaw';
|
||||||
|
use JSON::PP;
|
||||||
|
|
||||||
use base 'Exporter';
|
use base 'Exporter';
|
||||||
our @EXPORT = ();
|
our @EXPORT = ();
|
||||||
our @EXPORT_OK = qw/ get_communities snmp_comm_reindex /;
|
our @EXPORT_OK = qw/
|
||||||
|
get_communities
|
||||||
|
snmp_comm_reindex
|
||||||
|
sortable_oid
|
||||||
|
decode_and_munge
|
||||||
|
%ALL_MUNGERS
|
||||||
|
/;
|
||||||
our %EXPORT_TAGS = (all => \@EXPORT_OK);
|
our %EXPORT_TAGS = (all => \@EXPORT_OK);
|
||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
@@ -21,6 +31,24 @@ subroutines.
|
|||||||
|
|
||||||
=head1 EXPORT_OK
|
=head1 EXPORT_OK
|
||||||
|
|
||||||
|
=head2 sortable_oid( $oid, $seglen? )
|
||||||
|
|
||||||
|
Take an OID and return a version of it which is sortable using C<cmp>
|
||||||
|
operator. Works by zero-padding the numeric parts all to be length
|
||||||
|
C<< $seglen >>, which defaults to 6.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# take oid and make comparable
|
||||||
|
sub sortable_oid {
|
||||||
|
my ($oid, $seglen) = @_;
|
||||||
|
$seglen ||= 6;
|
||||||
|
return $oid if $oid !~ m/^[0-9.]+$/;
|
||||||
|
$oid =~ s/^(\.)//; my $leading = $1;
|
||||||
|
$oid = join '.', map { sprintf("\%0${seglen}d", $_) } (split m/\./, $oid);
|
||||||
|
return (($leading || '') . $oid);
|
||||||
|
}
|
||||||
|
|
||||||
=head2 get_communities( $device, $mode )
|
=head2 get_communities( $device, $mode )
|
||||||
|
|
||||||
Takes the current C<device_auth> setting and pushes onto the front of the list
|
Takes the current C<device_auth> setting and pushes onto the front of the list
|
||||||
@@ -130,4 +158,93 @@ sub snmp_comm_reindex {
|
|||||||
return $snmp;
|
return $snmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
our %ALL_MUNGERS = (
|
||||||
|
'SNMP::Info::munge_speed' => \&SNMP::Info::munge_speed,
|
||||||
|
'SNMP::Info::munge_highspeed' => \&SNMP::Info::munge_highspeed,
|
||||||
|
'SNMP::Info::munge_ip' => \&SNMP::Info::munge_ip,
|
||||||
|
'SNMP::Info::munge_mac' => \&SNMP::Info::munge_mac,
|
||||||
|
'SNMP::Info::munge_prio_mac' => \&SNMP::Info::munge_prio_mac,
|
||||||
|
'SNMP::Info::munge_prio_port' => \&SNMP::Info::munge_prio_port,
|
||||||
|
'SNMP::Info::munge_octet2hex' => \&SNMP::Info::munge_octet2hex,
|
||||||
|
'SNMP::Info::munge_dec2bin' => \&SNMP::Info::munge_dec2bin,
|
||||||
|
'SNMP::Info::munge_bits' => \&SNMP::Info::munge_bits,
|
||||||
|
'SNMP::Info::munge_counter64' => \&SNMP::Info::munge_counter64,
|
||||||
|
'SNMP::Info::munge_i_up' => \&SNMP::Info::munge_i_up,
|
||||||
|
'SNMP::Info::munge_port_list' => \&SNMP::Info::munge_port_list,
|
||||||
|
'SNMP::Info::munge_null' => \&SNMP::Info::munge_null,
|
||||||
|
'SNMP::Info::munge_e_type' => \&SNMP::Info::munge_e_type,
|
||||||
|
'SNMP::Info::Airespace::munge_64bits' => \&SNMP::Info::Airespace::munge_64bits,
|
||||||
|
'SNMP::Info::CDP::munge_power' => \&SNMP::Info::CDP::munge_power,
|
||||||
|
'SNMP::Info::CiscoAgg::munge_port_ifindex' => \&SNMP::Info::CiscoAgg::munge_port_ifindex,
|
||||||
|
'SNMP::Info::CiscoPortSecurity::munge_pae_capabilities' => \&SNMP::Info::CiscoPortSecurity::munge_pae_capabilities,
|
||||||
|
'SNMP::Info::CiscoStack::munge_port_status' => \&SNMP::Info::CiscoStack::munge_port_status,
|
||||||
|
'SNMP::Info::EtherLike::munge_el_duplex' => \&SNMP::Info::EtherLike::munge_el_duplex,
|
||||||
|
'SNMP::Info::IPv6::munge_physaddr' => \&SNMP::Info::IPv6::munge_physaddr,
|
||||||
|
'SNMP::Info::Layer2::Airespace::munge_cd11n_ch_bw' => \&SNMP::Info::Layer2::Airespace::munge_cd11n_ch_bw,
|
||||||
|
'SNMP::Info::Layer2::Airespace::munge_cd11_proto' => \&SNMP::Info::Layer2::Airespace::munge_cd11_proto,
|
||||||
|
'SNMP::Info::Layer2::Airespace::munge_cd11_rateset' => \&SNMP::Info::Layer2::Airespace::munge_cd11_rateset,
|
||||||
|
'SNMP::Info::Layer2::Aironet::munge_cd11_txrate' => \&SNMP::Info::Layer2::Aironet::munge_cd11_txrate,
|
||||||
|
'SNMP::Info::Layer2::HP::munge_hp_c_id' => \&SNMP::Info::Layer2::HP::munge_hp_c_id,
|
||||||
|
'SNMP::Info::Layer2::Nexans::munge_i_duplex' => \&SNMP::Info::Layer2::Nexans::munge_i_duplex,
|
||||||
|
'SNMP::Info::Layer2::Nexans::munge_i_duplex_admin' => \&SNMP::Info::Layer2::Nexans::munge_i_duplex_admin,
|
||||||
|
'SNMP::Info::Layer3::Altiga::munge_alarm' => \&SNMP::Info::Layer3::Altiga::munge_alarm,
|
||||||
|
'SNMP::Info::Layer3::Aruba::munge_aruba_fqln' => \&SNMP::Info::Layer3::Aruba::munge_aruba_fqln,
|
||||||
|
'SNMP::Info::Layer3::BayRS::munge_hw_rev' => \&SNMP::Info::Layer3::BayRS::munge_hw_rev,
|
||||||
|
'SNMP::Info::Layer3::BayRS::munge_wf_serial' => \&SNMP::Info::Layer3::BayRS::munge_wf_serial,
|
||||||
|
'SNMP::Info::Layer3::Extreme::munge_true_ok' => \&SNMP::Info::Layer3::Extreme::munge_true_ok,
|
||||||
|
'SNMP::Info::Layer3::Extreme::munge_power_stat' => \&SNMP::Info::Layer3::Extreme::munge_power_stat,
|
||||||
|
'SNMP::Info::Layer3::Huawei::munge_hw_peth_admin' => \&SNMP::Info::Layer3::Huawei::munge_hw_peth_admin,
|
||||||
|
'SNMP::Info::Layer3::Huawei::munge_hw_peth_power' => \&SNMP::Info::Layer3::Huawei::munge_hw_peth_power,
|
||||||
|
'SNMP::Info::Layer3::Huawei::munge_hw_peth_class' => \&SNMP::Info::Layer3::Huawei::munge_hw_peth_class,
|
||||||
|
'SNMP::Info::Layer3::Huawei::munge_hw_peth_status' => \&SNMP::Info::Layer3::Huawei::munge_hw_peth_status,
|
||||||
|
'SNMP::Info::Layer3::Timetra::munge_tmnx_state' => \&SNMP::Info::Layer3::Timetra::munge_tmnx_state,
|
||||||
|
'SNMP::Info::Layer3::Timetra::munge_tmnx_e_class' => \&SNMP::Info::Layer3::Timetra::munge_tmnx_e_class,
|
||||||
|
'SNMP::Info::Layer3::Timetra::munge_tmnx_e_swver' => \&SNMP::Info::Layer3::Timetra::munge_tmnx_e_swver,
|
||||||
|
'SNMP::Info::MAU::munge_int2bin' => \&SNMP::Info::MAU::munge_int2bin,
|
||||||
|
'SNMP::Info::NortelStack::munge_ns_grp_type' => \&SNMP::Info::NortelStack::munge_ns_grp_type,
|
||||||
|
);
|
||||||
|
|
||||||
|
=head2 decode_and_munge( $method, $data )
|
||||||
|
|
||||||
|
Takes some data from L<SNMP::Info> cache that has been Base64 encoded
|
||||||
|
and frozen with Storable, decodes it and then munge to handle data format,
|
||||||
|
before finally pretty render in JSON format.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub get_code_info { return ($_[0]) =~ m/^(.+)::(.*?)$/ }
|
||||||
|
sub sub_name { return (get_code_info $_[0])[1] }
|
||||||
|
sub class_name { return (get_code_info $_[0])[0] }
|
||||||
|
|
||||||
|
sub decode_and_munge {
|
||||||
|
my ($munger, $encoded) = @_;
|
||||||
|
return undef unless defined $encoded and length $encoded;
|
||||||
|
|
||||||
|
my $coder = JSON::PP->new->utf8->pretty->allow_nonref->allow_unknown->canonical;
|
||||||
|
$coder->sort_by( sub { sortable_oid($JSON::PP::a) cmp sortable_oid($JSON::PP::b) } );
|
||||||
|
|
||||||
|
my $data = (@{ thaw( decode_base64( $encoded ) ) })[0];
|
||||||
|
return $coder->encode( $data )
|
||||||
|
unless $munger and exists $ALL_MUNGERS{$munger};
|
||||||
|
|
||||||
|
my $sub = sub_name($munger);
|
||||||
|
my $class = class_name($munger);
|
||||||
|
Module::Load::load $class;
|
||||||
|
|
||||||
|
if (ref {} eq ref $data) {
|
||||||
|
my %munged;
|
||||||
|
foreach my $key ( keys %$data ) {
|
||||||
|
my $value = $data->{$key};
|
||||||
|
next unless defined $value;
|
||||||
|
$munged{$key} = $ALL_MUNGERS{$munger}->($value);
|
||||||
|
}
|
||||||
|
return $coder->encode( \%munged );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return unless $data;
|
||||||
|
return $coder->encode( $ALL_MUNGERS{$munger}->($data) );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
true;
|
true;
|
||||||
|
|||||||
@@ -58,6 +58,31 @@ ajax qr{/ajax/control/admin/(?:\w+/)?delete} => require_role setting('defanged_a
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ajax "/ajax/control/admin/snapshot_req" => require_role admin => sub {
|
||||||
|
my $device = NetAddr::IP->new(param('device'));
|
||||||
|
send_error('Bad device', 400)
|
||||||
|
if ! $device or $device->addr eq '0.0.0.0';
|
||||||
|
|
||||||
|
add_job('snapshot', $device->addr) or send_error('Bad device', 400);
|
||||||
|
};
|
||||||
|
|
||||||
|
get "/ajax/content/admin/snapshot_get" => require_role admin => sub {
|
||||||
|
my $device = NetAddr::IP->new(param('device'));
|
||||||
|
send_error('Bad device', 400)
|
||||||
|
if ! $device or $device->addr eq '0.0.0.0';
|
||||||
|
|
||||||
|
my $content = schema('netdisco')->resultset('DeviceSnapshot')->find($device->addr)->cache;
|
||||||
|
send_file( \$content, content_type => 'text/plain', filename => ($device->addr .'-snapshot.txt') );
|
||||||
|
};
|
||||||
|
|
||||||
|
ajax "/ajax/control/admin/snapshot_del" => require_role setting('defanged_admin') => sub {
|
||||||
|
my $device = NetAddr::IP->new(param('device'));
|
||||||
|
send_error('Bad device', 400)
|
||||||
|
if ! $device or $device->addr eq '0.0.0.0';
|
||||||
|
|
||||||
|
schema('netdisco')->resultset('DeviceSnapshot')->find($device->addr)->delete;
|
||||||
|
};
|
||||||
|
|
||||||
get '/admin/*' => require_role admin => sub {
|
get '/admin/*' => require_role admin => sub {
|
||||||
my ($tag) = splat;
|
my ($tag) = splat;
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ get '/device' => require_login sub {
|
|||||||
|
|
||||||
params->{'tab'} ||= 'details';
|
params->{'tab'} ||= 'details';
|
||||||
template 'device', {
|
template 'device', {
|
||||||
|
is_pseudo => $first->is_pseudo,
|
||||||
display_name => ($others ? $first->ip : ($first->dns || $first->ip)),
|
display_name => ($others ? $first->ip : ($first->dns || $first->ip)),
|
||||||
lgroup_list => [ schema('netdisco')->resultset('Device')->get_distinct_col('location') ],
|
lgroup_list => [ schema('netdisco')->resultset('Device')->get_distinct_col('location') ],
|
||||||
hgroup_list => setting('host_group_displaynames'),
|
hgroup_list => setting('host_group_displaynames'),
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ register 'register_search_tab' => sub {
|
|||||||
|
|
||||||
register 'register_device_tab' => sub {
|
register 'register_device_tab' => sub {
|
||||||
my ($self, $config) = plugin_args(@_);
|
my ($self, $config) = plugin_args(@_);
|
||||||
|
$config->{render_if} ||= sub { true };
|
||||||
_register_tab('device', $config);
|
_register_tab('device', $config);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ ajax '/ajax/control/admin/pseudodevice/add' => require_role admin => sub {
|
|||||||
vendor => 'netdisco',
|
vendor => 'netdisco',
|
||||||
layers => param('layers'),
|
layers => param('layers'),
|
||||||
last_discover => \'now()',
|
last_discover => \'now()',
|
||||||
|
is_pseudo => \'true',
|
||||||
});
|
});
|
||||||
return unless $device;
|
return unless $device;
|
||||||
|
|
||||||
@@ -96,7 +97,7 @@ ajax '/ajax/control/admin/pseudodevice/update' => require_role admin => sub {
|
|||||||
ajax '/ajax/content/admin/pseudodevice' => require_role admin => sub {
|
ajax '/ajax/content/admin/pseudodevice' => require_role admin => sub {
|
||||||
my $set = schema('netdisco')->resultset('Device')
|
my $set = schema('netdisco')->resultset('Device')
|
||||||
->search(
|
->search(
|
||||||
{vendor => 'netdisco'},
|
{-bool => 'is_pseudo'},
|
||||||
{order_by => { -desc => 'last_discover' }},
|
{order_by => { -desc => 'last_discover' }},
|
||||||
)->with_port_count;
|
)->with_port_count;
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,13 @@ ajax '/ajax/content/device/details' => require_login sub {
|
|||||||
|
|
||||||
my @results
|
my @results
|
||||||
= schema('netdisco')->resultset('Device')
|
= schema('netdisco')->resultset('Device')
|
||||||
->search( { 'me.ip' => $device->ip } )->with_times()
|
->search({ 'me.ip' => $device->ip },
|
||||||
|
{
|
||||||
|
'+select' => ['snapshot.ip'],
|
||||||
|
'+as' => ['has_snapshot'],
|
||||||
|
join => 'snapshot',
|
||||||
|
},
|
||||||
|
)->with_times()
|
||||||
->hri->all;
|
->hri->all;
|
||||||
|
|
||||||
my @power
|
my @power
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
package App::Netdisco::Web::Plugin::Device::SNMP;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Dancer qw(:syntax);
|
||||||
|
use Dancer::Plugin::Ajax;
|
||||||
|
use Dancer::Plugin::DBIC;
|
||||||
|
use Dancer::Plugin::Swagger;
|
||||||
|
use Dancer::Plugin::Auth::Extensible;
|
||||||
|
|
||||||
|
use App::Netdisco::Web::Plugin;
|
||||||
|
use App::Netdisco::Util::SNMP qw(%ALL_MUNGERS decode_and_munge);
|
||||||
|
use Module::Load ();
|
||||||
|
use Try::Tiny;
|
||||||
|
|
||||||
|
register_device_tab({ tag => 'snmp', label => 'SNMP',
|
||||||
|
render_if => sub { schema('netdisco')->resultset('DeviceBrowser')->count() } });
|
||||||
|
|
||||||
|
get '/ajax/content/device/snmp' => require_login sub {
|
||||||
|
my $device = try { schema('netdisco')->resultset('Device')
|
||||||
|
->find( param('ip') ) }
|
||||||
|
or send_error('Bad Device', 404);
|
||||||
|
|
||||||
|
template 'ajax/device/snmp.tt', { device => $device->ip },
|
||||||
|
{ layout => 'noop' };
|
||||||
|
};
|
||||||
|
|
||||||
|
ajax '/ajax/data/device/:ip/snmptree/:base' => require_login sub {
|
||||||
|
my $device = try { schema('netdisco')->resultset('Device')
|
||||||
|
->find( param('ip') ) }
|
||||||
|
or send_error('Bad Device', 404);
|
||||||
|
|
||||||
|
my $recurse = ((param('recurse') and param('recurse') eq 'on') ? 0 : 1);
|
||||||
|
my $base = param('base');
|
||||||
|
$base =~ m/^\.1\.3\.6\.1(\.\d+)*$/ or send_error('Bad OID Base', 404);
|
||||||
|
|
||||||
|
my $items = _get_snmp_data($device->ip, $base, $recurse);
|
||||||
|
|
||||||
|
content_type 'application/json';
|
||||||
|
to_json $items;
|
||||||
|
};
|
||||||
|
|
||||||
|
ajax '/ajax/data/device/:ip/typeahead' => require_login sub {
|
||||||
|
my $device = try { schema('netdisco')->resultset('Device')
|
||||||
|
->find( param('ip') ) }
|
||||||
|
or send_error('Bad Device', 404);
|
||||||
|
|
||||||
|
my $term = param('term') or return to_json [];
|
||||||
|
$term = '%'. $term .'%';
|
||||||
|
|
||||||
|
my @found = schema('netdisco')->resultset('DeviceBrowser')
|
||||||
|
->search({ leaf => { -ilike => $term }, ip => $device->ip },
|
||||||
|
{ rows => 25, columns => 'leaf' })
|
||||||
|
->get_column('leaf')->all;
|
||||||
|
return to_json [] unless scalar @found;
|
||||||
|
|
||||||
|
content_type 'application/json';
|
||||||
|
to_json [ sort @found ];
|
||||||
|
};
|
||||||
|
|
||||||
|
ajax '/ajax/data/device/:ip/snmpnodesearch' => require_login sub {
|
||||||
|
my $device = try { schema('netdisco')->resultset('Device')
|
||||||
|
->find( param('ip') ) }
|
||||||
|
or send_error('Bad Device', 404);
|
||||||
|
|
||||||
|
my $to_match = param('str');
|
||||||
|
my $partial = param('partial');
|
||||||
|
my $excludeself = param('excludeself');
|
||||||
|
|
||||||
|
return to_json [] unless $to_match or length($to_match);
|
||||||
|
$to_match = $to_match . '%' if $partial;
|
||||||
|
my $found = undef;
|
||||||
|
|
||||||
|
my $op = ($partial ? '-ilike' : '=');
|
||||||
|
$found = schema('netdisco')->resultset('DeviceBrowser')
|
||||||
|
->search({ -or => [ oid => { $op => $to_match }, leaf => { $op => $to_match } ], ip => $device->ip },
|
||||||
|
{ rows => 1, order_by => 'oid_parts' })->first;
|
||||||
|
|
||||||
|
return to_json [] unless $found;
|
||||||
|
|
||||||
|
$found = $found->oid;
|
||||||
|
$found =~ s/^\.1\.3\.6\.1\.?//;
|
||||||
|
my @results = ('.1.3.6.1');
|
||||||
|
|
||||||
|
foreach my $part (split m/\./, $found) {
|
||||||
|
my $last = $results[-1];
|
||||||
|
push @results, "${last}.${part}";
|
||||||
|
}
|
||||||
|
|
||||||
|
content_type 'application/json';
|
||||||
|
to_json \@results;
|
||||||
|
};
|
||||||
|
|
||||||
|
ajax '/ajax/content/device/:ip/snmpnode/:oid' => require_login sub {
|
||||||
|
my $device = try { schema('netdisco')->resultset('Device')
|
||||||
|
->find( param('ip') ) }
|
||||||
|
or send_error('Bad Device', 404);
|
||||||
|
|
||||||
|
my $oid = param('oid');
|
||||||
|
$oid =~ m/^\.1\.3\.6\.1(\.\d+)*$/ or send_error('Bad OID', 404);
|
||||||
|
|
||||||
|
my $object = schema('netdisco')->resultset('DeviceBrowser')
|
||||||
|
->with_snmp_object($device->ip)->find({ 'snmp_object.oid' => $oid })
|
||||||
|
or send_error('Bad OID', 404);
|
||||||
|
|
||||||
|
my $munge = (param('munge') and exists $ALL_MUNGERS{param('munge')})
|
||||||
|
? param('munge') : $object->munge;
|
||||||
|
|
||||||
|
my %data = (
|
||||||
|
$object->get_columns,
|
||||||
|
snmp_object => { $object->snmp_object->get_columns },
|
||||||
|
value => decode_and_munge( $munge, $object->value ),
|
||||||
|
);
|
||||||
|
|
||||||
|
template 'ajax/device/snmpnode.tt',
|
||||||
|
{ node => \%data, munge => $munge, mungers => [sort keys %ALL_MUNGERS] },
|
||||||
|
{ layout => 'noop' };
|
||||||
|
};
|
||||||
|
|
||||||
|
sub _get_snmp_data {
|
||||||
|
my ($ip, $base, $recurse) = @_;
|
||||||
|
my @parts = grep {length} split m/\./, $base;
|
||||||
|
++$recurse;
|
||||||
|
|
||||||
|
my %kids = map { ($base .'.'. $_->{part}) => $_ }
|
||||||
|
schema('netdisco')->resultset('Virtual::OidChildren')
|
||||||
|
->search({}, { bind => [
|
||||||
|
(scalar @parts + 1),
|
||||||
|
(scalar @parts + 2),
|
||||||
|
$base,
|
||||||
|
(scalar @parts + 1),
|
||||||
|
(scalar @parts + 1),
|
||||||
|
$ip,
|
||||||
|
$base,
|
||||||
|
] })->hri->all;
|
||||||
|
|
||||||
|
return [{
|
||||||
|
text => 'No SNMP data for this device.',
|
||||||
|
children => \0,
|
||||||
|
state => { disabled => \1 },
|
||||||
|
icon => 'icon-search',
|
||||||
|
}] unless scalar keys %kids;
|
||||||
|
|
||||||
|
my %meta = map { ('.'. join '.', @{$_->{oid_parts}}) => $_ }
|
||||||
|
schema('netdisco')->resultset('Virtual::FilteredSNMPObject')
|
||||||
|
->search({}, { bind => [
|
||||||
|
$base,
|
||||||
|
(scalar @parts + 1),
|
||||||
|
[[ map {$_->{part}} values %kids ]],
|
||||||
|
(scalar @parts + 1),
|
||||||
|
] })->hri->all;
|
||||||
|
|
||||||
|
my @items = map {{
|
||||||
|
id => $_,
|
||||||
|
text => ($meta{$_}->{leaf} .' ('. $kids{$_}->{part} .')'),
|
||||||
|
|
||||||
|
# for nodes with only one child, recurse to prefetch...
|
||||||
|
children => ( ($recurse < 2 and $kids{$_}->{children} == 1)
|
||||||
|
? _get_snmp_data($ip, ("${base}.". $kids{$_}->{part}), $recurse)
|
||||||
|
: ($kids{$_}->{children} ? \1 : \0)),
|
||||||
|
|
||||||
|
# and set the display to open to show the single child
|
||||||
|
state => { opened => ( ($recurse < 2 and $kids{$_}->{children} == 1)
|
||||||
|
? \1
|
||||||
|
: \0 ) },
|
||||||
|
|
||||||
|
($kids{$_}->{children} ? () : (icon => 'icon-leaf')),
|
||||||
|
(scalar @{$meta{$_}->{index}} ? (icon => 'icon-th') : ()),
|
||||||
|
}} sort {$kids{$a}->{part} <=> $kids{$b}->{part}} keys %kids;
|
||||||
|
|
||||||
|
return \@items;
|
||||||
|
}
|
||||||
|
|
||||||
|
true;
|
||||||
@@ -38,14 +38,14 @@ sub gather_subnets {
|
|||||||
|
|
||||||
my $ip_netmask = $snmp->ip_netmask;
|
my $ip_netmask = $snmp->ip_netmask;
|
||||||
foreach my $entry (keys %$ip_netmask) {
|
foreach my $entry (keys %$ip_netmask) {
|
||||||
my $ip = NetAddr::IP::Lite->new($entry);
|
my $ip = NetAddr::IP::Lite->new($entry) or next;
|
||||||
my $addr = $ip->addr;
|
my $addr = $ip->addr;
|
||||||
|
|
||||||
next if $addr eq '0.0.0.0';
|
next if $addr eq '0.0.0.0';
|
||||||
next if check_acl_no($ip, 'group:__LOCAL_ADDRESSES__');
|
next if check_acl_no($ip, 'group:__LOCAL_ADDRESSES__');
|
||||||
next if setting('ignore_private_nets') and $ip->is_rfc1918;
|
next if setting('ignore_private_nets') and $ip->is_rfc1918;
|
||||||
|
|
||||||
my $netmask = $ip_netmask->{$addr};
|
my $netmask = $ip_netmask->{$addr} || $ip->bits();
|
||||||
next if $netmask eq '255.255.255.255' or $netmask eq '0.0.0.0';
|
next if $netmask eq '255.255.255.255' or $netmask eq '0.0.0.0';
|
||||||
|
|
||||||
my $cidr = NetAddr::IP::Lite->new($addr, $netmask)->network->cidr;
|
my $cidr = NetAddr::IP::Lite->new($addr, $netmask)->network->cidr;
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
$device->set_column( last_discover => \'now()' );
|
$device->set_column( last_discover => \'now()' );
|
||||||
|
|
||||||
# protection for failed SNMP gather
|
# protection for failed SNMP gather
|
||||||
if ($device->in_storage) {
|
if ($device->in_storage and not $device->is_pseudo) {
|
||||||
my $ip = $device->ip;
|
my $ip = $device->ip;
|
||||||
my $protect = setting('snmp_field_protection')->{'device'} || {};
|
my $protect = setting('snmp_field_protection')->{'device'} || {};
|
||||||
my %dirty = $device->get_dirty_columns;
|
my %dirty = $device->get_dirty_columns;
|
||||||
@@ -199,7 +199,7 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
|
|||||||
my $agg_ports = $snmp->agg_ports;
|
my $agg_ports = $snmp->agg_ports;
|
||||||
|
|
||||||
# clear the cached uptime and get a new one
|
# clear the cached uptime and get a new one
|
||||||
my $dev_uptime = $snmp->load_uptime;
|
my $dev_uptime = ($device->is_pseudo ? $snmp->uptime : $snmp->load_uptime);
|
||||||
if (!defined $dev_uptime) {
|
if (!defined $dev_uptime) {
|
||||||
error sprintf ' [%s] interfaces - Error! Failed to get uptime from device!',
|
error sprintf ' [%s] interfaces - Error! Failed to get uptime from device!',
|
||||||
$device->ip;
|
$device->ip;
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package App::Netdisco::Worker::Plugin::LoadMIBs;
|
||||||
|
|
||||||
|
use Dancer ':syntax';
|
||||||
|
use App::Netdisco::Worker::Plugin;
|
||||||
|
use aliased 'App::Netdisco::Worker::Status';
|
||||||
|
|
||||||
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
|
|
||||||
|
use File::Spec::Functions qw(catdir catfile);
|
||||||
|
use File::Slurper qw(read_lines write_text);
|
||||||
|
# use DDP;
|
||||||
|
|
||||||
|
register_worker({ phase => 'main' }, sub {
|
||||||
|
my ($job, $workerconf) = @_;
|
||||||
|
|
||||||
|
debug "loadmibs - loading netdisco-mibs object cache";
|
||||||
|
|
||||||
|
my $home = (setting('mibhome') || catdir(($ENV{NETDISCO_HOME} || $ENV{HOME}), 'netdisco-mibs'));
|
||||||
|
my @report = read_lines(catfile($home, qw(EXTRAS reports all_oids)), 'latin-1');
|
||||||
|
|
||||||
|
my @browser = ();
|
||||||
|
foreach my $line (@report) {
|
||||||
|
my ($oid, $qual_leaf, $type, $access, $index) = split m/,/, $line;
|
||||||
|
next unless defined $oid and defined $qual_leaf;
|
||||||
|
my ($mib, $leaf) = split m/::/, $qual_leaf;
|
||||||
|
push @browser, {
|
||||||
|
oid => $oid,
|
||||||
|
oid_parts => [ grep {length} (split m/\./, $oid) ],
|
||||||
|
mib => $mib,
|
||||||
|
leaf => $leaf,
|
||||||
|
type => $type,
|
||||||
|
access => $access,
|
||||||
|
index => [($index ? (split m/:/, $index) : ())],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
debug sprintf "loadmibs - loaded %d objects from netdisco-mibs",
|
||||||
|
scalar @browser;
|
||||||
|
|
||||||
|
schema('netdisco')->txn_do(sub {
|
||||||
|
my $gone = schema('netdisco')->resultset('SNMPObject')->delete;
|
||||||
|
debug sprintf ' loadmibs - removed %d oids', $gone;
|
||||||
|
schema('netdisco')->resultset('SNMPObject')->populate(\@browser);
|
||||||
|
debug sprintf ' loadmibs - added %d new oids', scalar @browser;
|
||||||
|
});
|
||||||
|
|
||||||
|
return Status->done('Loaded MIBs');
|
||||||
|
});
|
||||||
|
|
||||||
|
true;
|
||||||
@@ -28,8 +28,8 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my $i = App::Netdisco::Transport::SNMP->reader_for($device, $class);
|
my $snmp = App::Netdisco::Transport::SNMP->reader_for($device, $class);
|
||||||
my $result = sub { eval { $i->$extra($port) } || undef };
|
my $result = sub { eval { $snmp->$extra($port) } || undef };
|
||||||
Data::Printer::p( $result->() );
|
Data::Printer::p( $result->() );
|
||||||
|
|
||||||
return Status->done(
|
return Status->done(
|
||||||
|
|||||||
@@ -0,0 +1,433 @@
|
|||||||
|
package App::Netdisco::Worker::Plugin::Snapshot;
|
||||||
|
|
||||||
|
use Dancer ':syntax';
|
||||||
|
use App::Netdisco::Worker::Plugin;
|
||||||
|
use aliased 'App::Netdisco::Worker::Status';
|
||||||
|
|
||||||
|
use App::Netdisco::Transport::SNMP;
|
||||||
|
use App::Netdisco::Util::SNMP 'sortable_oid';
|
||||||
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
|
|
||||||
|
use File::Spec::Functions qw(catdir catfile);
|
||||||
|
use MIME::Base64 'encode_base64';
|
||||||
|
use File::Slurper qw(read_lines write_text);
|
||||||
|
use File::Path 'make_path';
|
||||||
|
use Sub::Util 'subname';
|
||||||
|
use Storable qw(dclone nfreeze);
|
||||||
|
# use DDP;
|
||||||
|
|
||||||
|
register_worker({ phase => 'check' }, sub {
|
||||||
|
return Status->error('Missing device (-d).')
|
||||||
|
unless defined shift->device;
|
||||||
|
return Status->done('Snapshot is able to run');
|
||||||
|
});
|
||||||
|
|
||||||
|
register_worker({ phase => 'main', driver => 'snmp' }, sub {
|
||||||
|
my ($job, $workerconf) = @_;
|
||||||
|
my $device = $job->device;
|
||||||
|
my $save_file = $job->port;
|
||||||
|
my $save_db = $job->extra;
|
||||||
|
|
||||||
|
# needed to avoid $var being returned with leafname and breaking loop checks
|
||||||
|
$SNMP::use_numeric = 1;
|
||||||
|
my $snmp = App::Netdisco::Transport::SNMP->reader_for($device)
|
||||||
|
or return Status->defer("snapshot failed: could not SNMP connect to $device");
|
||||||
|
|
||||||
|
my %oidmap = getoidmap($device, $snmp);
|
||||||
|
my %walk = walker($device, $snmp, '.1.3.6.1'); # 10205 rows
|
||||||
|
# my %walk = walker($device, $snmp, '.1.3.6.1.2.1.2.2.1.6'); # 22 rows, i_mac/ifPhysAddress
|
||||||
|
|
||||||
|
my %munge = %{ $snmp->munge() };
|
||||||
|
my %munge_set = ();
|
||||||
|
|
||||||
|
# take the snmpwalk of the device which is numeric (no MIB translateObj),
|
||||||
|
# resolve to MIB identifiers using netdisco-mibs, then store in SNMP::Info
|
||||||
|
# instance cache
|
||||||
|
|
||||||
|
my (%tables, %leaves, @realoids) = ((), (), ());
|
||||||
|
OID: foreach my $orig_oid (keys %walk) {
|
||||||
|
my $oid = $orig_oid;
|
||||||
|
my $idx = '';
|
||||||
|
|
||||||
|
while (length($oid) and !exists $oidmap{$oid}) {
|
||||||
|
$oid =~ s/\.(\d+)$//;
|
||||||
|
$idx = ($idx ? "${1}.${idx}" : $1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exists $oidmap{$oid}) {
|
||||||
|
$idx =~ s/^\.//;
|
||||||
|
my $leaf = $oidmap{$oid};
|
||||||
|
|
||||||
|
if ($idx eq 0) {
|
||||||
|
push @realoids, $oid;
|
||||||
|
$leaves{ $leaf } = $walk{$orig_oid};
|
||||||
|
$munge_set{$leaf} = subname($munge{$leaf}) if exists $munge{$leaf};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
push @realoids, $oid if !exists $tables{ $leaf };
|
||||||
|
$tables{ $leaf }->{$idx} = $walk{$orig_oid};
|
||||||
|
$munge_set{$leaf} = subname($munge{$leaf}) if exists $munge{$leaf};
|
||||||
|
}
|
||||||
|
|
||||||
|
# debug "snapshot $device - cached $oidmap{$oid}($idx)";
|
||||||
|
next OID;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug "snapshot $device - missing OID $orig_oid in netdisco-mibs";
|
||||||
|
}
|
||||||
|
|
||||||
|
$snmp->_cache($_, $leaves{$_}) for keys %leaves;
|
||||||
|
$snmp->_cache($_, $tables{$_}) for keys %tables;
|
||||||
|
|
||||||
|
# we want to add in the GLOBALS and FUNCS aliases which users
|
||||||
|
# have created in the SNMP::Info device class, with binary copy
|
||||||
|
# of data so that it can be frozen
|
||||||
|
|
||||||
|
my %cache = %{ $snmp->cache() };
|
||||||
|
my %funcs = %{ $snmp->funcs() };
|
||||||
|
my %globals = %{ $snmp->globals() };
|
||||||
|
|
||||||
|
while (my ($alias, $leaf) = each %globals) {
|
||||||
|
if (exists $cache{"_$leaf"} and !exists $cache{"_$alias"}) {
|
||||||
|
$snmp->_cache($alias, $cache{"_$leaf"});
|
||||||
|
}
|
||||||
|
$munge_set{$leaf} = subname($munge{$alias}) if exists $munge{$alias};
|
||||||
|
}
|
||||||
|
|
||||||
|
while (my ($alias, $leaf) = each %funcs) {
|
||||||
|
if (exists $cache{store}->{$leaf} and !exists $cache{store}->{$alias}) {
|
||||||
|
$snmp->_cache($alias, dclone $cache{store}->{$leaf});
|
||||||
|
}
|
||||||
|
$munge_set{$leaf} = subname($munge{$alias}) if exists $munge{$alias};
|
||||||
|
}
|
||||||
|
|
||||||
|
# now for any other SNMP::Info method in GLOBALS or FUNCS which Netdisco
|
||||||
|
# might call, but will not have data, we fake a cache entry to avoid
|
||||||
|
# throwing errors
|
||||||
|
|
||||||
|
# refresh the cache
|
||||||
|
%cache = %{ $snmp->cache() };
|
||||||
|
|
||||||
|
while (my $method = <DATA>) {
|
||||||
|
$method =~ s/\s//g;
|
||||||
|
next unless length $method and !exists $cache{"_$method"};
|
||||||
|
|
||||||
|
$snmp->_cache($method, {}) if exists $funcs{$method};
|
||||||
|
$snmp->_cache($method, '') if exists $globals{$method};
|
||||||
|
}
|
||||||
|
|
||||||
|
# finally, freeze the cache, then base64 encode, store in the DB, and
|
||||||
|
# optionally save file.
|
||||||
|
|
||||||
|
# refresh the cache again
|
||||||
|
%cache = %{ $snmp->cache() };
|
||||||
|
|
||||||
|
debug "snapshot $device - cacheing snapshot bundle";
|
||||||
|
my $frozen = encode_base64( nfreeze( \%cache ) );
|
||||||
|
$device->update_or_create_related('snapshot', {cache => $frozen});
|
||||||
|
|
||||||
|
if ($save_db) {
|
||||||
|
debug "snapshot $device - cacheing snapshot for browsing";
|
||||||
|
my @browser = map {{
|
||||||
|
oid => $_,
|
||||||
|
oid_parts => [ grep {length} (split m/\./, $_) ],
|
||||||
|
leaf => $oidmap{$_},
|
||||||
|
munge => $munge_set{ $oidmap{$_} },
|
||||||
|
value => do { my $m = $oidmap{$_}; encode_base64( nfreeze( [$snmp->$m] ) ); },
|
||||||
|
}} sort {sortable_oid($a) cmp sortable_oid($b)} @realoids;
|
||||||
|
|
||||||
|
schema('netdisco')->txn_do(sub {
|
||||||
|
my $gone = $device->oids->delete;
|
||||||
|
debug sprintf ' [%s] snapshot - removed %d oids',
|
||||||
|
$device->ip, $gone;
|
||||||
|
$device->oids->populate(\@browser);
|
||||||
|
debug sprintf ' [%s] snapshot - added %d new oids',
|
||||||
|
$device->ip, scalar @browser;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($save_file) {
|
||||||
|
my $target_dir = catdir(($ENV{NETDISCO_HOME} || $ENV{HOME}), 'logs', 'snapshots');
|
||||||
|
make_path($target_dir);
|
||||||
|
my $target_file = catfile($target_dir, $device->ip);
|
||||||
|
debug "snapshot $device - saving snapshot to $target_file";
|
||||||
|
write_text($target_file, $frozen);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status->done(
|
||||||
|
sprintf "Snapshot data captured from %s", $device->ip);
|
||||||
|
});
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
# read in netdisco-mibs translation report and make an OID -> leafname map
|
||||||
|
sub getoidmap {
|
||||||
|
my ($device, $snmp) = @_;
|
||||||
|
debug "snapshot $device - loading netdisco-mibs object cache";
|
||||||
|
|
||||||
|
my $home = (setting('mibhome') || catdir(($ENV{NETDISCO_HOME} || $ENV{HOME}), 'netdisco-mibs'));
|
||||||
|
my @report = read_lines(catfile($home, qw(EXTRAS reports all_oids)), 'latin-1');
|
||||||
|
|
||||||
|
my %oidmap = ();
|
||||||
|
foreach my $line (@report) {
|
||||||
|
my ($oid, $qual_leaf, $rest) = split m/,/, $line;
|
||||||
|
next unless defined $oid and defined $qual_leaf;
|
||||||
|
my ($mib, $leaf) = split m/::/, $qual_leaf;
|
||||||
|
$oidmap{$oid} = $leaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug sprintf "snapshot $device - loaded %d objects from netdisco-mibs",
|
||||||
|
scalar keys %oidmap;
|
||||||
|
return %oidmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
# taken from SNMP::Info and adjusted to work on walks outside a single table
|
||||||
|
sub walker {
|
||||||
|
my ($device, $snmp, $base) = @_;
|
||||||
|
$base ||= '.1';
|
||||||
|
|
||||||
|
my $sess = $snmp->session();
|
||||||
|
return unless defined $sess;
|
||||||
|
|
||||||
|
my $REPEATERS = 20;
|
||||||
|
my $ver = $snmp->snmp_ver();
|
||||||
|
|
||||||
|
# We want the qualified leaf name so that we can
|
||||||
|
# specify the Module (MIB) in the case of private leaf naming
|
||||||
|
# conflicts. Example: ALTEON-TIGON-SWITCH-MIB::agSoftwareVersion
|
||||||
|
# and ALTEON-CHEETAH-SWITCH-MIB::agSoftwareVersion
|
||||||
|
# Third argument to translateObj specifies the Module prefix
|
||||||
|
|
||||||
|
my $qual_leaf = SNMP::translateObj($base,0,1) || '';
|
||||||
|
|
||||||
|
# We still want just the leaf since a SNMP get in the case of a
|
||||||
|
# partial fetch may strip the Module portion upon return. We need
|
||||||
|
# the match to make sure we didn't leave the table during getnext
|
||||||
|
# requests
|
||||||
|
|
||||||
|
my ($leaf) = $qual_leaf =~ /::(.+)$/;
|
||||||
|
|
||||||
|
# If we weren't able to translate, we'll only have an OID
|
||||||
|
$leaf = $base unless defined $leaf;
|
||||||
|
|
||||||
|
# debug "snapshot $device - $base translated as $qual_leaf";
|
||||||
|
my $var = SNMP::Varbind->new( [$qual_leaf] );
|
||||||
|
|
||||||
|
# So devices speaking SNMP v.1 are not supposed to give out
|
||||||
|
# data from SNMP2, but most do. Net-SNMP, being very precise
|
||||||
|
# will tell you that the SNMP OID doesn't exist for the device.
|
||||||
|
# They have a flag RetryNoSuch that is used for get() operations,
|
||||||
|
# but not for getnext(). We set this flag normally, and if we're
|
||||||
|
# using V1, let's try and fetch the data even if we get one of those.
|
||||||
|
|
||||||
|
my %localstore = ();
|
||||||
|
my $errornum = 0;
|
||||||
|
my %seen = ();
|
||||||
|
|
||||||
|
my $vars = [];
|
||||||
|
my $bulkwalk_no
|
||||||
|
= $snmp->can('bulkwalk_no') ? $snmp->bulkwalk_no() : 0;
|
||||||
|
my $bulkwalk_on = defined $snmp->{BulkWalk} ? $snmp->{BulkWalk} : 1;
|
||||||
|
my $can_bulkwalk = $bulkwalk_on && !$bulkwalk_no;
|
||||||
|
my $repeaters = $snmp->{BulkRepeaters} || $REPEATERS;
|
||||||
|
my $bulkwalk = $can_bulkwalk && $ver != 1;
|
||||||
|
my $loopdetect
|
||||||
|
= defined $snmp->{LoopDetect} ? $snmp->{LoopDetect} : 1;
|
||||||
|
|
||||||
|
debug "snapshot $device - starting walk from $base";
|
||||||
|
|
||||||
|
# Use BULKWALK if we can because its faster
|
||||||
|
if ( $bulkwalk && @$vars == 0 ) {
|
||||||
|
($vars) = $sess->bulkwalk( 0, $repeaters, $var );
|
||||||
|
if ( $sess->{ErrorNum} ) {
|
||||||
|
error "snapshot $device BULKWALK " . $sess->{ErrorStr};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( !$errornum ) {
|
||||||
|
if ($bulkwalk) {
|
||||||
|
$var = shift @$vars or last;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# GETNEXT instead of BULKWALK
|
||||||
|
# debug "snapshot $device GETNEXT $var";
|
||||||
|
$sess->getnext($var);
|
||||||
|
$errornum = $sess->{ErrorNum};
|
||||||
|
}
|
||||||
|
|
||||||
|
my $iid = $var->[1];
|
||||||
|
my $val = $var->[2];
|
||||||
|
my $oid = $var->[0] . (defined $iid ? ".${iid}" : '');
|
||||||
|
|
||||||
|
# debug "snapshot $device reading $oid";
|
||||||
|
# p $var;
|
||||||
|
|
||||||
|
unless ( defined $iid ) {
|
||||||
|
error "snapshot $device not here";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if last element, V2 devices may report ENDOFMIBVIEW even if
|
||||||
|
# instance or object doesn't exist.
|
||||||
|
if ( $val eq 'ENDOFMIBVIEW' ) {
|
||||||
|
debug "snapshot $device : ENDOFMIBVIEW";
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Similarly for SNMPv1 - noSuchName return results in both $iid
|
||||||
|
# and $val being empty strings.
|
||||||
|
if ( $val eq '' and $iid eq '' ) {
|
||||||
|
debug "snapshot $device : v1 noSuchName (1)";
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Another check for SNMPv1 - noSuchName return may results in an $oid
|
||||||
|
# we've already seen and $val an empty string. If we don't catch
|
||||||
|
# this here we erroneously report a loop below.
|
||||||
|
if ( defined $seen{$oid} and $seen{$oid} and $val eq '' ) {
|
||||||
|
debug "snapshot $device : v1 noSuchName (2)";
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($loopdetect) {
|
||||||
|
# Check to see if we've already seen this IID (looping)
|
||||||
|
if ( defined $seen{$oid} and $seen{$oid} ) {
|
||||||
|
error "Looping on: oid:$oid. ";
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$seen{$oid}++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $val eq 'NOSUCHOBJECT' ) {
|
||||||
|
error "snapshot $device : NOSUCHOBJECT";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ( $val eq 'NOSUCHINSTANCE' ) {
|
||||||
|
error "snapshot $device : NOSUCHINSTANCE";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# debug "snapshot $device - retreived $oid : $val";
|
||||||
|
$localstore{$oid} = $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug sprintf "snapshot $device - walked %d rows from $base",
|
||||||
|
scalar keys %localstore;
|
||||||
|
return %localstore;
|
||||||
|
}
|
||||||
|
|
||||||
|
true;
|
||||||
|
|
||||||
|
__DATA__
|
||||||
|
agg_ports
|
||||||
|
at_paddr
|
||||||
|
bgp_peer_addr
|
||||||
|
bp_index
|
||||||
|
c_cap
|
||||||
|
c_id
|
||||||
|
c_if
|
||||||
|
c_ip
|
||||||
|
c_platform
|
||||||
|
c_port
|
||||||
|
cd11_mac
|
||||||
|
cd11_port
|
||||||
|
cd11_rateset
|
||||||
|
cd11_rxbyte
|
||||||
|
cd11_rxpkt
|
||||||
|
cd11_sigqual
|
||||||
|
cd11_sigstrength
|
||||||
|
cd11_ssid
|
||||||
|
cd11_txbyte
|
||||||
|
cd11_txpkt
|
||||||
|
cd11_txrate
|
||||||
|
cd11_uptime
|
||||||
|
class
|
||||||
|
contact
|
||||||
|
docs_if_cmts_cm_status_inet_address
|
||||||
|
dot11_cur_tx_pwr_mw
|
||||||
|
e_class
|
||||||
|
e_descr
|
||||||
|
e_fru
|
||||||
|
e_fwver
|
||||||
|
e_hwver
|
||||||
|
e_index
|
||||||
|
e_model
|
||||||
|
e_name
|
||||||
|
e_parent
|
||||||
|
e_pos
|
||||||
|
e_serial
|
||||||
|
e_swver
|
||||||
|
e_type
|
||||||
|
eigrp_peers
|
||||||
|
fw_mac
|
||||||
|
fw_port
|
||||||
|
has_topo
|
||||||
|
i_80211channel
|
||||||
|
i_alias
|
||||||
|
i_description
|
||||||
|
i_duplex
|
||||||
|
i_duplex_admin
|
||||||
|
i_err_disable_cause
|
||||||
|
i_faststart_enabled
|
||||||
|
i_ignore
|
||||||
|
i_lastchange
|
||||||
|
i_mac
|
||||||
|
i_mtu
|
||||||
|
i_name
|
||||||
|
i_speed
|
||||||
|
i_speed_admin
|
||||||
|
i_speed_raw
|
||||||
|
i_ssidbcast
|
||||||
|
i_ssidlist
|
||||||
|
i_ssidmac
|
||||||
|
i_stp_state
|
||||||
|
i_type
|
||||||
|
i_up
|
||||||
|
i_up_admin
|
||||||
|
i_vlan
|
||||||
|
i_vlan_membership
|
||||||
|
i_vlan_membership_untagged
|
||||||
|
i_vlan_type
|
||||||
|
interfaces
|
||||||
|
ip_index
|
||||||
|
ip_netmask
|
||||||
|
ipv6_addr
|
||||||
|
ipv6_addr_prefixlength
|
||||||
|
ipv6_index
|
||||||
|
ipv6_n2p_mac
|
||||||
|
ipv6_type
|
||||||
|
isis_peers
|
||||||
|
lldp_ipv6
|
||||||
|
lldp_media_cap
|
||||||
|
lldp_rem_model
|
||||||
|
lldp_rem_serial
|
||||||
|
lldp_rem_sw_rev
|
||||||
|
lldp_rem_vendor
|
||||||
|
location
|
||||||
|
model
|
||||||
|
name
|
||||||
|
ospf_peer_id
|
||||||
|
ospf_peers
|
||||||
|
peth_port_admin
|
||||||
|
peth_port_class
|
||||||
|
peth_port_ifindex
|
||||||
|
peth_port_power
|
||||||
|
peth_port_status
|
||||||
|
peth_power_status
|
||||||
|
peth_power_watts
|
||||||
|
ports
|
||||||
|
qb_fw_vlan
|
||||||
|
serial
|
||||||
|
serial1
|
||||||
|
snmpEngineID
|
||||||
|
snmpEngineTime
|
||||||
|
snmp_comm
|
||||||
|
snmp_ver
|
||||||
|
v_index
|
||||||
|
v_name
|
||||||
|
vrf_name
|
||||||
|
vtp_d_name
|
||||||
|
vtp_version
|
||||||
+9
-6
@@ -92,6 +92,7 @@ web_plugins:
|
|||||||
- Device::Neighbors
|
- Device::Neighbors
|
||||||
- Device::Addresses
|
- Device::Addresses
|
||||||
- Device::Vlans
|
- Device::Vlans
|
||||||
|
- Device::SNMP
|
||||||
extra_web_plugins: []
|
extra_web_plugins: []
|
||||||
sidebar_defaults:
|
sidebar_defaults:
|
||||||
search_node:
|
search_node:
|
||||||
@@ -392,51 +393,53 @@ job_prio:
|
|||||||
|
|
||||||
worker_plugins:
|
worker_plugins:
|
||||||
- 'Arpnip'
|
- 'Arpnip'
|
||||||
|
- 'Arpnip::Hooks'
|
||||||
- 'Arpnip::Nodes'
|
- 'Arpnip::Nodes'
|
||||||
- 'Arpnip::Subnets'
|
- 'Arpnip::Subnets'
|
||||||
- 'Arpnip::Hooks'
|
|
||||||
- 'Arpwalk'
|
- 'Arpwalk'
|
||||||
- 'Contact'
|
- 'Contact'
|
||||||
- 'Delete'
|
- 'Delete'
|
||||||
- 'Discover'
|
- 'Discover'
|
||||||
- 'Discover::CanonicalIP'
|
- 'Discover::CanonicalIP'
|
||||||
- 'Discover::Entities'
|
- 'Discover::Entities'
|
||||||
|
- 'Discover::Hooks'
|
||||||
- 'Discover::Neighbors'
|
- 'Discover::Neighbors'
|
||||||
- 'Discover::Neighbors::Routed'
|
|
||||||
- 'Discover::Neighbors::DOCSIS'
|
- 'Discover::Neighbors::DOCSIS'
|
||||||
|
- 'Discover::Neighbors::Routed'
|
||||||
- 'Discover::PortPower'
|
- 'Discover::PortPower'
|
||||||
- 'Discover::PortProperties'
|
- 'Discover::PortProperties'
|
||||||
- 'Discover::Properties'
|
- 'Discover::Properties'
|
||||||
- 'Discover::VLANs'
|
- 'Discover::VLANs'
|
||||||
- 'Discover::Wireless'
|
- 'Discover::Wireless'
|
||||||
- 'Discover::WithNodes'
|
- 'Discover::WithNodes'
|
||||||
- 'Discover::Hooks'
|
|
||||||
- 'DiscoverAll'
|
- 'DiscoverAll'
|
||||||
- 'DumpConfig'
|
- 'DumpConfig'
|
||||||
- 'Expire'
|
- 'Expire'
|
||||||
- 'ExpireNodes'
|
- 'ExpireNodes'
|
||||||
|
- 'GetAPIKey'
|
||||||
- 'Graph'
|
- 'Graph'
|
||||||
- 'Hook'
|
- 'Hook'
|
||||||
- 'Hook::Exec'
|
- 'Hook::Exec'
|
||||||
- 'Hook::HTTP'
|
- 'Hook::HTTP'
|
||||||
|
- 'LoadMIBs'
|
||||||
- 'Location'
|
- 'Location'
|
||||||
- 'Macsuck'
|
- 'Macsuck'
|
||||||
|
- 'Macsuck::Hooks'
|
||||||
- 'Macsuck::Nodes'
|
- 'Macsuck::Nodes'
|
||||||
- 'Macsuck::WirelessNodes'
|
- 'Macsuck::WirelessNodes'
|
||||||
- 'Macsuck::Hooks'
|
|
||||||
- 'Macwalk'
|
- 'Macwalk'
|
||||||
- 'MakeRancidConf'
|
- 'MakeRancidConf'
|
||||||
- 'NodeMonitor'
|
|
||||||
- 'Nbtstat'
|
- 'Nbtstat'
|
||||||
- 'Nbtstat::Core'
|
- 'Nbtstat::Core'
|
||||||
- 'Nbtwalk'
|
- 'Nbtwalk'
|
||||||
|
- 'NodeMonitor'
|
||||||
- 'PortControl'
|
- 'PortControl'
|
||||||
- 'PortName'
|
- 'PortName'
|
||||||
- 'Power'
|
- 'Power'
|
||||||
- 'Psql'
|
- 'Psql'
|
||||||
- 'Renumber'
|
- 'Renumber'
|
||||||
- 'GetAPIKey'
|
|
||||||
- 'Show'
|
- 'Show'
|
||||||
|
- 'Snapshot'
|
||||||
- 'Stats'
|
- 'Stats'
|
||||||
- 'Vlan'
|
- 'Vlan'
|
||||||
- 'Vlan::Core'
|
- 'Vlan::Core'
|
||||||
|
|||||||
@@ -61,6 +61,17 @@ div.content > div.tab-content table.nd_floatinghead thead {
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* jstree scrollable */
|
||||||
|
|
||||||
|
.nd_scrollable {
|
||||||
|
height: 85vh;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#snmpPartialSearch {
|
||||||
|
margin-top: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
/* fake looks for form submit buttons embedded in bootstrap dropdowns */
|
/* fake looks for form submit buttons embedded in bootstrap dropdowns */
|
||||||
.nd_btn-link {
|
.nd_btn-link {
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
BIN
Binary file not shown.
+2377
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 132 KiB |
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+2410
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 137 KiB |
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+2725
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 147 KiB |
BIN
Binary file not shown.
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,9 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE device ADD COLUMN "is_pseudo" boolean DEFAULT false;
|
||||||
|
|
||||||
|
UPDATE device SET is_pseudo = false;
|
||||||
|
|
||||||
|
UPDATE device SET is_pseudo = true WHERE vendor = 'netdisco';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
CREATE TABLE device_snapshot (
|
||||||
|
"ip" "inet",
|
||||||
|
"cache" "text",
|
||||||
|
PRIMARY KEY ("ip")
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
CREATE TABLE device_browser (
|
||||||
|
"ip" "inet" NOT NULL,
|
||||||
|
"oid" "text" NOT NULL,
|
||||||
|
"oid_parts" integer[] NOT NULL,
|
||||||
|
"leaf" "text" NOT NULL,
|
||||||
|
"munge" "text",
|
||||||
|
"value" "text",
|
||||||
|
PRIMARY KEY ("ip", "oid")
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_device_browser_ip_leaf ON device_browser(ip, leaf);
|
||||||
|
|
||||||
|
CREATE INDEX idx_device_browser_oid__pattern on device_browser (oid text_pattern_ops);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
CREATE TABLE snmp_object (
|
||||||
|
"oid" "text" NOT NULL,
|
||||||
|
"oid_parts" integer[] NOT NULL,
|
||||||
|
"mib" "text" NOT NULL,
|
||||||
|
"leaf" "text" NOT NULL,
|
||||||
|
"type" "text",
|
||||||
|
"access" "text",
|
||||||
|
"index" text[] DEFAULT '{}',
|
||||||
|
PRIMARY KEY ("oid")
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_snmp_object_oid__pattern on snmp_object (oid text_pattern_ops);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -33,8 +33,8 @@
|
|||||||
<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">
|
<td class="nd_center-cell">
|
||||||
<span class="badge"> </span><span class="badge"> </span>
|
<span class="badge[% ' badge-success' IF row.layers.substr(7,1) %]">[% row.layers.substr(7,1) ? '1' : ' ' | none %]</span><span class="badge[% ' badge-success' IF row.layers.substr(6,1) %]">[% row.layers.substr(6,1) ? '2' : ' ' | none %]</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>
|
<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[% ' badge-success' IF row.layers.substr(4,1) %]">[% row.layers.substr(4,1) ? '4' : ' ' | none %]</span><span class="badge[% ' badge-success' IF row.layers.substr(3,1) %]">[% row.layers.substr(3,1) ? '5' : ' ' | none %]</span><span class="badge[% ' badge-success' IF row.layers.substr(2,1) %]">[% row.layers.substr(2,1) ? '6' : ' ' | none %]</span><span class="badge[% ' badge-success' IF row.layers.substr(1,1) %]">[% row.layers.substr(1,1) ? '7' : ' ' | none %]</span>
|
||||||
<input data-form="update" name="layers" type="hidden" value="[% row.layers | html_entity %]">
|
<input data-form="update" name="layers" type="hidden" value="[% row.layers | html_entity %]">
|
||||||
</td>
|
</td>
|
||||||
<td class="nd_center-cell">
|
<td class="nd_center-cell">
|
||||||
|
|||||||
@@ -180,6 +180,24 @@
|
|||||||
<input type="hidden" data-form="nbtstat" value="[% d.ip | html_entity %]" name="device"/>
|
<input type="hidden" data-form="nbtstat" value="[% d.ip | html_entity %]" name="device"/>
|
||||||
<button class="btn btn-info btn-small nd_adminbutton" name="nbtstat">NBTstat</button>
|
<button class="btn btn-info btn-small nd_adminbutton" name="nbtstat">NBTstat</button>
|
||||||
|
|
||||||
|
[% IF NOT d.is_pseudo %]
|
||||||
|
<span class="dropdown">
|
||||||
|
<button class="nd_snap_btn btn [% d.has_snapshot ? 'btn-success' : 'btn-info' %] btn-small dropdown-toggle" type="button" id="snapshotmenu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||||
|
Snapshot
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="snapshotmenu">
|
||||||
|
<input type="hidden" data-form="snapshot_req" value="[% d.ip | html_entity %]" name="device"/>
|
||||||
|
<li><a href="#" class="nd_adminbutton" name="snapshot_req"><i class="icon-edit"></i> Create</a></li>
|
||||||
|
|
||||||
|
<li class='nd_snap_func [% 'disabled' UNLESS d.has_snapshot %]'><a href="[% uri_for('/ajax/content/admin/snapshot_get') | none %]?device=[% d.ip | uri %]"><i class="icon-download-alt"></i> Download</a></li>
|
||||||
|
|
||||||
|
<input type="hidden" data-form="snapshot_del" value="[% d.ip | html_entity %]" name="device"/>
|
||||||
|
<li class='nd_snap_func [% 'disabled' UNLESS d.has_snapshot %]'><a href="#" class="nd_adminbutton" name="snapshot_del"><i class="icon-trash"></i> Delete</a></li>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
[% END %]
|
||||||
|
|
||||||
<button class="btn btn-danger btn-small pull-right"
|
<button class="btn btn-danger btn-small pull-right"
|
||||||
data-toggle="modal" data-target="#nd_devdel" type="button">Delete</button>
|
data-toggle="modal" data-target="#nd_devdel" type="button">Delete</button>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="span5">
|
||||||
|
<div id="jstree" class="nd_scrollable"></div>
|
||||||
|
</div>
|
||||||
|
<div id="snmpnodecontainer" class="span8">
|
||||||
|
<form id="searchTreeForm" class="form-inline col-md-4">
|
||||||
|
<span class="form-group">
|
||||||
|
<input id="treeSearchText" type="text" class="form-control" size="30" required placeholder="Search for label or OID">
|
||||||
|
<label class="checkbox-inline"
|
||||||
|
rel="tooltip" data-placement="top" data-offset="5" data-title="Anchored to the beginning">
|
||||||
|
<input type="checkbox" id="snmpPartialSearch" value="partial"> Partial </input>
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
<button type="submit" class="btn btn-default">Search</button>
|
||||||
|
</form>
|
||||||
|
<div id="node">
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th scope="row" class="span1">OID</th>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Module</th>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Leaf</th>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Type</th>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Munge</th>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Access</th>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Index</th>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Value</th>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function () {
|
||||||
|
var jstree_search_callback = function(str, node) {
|
||||||
|
var pattern = str.toLowerCase();
|
||||||
|
var name = node.text.toLowerCase();
|
||||||
|
var oid = node.id.toLowerCase();
|
||||||
|
|
||||||
|
if (document.getElementById('snmpPartialSearch').checked) {
|
||||||
|
if ((name.indexOf(pattern) == 0) || (oid.indexOf(pattern) == 0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ((name.indexOf(pattern + ' ') == 0) || (oid == pattern)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
$('#jstree').jstree({
|
||||||
|
'core': {
|
||||||
|
'multiple' : false,
|
||||||
|
'themes': {
|
||||||
|
'name': 'proton',
|
||||||
|
'responsive': true
|
||||||
|
},
|
||||||
|
'data' : {
|
||||||
|
'url' : function (node) {
|
||||||
|
return ('[% uri_base | none %]/ajax/data/device/[% device %]/snmptree/'
|
||||||
|
+ (node.id === '#' ? '.1.3.6.1' : node.id) + '?recurse=on');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'plugins': ['search'],
|
||||||
|
'search': {
|
||||||
|
'ajax' : {
|
||||||
|
'url' : '[% uri_base | none %]/ajax/data/device/[% device %]/snmpnodesearch',
|
||||||
|
'beforeSend' : function(jqXHR, settings) {
|
||||||
|
settings.url = settings.url + '&excludeself=on';
|
||||||
|
if (document.getElementById('snmpPartialSearch').checked) {
|
||||||
|
settings.url = settings.url + '&partial=on';
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'search_callback' : jstree_search_callback
|
||||||
|
},
|
||||||
|
});
|
||||||
|
$('#snmpnodecontainer').on("change", "#munger", function(e, data) {
|
||||||
|
var ary = $('#jstree').jstree('get_selected');
|
||||||
|
$('#node').load('[% uri_base | none %]/ajax/content/device/[% device %]/snmpnode/'
|
||||||
|
+ ary[0] + '?munge=' + $('#munger').find(":selected").text());
|
||||||
|
});
|
||||||
|
$('#jstree').on("changed.jstree", function (e, data) {
|
||||||
|
if (data.selected && data.selected != "#") {
|
||||||
|
$('#node').load('[% uri_base | none %]/ajax/content/device/[% device %]/snmpnode/' + data.selected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('#jstree').on("search.jstree", function (e, data) {
|
||||||
|
if (data.res.length) {
|
||||||
|
document.getElementById( data.res[0] + '_anchor' ).scrollIntoView();
|
||||||
|
$('#node').load('[% uri_base | none %]/ajax/content/device/[% device %]/snmpnode/' + data.res[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#searchTreeForm").submit(function(e) {
|
||||||
|
$("#jstree").jstree("search", $("#treeSearchText").val());
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
$('#treeSearchText').autocomplete({
|
||||||
|
source: uri_base + '/ajax/data/device/[% device %]/typeahead'
|
||||||
|
,delay: 150
|
||||||
|
,minLength: 2
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<table class="table table-bordered">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th scope="row" class="span1">OID</th>
|
||||||
|
<td>[% node.snmp_object.oid %]</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Module</th>
|
||||||
|
<td>[% node.snmp_object.mib %]</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Leaf</th>
|
||||||
|
<td>[% node.snmp_object.leaf %]</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Type</th>
|
||||||
|
<td>[% node.snmp_object.type %]</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Munge</th>
|
||||||
|
<td>
|
||||||
|
[% IF node.value %]
|
||||||
|
<select name="munger" id="munger">
|
||||||
|
[% UNLESS munge %]<option value="" selected disabled hidden>None applied</option>[% END %]
|
||||||
|
[% FOREACH m IN mungers %]
|
||||||
|
<option [% 'selected' IF m == munge %] value="[% m %]">[% m %]</option>
|
||||||
|
[% END %]
|
||||||
|
</select>
|
||||||
|
[% END %]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Access</th>
|
||||||
|
<td>[% node.snmp_object.access %]</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Index</th>
|
||||||
|
<td>
|
||||||
|
[% IF node.snmp_object.index.size > 0 %]
|
||||||
|
<table class="table table-condensed table-bordered">
|
||||||
|
[% FOREACH idx IN node.snmp_object.index %]
|
||||||
|
<tr><td>[% idx %]</td></tr>
|
||||||
|
[% END %]
|
||||||
|
</table>
|
||||||
|
[% END %]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Value</th>
|
||||||
|
<td>[% IF node.value %]<pre id="snmp_node_value">[% node.value %]</pre>[% END %]</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
@@ -36,10 +36,11 @@
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<ul id="nd_search-results" class="nav nav-tabs">
|
<ul id="nd_search-results" class="nav nav-tabs">
|
||||||
[% FOREACH tab IN settings._device_tabs %]
|
[% FOREACH tab IN settings._device_tabs %]
|
||||||
|
[% NEXT UNLESS tab.render_if %]
|
||||||
<li[% ' class="active"' IF params.tab == tab.tag %]><a id="[% tab.tag | html_entity %]_link" href="#[% tab.tag | html_entity %]_pane">[% tab.label | html_entity %]</a></li>
|
<li[% ' class="active"' IF params.tab == tab.tag %]><a id="[% tab.tag | html_entity %]_link" href="#[% tab.tag | html_entity %]_pane">[% tab.label | html_entity %]</a></li>
|
||||||
[% END %]
|
[% END %]
|
||||||
<span id="nd_device-name">
|
<span id="nd_device-name">
|
||||||
[% display_name | html_entity %]
|
[% IF is_pseudo %]<span class="badge badge-warning">[% END %][% display_name | html_entity %][% IF is_pseudo %]</span>[% END %]
|
||||||
<a id="nd_csv-download" href="#" download="netdisco.csv">
|
<a id="nd_csv-download" href="#" download="netdisco.csv">
|
||||||
<i id="nd_csv-download-icon" class="text-info icon-file-text-alt icon-large"
|
<i id="nd_csv-download-icon" class="text-info icon-file-text-alt icon-large"
|
||||||
rel="tooltip" data-placement="left" data-offset="5" data-title="Download as CSV"></i></a>
|
rel="tooltip" data-placement="left" data-offset="5" data-title="Download as CSV"></i></a>
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
[% FOREACH tab IN settings._device_tabs %]
|
[% FOREACH tab IN settings._device_tabs %]
|
||||||
|
[% NEXT UNLESS tab.render_if %]
|
||||||
<div class="tab-pane[% ' active' IF params.tab == tab.tag %]" id="[% tab.tag | html_entity %]_pane"></div>
|
<div class="tab-pane[% ' active' IF params.tab == tab.tag %]" id="[% tab.tag | html_entity %]_pane"></div>
|
||||||
[% END %]
|
[% END %]
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -169,6 +169,11 @@
|
|||||||
,success: function() {
|
,success: function() {
|
||||||
if (mode != 'delete') {
|
if (mode != 'delete') {
|
||||||
toastr.info('Requested '+ mode +' for device '+ tr.data('for-device'));
|
toastr.info('Requested '+ mode +' for device '+ tr.data('for-device'));
|
||||||
|
if (mode == 'snapshot_del') {
|
||||||
|
$('.nd_snap_btn').toggleClass('btn-success');
|
||||||
|
$('.nd_snap_btn').toggleClass('btn-info');
|
||||||
|
$('.nd_snap_func').toggleClass('disabled');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
toastr.success('Deleted device '+ tr.data('for-device'));
|
toastr.success('Deleted device '+ tr.data('for-device'));
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
<script type="text/javascript" src="[% uri_base | none %]/javascripts/dataTables.bootstrap.js"></script>
|
<script type="text/javascript" src="[% uri_base | none %]/javascripts/dataTables.bootstrap.js"></script>
|
||||||
<script type="text/javascript" src="[% uri_base | none %]/javascripts/dataTables.ip-address-detect.js"></script>
|
<script type="text/javascript" src="[% uri_base | none %]/javascripts/dataTables.ip-address-detect.js"></script>
|
||||||
<script type="text/javascript" src="[% uri_base | none %]/javascripts/dataTables.ip-address-sort.js"></script>
|
<script type="text/javascript" src="[% uri_base | none %]/javascripts/dataTables.ip-address-sort.js"></script>
|
||||||
|
<script type="text/javascript" src="[% uri_base | none %]/javascripts/jstree/jstree.min.js"></script>
|
||||||
<script type="text/javascript" src="[% uri_base | none %]/javascripts/he.js"></script>
|
<script type="text/javascript" src="[% uri_base | none %]/javascripts/he.js"></script>
|
||||||
<script type="text/javascript" src="[% uri_base | none %]/javascripts/natural.js"></script>
|
<script type="text/javascript" src="[% uri_base | none %]/javascripts/natural.js"></script>
|
||||||
<script type="text/javascript" src="[% uri_base | none %]/javascripts/portsort.js"></script>
|
<script type="text/javascript" src="[% uri_base | none %]/javascripts/portsort.js"></script>
|
||||||
@@ -61,6 +62,7 @@
|
|||||||
<link rel="stylesheet" href="[% uri_base | none %]/css/d3-force-network-chart.css"/>
|
<link rel="stylesheet" href="[% uri_base | none %]/css/d3-force-network-chart.css"/>
|
||||||
<link rel="stylesheet" href="[% uri_base | none %]/css/netdisco.css"/>
|
<link rel="stylesheet" href="[% uri_base | none %]/css/netdisco.css"/>
|
||||||
<link rel="stylesheet" href="[% uri_base | none %]/css/bootstrap-tree.css"/>
|
<link rel="stylesheet" href="[% uri_base | none %]/css/bootstrap-tree.css"/>
|
||||||
|
<link rel="stylesheet" href="[% uri_base | none %]/javascripts/jstree/themes/proton/style.min.css"/>
|
||||||
<link rel="stylesheet" href="[% uri_base | none %]/css/daterangepicker-bs2.css"/>
|
<link rel="stylesheet" href="[% uri_base | none %]/css/daterangepicker-bs2.css"/>
|
||||||
<link rel="stylesheet" href="[% uri_base | none %]/css/dataTables.bootstrap.css"/>
|
<link rel="stylesheet" href="[% uri_base | none %]/css/dataTables.bootstrap.css"/>
|
||||||
<link rel="stylesheet" href="[% uri_base | none %]/css/nd_print.css" media="print"/>
|
<link rel="stylesheet" href="[% uri_base | none %]/css/nd_print.css" media="print"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user