App::Netdisco::Manual::WritingWorkers - Developer Documentation on Worker Plugins
App::Netdisco's plugin system allows users to write workers to gather information from network devices using different transports and store results in the database.
For example, transports might be SNMP, SSH, or HTTPS. Workers might be combining those transports with application protocols such as SNMP, NETCONF (OpenConfig with XML), RESTCONF (OpenConfig with JSON), eAPI, or even CLI scraping. The combination of transport and protocol is known as a driver.
Workers can be restricted to certain vendor platforms using familiar ACL syntax. They are also attached to specific actions in Netdisco's backend operation (discover, macsuck, etc).
See App::Netdisco::Worker::Plugin for more information about worker plugins.
A worker is Perl code which is run. Therefore it can do anything you like, but typically it will make a connection to a device, gather some data, and store it in Netdisco's database.
App::Netdisco plugins must load the App::Netdisco::Worker::Plugin module. This exports a helper subroutine to register the worker. Here's the boilerplate code for our example plugin module:
package App::Netdisco::Worker::Plugin::Discover::Wireless::UniFi; use Dancer ':syntax'; use App::Netdisco::Worker::Plugin; use aliased 'App::Netdisco::Worker::Status'; # worker registration code goes here, ** see below ** true;
Use the register_worker helper from App::Netdisco::Worker::Plugin to register a worker:
register_worker
register_worker( $coderef ); # or register_worker( \%workerconf, $coderef );
For example (using the second form):
register_worker({ driver => 'unifiapi', }, sub { "worker code here" });
The %workerconf hashref is optional, and described below. The $coderef is the main body of your worker. Your worker is run in a Try::Tiny statement to catch errors, and passed the following arguments:
%workerconf
$coderef
$coderef->($job, \%workerconf);
The $job is an instance of App::Netdisco::Backend::Job. Note that this class has a device slot which may be filled, depending on the action, and if the device is not yet discovered then the row will not yet be in storage. The \%workerconf hashref is the set of configuration parameters you used to declare the worker (documented below).
$job
device
\%workerconf
The package name used where the worker is declared is significant. Let's look at the boilerplate example again:
package App::Netdisco::Worker::Plugin::Discover::Wireless::UniFi;
The package name must contain Plugin:: and the namespace component after that becomes the action. For example workers registered in the above package will be run during the discover backend action (that is, during a discover job). You can replace Discover with other actions such as Macsuck, Arpnip, Expire, and Nbtstat, or create your own.
Plugin::
discover
Discover
Macsuck
Arpnip
Expire
Nbtstat
The component after the action is known as the phase (Wireless in this example), and is the way to override a Netdisco built-in worker, by using the same name (plus an entry in %workerconf, see below). Otherwise you can use any valid Perl bareword for the phase.
Wireless
Workers may also be registered directly to the action (Discover, in this example), without any phase. This is used for very early bootstrapping code (such as first inserting a device into the database so it can be used by subsequent phases) or for very simple, generic actions (such as netdisco-do psql).
netdisco-do psql
Workers may have only and no parameters configured which use the standard ACL syntax described in the settings guide. The only directive is especially useful as it can restrict a worker to a given device platform or operating system (for example Cisco IOS XR for the restconf driver).
only
no
restconf
driver
The driver is a label associated with a group of workers and typically refers to the combination of transport and application protocol. Examples include snmp, netconf, restconf, eapi, and cli. The convention is for driver names to be lowercase.
snmp
netconf
eapi
cli
Users will bind authentication configuration settings to drivers in their configuration. If no driver is specified when registering a worker, it will be run for every device and phase (such as during Expire jobs).
primary
When multiple workers are registered for the same phase, they will all be run. However there is a special "primary" slot for each phase in which only one worker (the first that succeeds) is used. Most of Netdisco's built-in worker code is registered in this way, so to override it you can use the same package namespace and set primary to be true.
true
Workers are configured as an ordered list. They are grouped by action and phase (as in Package Naming Convention, above).
action
phase
Workers defined in extra_worker_plugins are run before those in worker_plugins so you have an opportunity to override built-in workers by adding them to extra_worker_plugins and setting primary to true in the worker configuration.
extra_worker_plugins
worker_plugins
The return code of the worker is significant for those configured with primary as true: when the worker returns true, no other primary hooks are run for that phase. You should always use the aliased App::Netdisco::Worker::Status helper (loaded as in the boilerplate code above) when returning a value, such as:
return Status->done('everything is good'); # or return Status->error('something went wrong'); # or return Status->defer('this device cannot be processed right now');
Remember that a worker is only run if it matches the hardware platform of the target device and the user's configuration, and is not also excluded by the user's configuration. This filtering takes place before inspecting primary.
From your worker you will want to connect to a device to gather data. This is done using a transport protocol session (SNMP, SSH, etc). Transports are singleton objects instantiated on demand, so they can be shared among a set of workers that are accessing the same device.
See the documentation for each transport to find out how to access it:
App::Netdisco::Transport::SNMP
The Netdisco database is available via the netdisco schema key, as below. You can also use the external_databases configuration item to set up connections to other databases.
netdisco
external_databases
# plugin package use Dancer::Plugin::DBIC; my $set = schema('netdisco')->resultset('Devices') ->search({vendor => 'cisco'});
In summary, Worker code is defined in a package namespace specifying the Action and Phase, and registered as a plugin with configuration which may specify the Driver and whether it is in the Primary slot. Access Control Lists determine which Workers are permitted to run, and when. Here are more complete definitions:
The highest level grouping of workers, corresponding to a Netdisco command such as discover or macsuck. Workers can be registered at this level to do really early bootstrapping work.
macsuck
The next level down from action for grouping workers. Phases have arbitrary names and are visited in the order defined in the extra_worker_plugins setting list, followed by the worker_plugins setting list. Workers are usually registered at this level.
worker
A lump of code you write which does a single clearly defined task. The package namespace of the worker identifies the action and optionally the phase. Workers are typically registered with some configuration settings.
A label associated with a group of workers which refers to a combination of transport and application protocol used to connect to and communicate with the target device. Users attach authentication configuration to specific drivers.
false
Indicates that the worker will only be run if no other primary worker for this phase has already succeeded. In this way, you can override Netdisco code by setting this option and returning true from your worker.
1 POD Error
The following errors were encountered while parsing the POD:
Non-ASCII character seen before =encoding in '# or'. Assuming UTF-8
To install App::Netdisco, copy and paste the appropriate command in to your terminal.
cpanm
cpanm App::Netdisco
CPAN shell
perl -MCPAN -e shell install App::Netdisco
For more information on module installation, please visit the detailed CPAN module installation guide.