use Scope::Guard to reduce device_auth

This commit is contained in:
Oliver Gorwits
2017-08-02 10:19:16 +01:00
parent ec041dafd2
commit 464c42d1f5
3 changed files with 41 additions and 65 deletions

View File

@@ -55,6 +55,7 @@ Module::Build->new(
'Plack::Middleware::ReverseProxy' => '0.15',
'Pod::Usage' => 0,
'Role::Tiny' => '1.002005',
'Scope::Guard' => 0,
'Sereal' => '0',
'Socket6' => '0.23',
'Starman' => '0.4008',

View File

@@ -5,6 +5,7 @@ use Dancer::Plugin;
use Dancer::Factory::Hook;
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
use Scope::Guard;
use Try::Tiny;
Dancer::Factory::Hook->instance->install_hooks(
@@ -19,32 +20,38 @@ register 'register_core_driver' => sub {
and exists $driverconf->{phase} and exists $driverconf->{driver}
and Dancer::Factory::Hook->instance->hook_is_registered($driverconf->{phase}));
my $no = (exists $driverconf->{no} ? $driverconf->{no} : undef);
my $only = (exists $driverconf->{only} ? $driverconf->{only} : undef);
# needs to be here for caller() context
$driverconf->{plugin} = (caller)[0];
my $hook = sub {
my ($device, $userconf) = @_;
return false unless (ref $device and (ref {} eq ref $userconf));
my $device = shift or return false;
# first check internal (driverconf) exclusion/inclusion criteria
return false if ($only and not check_acl_only($device, $only));
return false if ($no and (not exists $userconf->{driver})
and check_acl_no($device, $only));
my $no = (exists $driverconf->{no} ? $driverconf->{no} : undef);
my $only = (exists $driverconf->{only} ? $driverconf->{only} : undef);
# then check external (userconf) exclusion/inclusion criteria
return false if exists $userconf->{phase}
and (($userconf->{phase} || '') ne $driverconf->{phase});
my @newuserconf = ();
my @userconf = @{ setting('device_auth') || [] };
return false if exists $userconf->{driver}
and (($userconf->{driver} || '') ne $driverconf->{driver});
# reduce device_auth by driver, plugin, driver's only/no
foreach my $stanza (@userconf) {
next if $no and check_acl_no($device, $no);
next if $only and not check_acl_only($device, $only);
next if exists $stanza->{driver}
and (($stanza->{driver} || '') ne $driverconf->{driver});
next if exists $stanza->{plugin}
and (($stanza->{plugin} || '') ne $driverconf->{plugin});
push @newuserconf, $stanza;
}
return false if exists $userconf->{plugin}
and (($userconf->{plugin} || '') ne $driverconf->{plugin});
# back up and restore device_auth
return false unless scalar @newuserconf;
my $guard = guard { set(device_auth => \@userconf) };
set(device_auth => \@newuserconf);
# run driver
my $happy = false;
try {
$code->($device, $driverconf, $userconf);
$code->($device, $driverconf);
$happy = true;
}
catch { debug $_ };
@@ -109,11 +116,14 @@ Plugin modules can either ship with the App::Netdisco distribution itself, or
be installed separately. Perl uses the standard C<@INC> path searching
mechanism to load the plugin modules. See the C<include_paths> and
C<site_local_files> settings in order to modify C<@INC> for loading local
plugins.
plugins. As an example, if your plugin is called
"App::NetdiscoX::Core::Plugin::MyPluginName" then it could live at:
The order of the entries is significant. Drivers are executed in REVERSE
order that they appear in the C<extra_collector_plugins> and
C<collector_plugins> settings.
~netdisco/nd-site-local/lib/App/NetdiscoX/Core/Plugin/MyPluginName.pm
The order of the entries is significant, drivers being executed in the order
which they appear in C<collector_plugins> and C<extra_collector_plugins>
(although see L<App::Netdisco::Manual::WritingBackendDrivers> for caveats).
Finally, you can also prepend module names with "C<X::>", to support the
"Netdisco extension" namespace. For example,

View File

@@ -22,12 +22,11 @@ See L<App::Netdisco::Core::Plugin> for more information about core plugins.
=head1 Developing Plugins
A plugin is simply a Perl module which is loaded. Therefore it can do anything
you like, but most usefully for the App::Netdisco application the module
will make a connection to a device, gather some data, and store it in
Netdisco's database.
A plugin is a Perl module which is loaded. Therefore it can do anything you
like, but the module will make a connection to a device, gather some data, and
store it in Netdisco's database.
App::Netdisco plugins should load the L<App::Netdisco::Core::Plugin> module.
App::Netdisco plugins must load the L<App::Netdisco::Core::Plugin> module.
This exports a set of helper subroutines to register the driver. Here's the
boilerplate code for our example plugin module:
@@ -55,24 +54,21 @@ For example:
phase => 'discover_wireless',
}, sub { "driver code here" });
An explanation of the C<$driverconf> options is below. The C<$coderef> is the
An explanation of the C<%driverconf> options is below. The C<$coderef> is the
main body of your driver. Your driver is run in a L<Try::Tiny> statement to
catch errors, and passed the following arguments:
$coderef->($device, $driverconf, $userconf);
$coderef->($device, $driverconf);
The C<$device> is an instance of L<App::Netdisco::DB::Result::Device>; that
is, a representation of a row in the database. Note that for early discover
phases this row may not yet exist in the database.
The C<$driverconf> hashref is the set of configuration parameters you used to
declare the driver (documented below). The C<$userconf> hashref is the
settings from C<device_auth> that the end-user configured for authentication;
these are typically specific to the driver and transport in use.
phases this row may not yet exist in the database. The C<$driverconf> hashref
is the set of configuration parameters you used to declare the driver
(documented below).
=head2 Required Parameters
You must register drivers with a C<driver> and C<phase> parameter.
You must register drivers with a C<driver> and a C<phase> parameter.
The C<driver> is a label associated with a group of drivers and typically
refers to the combination of transport and application protocol. Examples
@@ -161,36 +157,5 @@ connections to other databases.
use Dancer::Plugin::DBIC;
schema('netdisco')->resultset('Devices')->search({vendor => 'cisco'});
=head1 Naming and File Location
There are several options for how you name, distribute and install your
App::Netdisco plugin.
=head2 Namespaces
As mentioned in L<App::Netdisco::Core::Plugin>, official Netdisco plugins live
in the C<App::Netdisco::Core::Plugin::> namespace. You can use this namespace
and submit the product to the Netdisco developer team for consideration for
inclusion in the official distribution.
Alternatively you can release the plugin to CPAN under your own account. In
that case we request that you instead use the
C<App::NetdiscoX::Core::Plugin::> namespace (note the "X"). Users can load
such modules by using the abbreviated form "X::MyPluginName" which is then
expanded to the full package.
=head2 File Location
If writing your own plugins that are not for redistribution or packaging on
CPAN, Netdisco can enable a local include path (C<@INC>). Configuring the
C<site_local_files> setting to be "true" enables:
$ENV{NETDISCO_HOME}/nd-site-local/lib
As an example, if your plugin is called
"App::NetdiscoX::Core::Plugin::MyPluginName" then it could live at:
~netdisco/nd-site-local/lib/App/NetdiscoX/Core/Plugin/MyPluginName.pm
=cut