* 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
		
			
				
	
	
		
			272 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			272 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| package App::Netdisco::Web::Plugin;
 | |
| 
 | |
| use Dancer ':syntax';
 | |
| use Dancer::Plugin;
 | |
| use Dancer::Plugin::Swagger;
 | |
| use Dancer::Plugin::Auth::Extensible;
 | |
| 
 | |
| use Path::Class 'dir';
 | |
| 
 | |
| set(
 | |
|   '_additional_css'         => [],
 | |
|   '_additional_javascript'  => [],
 | |
|   '_extra_device_port_cols' => [],
 | |
|   '_extra_device_details'   => [],
 | |
|   '_navbar_items' => [],
 | |
|   '_search_tabs'  => [],
 | |
|   '_device_tabs'  => [],
 | |
|   '_admin_tasks'  => {},
 | |
|   '_admin_order'  => [],
 | |
|   '_reports_menu' => {},
 | |
|   '_reports' => {},
 | |
|   '_report_order' => [qw/Device Port IP Node VLAN Network Wireless/, 'My Reports'],
 | |
| );
 | |
| 
 | |
| # this is what Dancer::Template::TemplateToolkit does by default
 | |
| config->{engines}->{netdisco_template_toolkit}->{INCLUDE_PATH} ||= [ setting('views') ];
 | |
| 
 | |
| register 'register_template_path' => sub {
 | |
|   my ($self, $path) = plugin_args(@_);
 | |
| 
 | |
|   if (!$path) {
 | |
|       return error "bad template path to register_template_paths";
 | |
|   }
 | |
| 
 | |
|   unshift @{ config->{engines}->{netdisco_template_toolkit}->{INCLUDE_PATH} },
 | |
|        dir($path, 'views')->stringify;
 | |
| };
 | |
| 
 | |
| sub _register_include {
 | |
|   my ($type, $plugin) = @_;
 | |
| 
 | |
|   if (!$type) {
 | |
|       return error "bad type to _register_include";
 | |
|   }
 | |
| 
 | |
|   if (!$plugin) {
 | |
|       return error "bad plugin name to register_$type";
 | |
|   }
 | |
| 
 | |
|   push @{ setting("_additional_$type") }, $plugin;
 | |
| }
 | |
| 
 | |
| register 'register_css' => sub {
 | |
|   my ($self, $plugin) = plugin_args(@_);
 | |
|   _register_include('css', $plugin);
 | |
| };
 | |
| 
 | |
| register 'register_javascript' => sub {
 | |
|   my ($self, $plugin) = plugin_args(@_);
 | |
|   _register_include('javascript', $plugin);
 | |
| };
 | |
| 
 | |
| register 'register_device_port_column' => sub {
 | |
|   my ($self, $config) = plugin_args(@_);
 | |
|   $config->{default} ||= '';
 | |
|   $config->{position} ||= 'right';
 | |
| 
 | |
|   if (!$config->{name} or !$config->{label}) {
 | |
|       return error "bad config to register_device_port_column";
 | |
|   }
 | |
| 
 | |
|   foreach my $item (@{ setting('_extra_device_port_cols') }) {
 | |
|       if ($item->{name} eq $config->{name}) {
 | |
|           $item = $config;
 | |
|           return;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   push @{ setting('_extra_device_port_cols') }, $config;
 | |
| };
 | |
| 
 | |
| register 'register_device_details' => sub {
 | |
|   my ($self, $config) = plugin_args(@_);
 | |
| 
 | |
|   if (!$config->{name} or !$config->{label}) {
 | |
|       return error "bad config to register_device_details";
 | |
|   }
 | |
| 
 | |
|   foreach my $item (@{ setting('_extra_device_details') }) {
 | |
|       if ($item->{name} eq $config->{name}) {
 | |
|           $item = $config;
 | |
|           return;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   push @{ setting('_extra_device_details') }, $config;
 | |
| };
 | |
| 
 | |
| register 'register_navbar_item' => sub {
 | |
|   my ($self, $config) = plugin_args(@_);
 | |
| 
 | |
|   if (!$config->{tag}
 | |
|       or !$config->{path}
 | |
|       or !$config->{label}) {
 | |
| 
 | |
|       return error "bad config to register_navbar_item";
 | |
|   }
 | |
| 
 | |
|   foreach my $item (@{ setting('_navbar_items') }) {
 | |
|       if ($item->{tag} eq $config->{tag}) {
 | |
|           $item = $config;
 | |
|           return;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   push @{ setting('_navbar_items') }, $config;
 | |
| };
 | |
| 
 | |
| register 'register_admin_task' => sub {
 | |
|   my ($self, $config) = plugin_args(@_);
 | |
| 
 | |
|   if (!$config->{tag}
 | |
|       or !$config->{label}) {
 | |
| 
 | |
|       return error "bad config to register_admin_task";
 | |
|   }
 | |
| 
 | |
|   push @{ setting('_admin_order') }, $config->{tag};
 | |
|   setting('_admin_tasks')->{ $config->{tag} } = $config;
 | |
| };
 | |
| 
 | |
| sub _register_tab {
 | |
|   my ($nav, $config) = @_;
 | |
|   my $stash = setting("_${nav}_tabs");
 | |
| 
 | |
|   if (!$config->{tag}
 | |
|       or !$config->{label}) {
 | |
| 
 | |
|       return error "bad config to register_${nav}_item";
 | |
|   }
 | |
| 
 | |
|   foreach my $item (@{ $stash }) {
 | |
|       if ($item->{tag} eq $config->{tag}) {
 | |
|           $item = $config;
 | |
|           return;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   push @{ $stash }, $config;
 | |
| }
 | |
| 
 | |
| register 'register_search_tab' => sub {
 | |
|   my ($self, $config) = plugin_args(@_);
 | |
|   _register_tab('search', $config);
 | |
| 
 | |
|   if ($config->{api_endpoint}) {
 | |
|       my $tag = $config->{tag};
 | |
|       swagger_path {
 | |
|         tags => ['Search'],
 | |
|         path => setting('api_base')."/search/$tag",
 | |
|         description => $config->{label} .' Search',
 | |
|         parameters  => $config->{api_parameters},
 | |
|         responses =>
 | |
|           ($config->{api_responses} || { default => {} }),
 | |
|       }, get "/api/v1/search/$tag" => require_role api => sub {
 | |
|         forward "/ajax/content/search/$tag";
 | |
|       };
 | |
|   }
 | |
| };
 | |
| 
 | |
| register 'register_device_tab' => sub {
 | |
|   my ($self, $config) = plugin_args(@_);
 | |
|   $config->{render_if} ||= sub { true };
 | |
|   _register_tab('device', $config);
 | |
| };
 | |
| 
 | |
| register 'register_report' => sub {
 | |
|   my ($self, $config) = plugin_args(@_);
 | |
|   my @categories = @{ setting('_report_order') };
 | |
| 
 | |
|   if (!$config->{category}
 | |
|       or !$config->{tag}
 | |
|       or !$config->{label}
 | |
|       or 0 == scalar grep {$config->{category} eq $_} @categories) {
 | |
| 
 | |
|       return error "bad config to register_report";
 | |
|   }
 | |
| 
 | |
|   if (0 == scalar grep {$_ eq $config->{tag}}
 | |
|                        @{setting('_reports_menu')->{ $config->{category} }}) {
 | |
|       push @{setting('_reports_menu')->{ $config->{category} }}, $config->{tag};
 | |
|   }
 | |
| 
 | |
|   foreach my $tag (@{setting('_reports_menu')->{ $config->{category} }}) {
 | |
|       if ($config->{tag} eq $tag) {
 | |
|           setting('_reports')->{$tag} = $config;
 | |
| 
 | |
|           if ($config->{api_endpoint}) {
 | |
|               (my $category_path = lc $config->{category}) =~ s/ /-/g;
 | |
|               swagger_path {
 | |
|                 tags => ['Reports'],
 | |
|                 path => setting('api_base')."/report/$category_path/$tag",
 | |
|                 description => $config->{label} .' Report',
 | |
|                 parameters =>
 | |
|                   ($config->{api_parameters} ||
 | |
|                   ($config->{bind_params} ? [map { $_ => {} } @{ $config->{bind_params} }] : [])),
 | |
|                 responses => 
 | |
|                   ($config->{api_responses} || { default => {} }),
 | |
|               }, get "/api/v1/report/$category_path/$tag" => require_role api => sub {
 | |
|                 forward "/ajax/content/report/$tag";
 | |
|               };
 | |
|           }
 | |
| 
 | |
|           foreach my $rconfig (@{setting('reports')}) {
 | |
|               if ($rconfig->{tag} eq $tag) {
 | |
|                   setting('_reports')->{$tag}->{'rconfig'} = $rconfig;
 | |
|                   last;
 | |
|               }
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| };
 | |
| 
 | |
| register_plugin;
 | |
| true;
 | |
| 
 | |
| =head1 NAME
 | |
| 
 | |
| App::Netdisco::Web::Plugin - Netdisco Web UI components
 | |
| 
 | |
| =head1 Introduction
 | |
| 
 | |
| L<App::Netdisco>'s plugin system allows you more control of what Netdisco
 | |
| components are displayed in the web interface. Plugins can be distributed
 | |
| independently from Netdisco and are a better alternative to source code
 | |
| patches.
 | |
| 
 | |
| The following web interface components are implemented as plugins:
 | |
| 
 | |
| =over 4
 | |
| 
 | |
| =item *
 | |
| 
 | |
| Navigation Bar items (e.g. Inventory link)
 | |
| 
 | |
| =item *
 | |
| 
 | |
| Tabs for Search and Device pages
 | |
| 
 | |
| =item *
 | |
| 
 | |
| Reports (pre-canned searches)
 | |
| 
 | |
| =item *
 | |
| 
 | |
| Additional Device Port Columns
 | |
| 
 | |
| =item *
 | |
| 
 | |
| Additional Device Details
 | |
| 
 | |
| =item *
 | |
| 
 | |
| Admin Menu function (job control, manual topology, pseudo devices)
 | |
| 
 | |
| =back
 | |
| 
 | |
| See L<https://github.com/netdisco/netdisco/wiki/Web-Plugins> for details.
 | |
| 
 | |
| =cut
 | |
| 
 |