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:
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -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
|
||||||
|
|||||||
4
Build.PL
4
Build.PL
@@ -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',
|
||||||
|
|||||||
33
MANIFEST
33
MANIFEST
@@ -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),
|
||||||
|
|||||||
50
lib/App/Netdisco/DB/Result/DeviceBrowser.pm
Normal file
50
lib/App/Netdisco/DB/Result/DeviceBrowser.pm
Normal file
@@ -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;
|
||||||
27
lib/App/Netdisco/DB/Result/DeviceSnapshot.pm
Normal file
27
lib/App/Netdisco/DB/Result/DeviceSnapshot.pm
Normal file
@@ -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;
|
||||||
27
lib/App/Netdisco/DB/Result/SNMPObject.pm
Normal file
27
lib/App/Netdisco/DB/Result/SNMPObject.pm
Normal file
@@ -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;
|
||||||
34
lib/App/Netdisco/DB/Result/Virtual/FilteredSNMPObject.pm
Normal file
34
lib/App/Netdisco/DB/Result/Virtual/FilteredSNMPObject.pm
Normal file
@@ -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;
|
||||||
36
lib/App/Netdisco/DB/Result/Virtual/OidChildren.pm
Normal file
36
lib/App/Netdisco/DB/Result/Virtual/OidChildren.pm
Normal file
@@ -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
|
||||||
|
|
||||||
|
|||||||
28
lib/App/Netdisco/DB/ResultSet/DeviceBrowser.pm
Normal file
28
lib/App/Netdisco/DB/ResultSet/DeviceBrowser.pm
Normal file
@@ -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,9 +17,15 @@ 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
|
||||||
= schema('netdisco')->resultset('DevicePower')
|
= schema('netdisco')->resultset('DevicePower')
|
||||||
->search( { 'me.ip' => $device->ip } )->with_poestats->hri->all;
|
->search( { 'me.ip' => $device->ip } )->with_poestats->hri->all;
|
||||||
|
|||||||
175
lib/App/Netdisco/Web/Plugin/Device/SNMP.pm
Normal file
175
lib/App/Netdisco/Web/Plugin/Device/SNMP.pm
Normal file
@@ -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;
|
||||||
|
|||||||
50
lib/App/Netdisco/Worker/Plugin/LoadMIBs.pm
Normal file
50
lib/App/Netdisco/Worker/Plugin/LoadMIBs.pm
Normal file
@@ -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(
|
||||||
|
|||||||
433
lib/App/Netdisco/Worker/Plugin/Snapshot.pm
Normal file
433
lib/App/Netdisco/Worker/Plugin/Snapshot.pm
Normal file
@@ -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
|
||||||
@@ -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;
|
||||||
|
|||||||
6
share/public/javascripts/jstree/jstree.min.js
vendored
Normal file
6
share/public/javascripts/jstree/jstree.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
share/public/javascripts/jstree/themes/proton/30px.png
Normal file
BIN
share/public/javascripts/jstree/themes/proton/30px.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
BIN
share/public/javascripts/jstree/themes/proton/32px.png
Normal file
BIN
share/public/javascripts/jstree/themes/proton/32px.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 132 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 137 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 147 KiB |
Binary file not shown.
Binary file not shown.
1122
share/public/javascripts/jstree/themes/proton/style.css
Normal file
1122
share/public/javascripts/jstree/themes/proton/style.css
Normal file
File diff suppressed because it is too large
Load Diff
1
share/public/javascripts/jstree/themes/proton/style.min.css
vendored
Normal file
1
share/public/javascripts/jstree/themes/proton/style.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
share/public/javascripts/jstree/themes/proton/throbber.gif
Normal file
BIN
share/public/javascripts/jstree/themes/proton/throbber.gif
Normal file
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;
|
||||||
17
share/schema_versions/App-Netdisco-DB-68-69-PostgreSQL.sql
Normal file
17
share/schema_versions/App-Netdisco-DB-68-69-PostgreSQL.sql
Normal file
@@ -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;
|
||||||
16
share/schema_versions/App-Netdisco-DB-69-70-PostgreSQL.sql
Normal file
16
share/schema_versions/App-Netdisco-DB-69-70-PostgreSQL.sql
Normal file
@@ -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>
|
||||||
|
|
||||||
|
|||||||
132
share/views/ajax/device/snmp.tt
Normal file
132
share/views/ajax/device/snmp.tt
Normal file
@@ -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>
|
||||||
53
share/views/ajax/device/snmpnode.tt
Normal file
53
share/views/ajax/device/snmpnode.tt
Normal file
@@ -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