add priority and namespace to support fancy worker overrides

This commit is contained in:
Oliver Gorwits
2017-11-04 23:06:20 +00:00
parent b9f9816d09
commit 10f78d5dbe
4 changed files with 82 additions and 13 deletions

View File

@@ -5,9 +5,9 @@ use warnings;
use Module::Load (); use Module::Load ();
use Module::Find qw/findsubmod findallmod/; use Module::Find qw/findsubmod findallmod/;
use Dancer ':syntax';
# load worker plugins for our action use Dancer ':syntax';
use Dancer::Factory::Hook;
sub import { sub import {
my ($class, $action) = @_; my ($class, $action) = @_;
@@ -17,6 +17,7 @@ sub import {
my @check_plugins = findsubmod 'App::Netdisco::Worker::Plugin'; my @check_plugins = findsubmod 'App::Netdisco::Worker::Plugin';
my @phase_plugins = map { findallmod $_ } @check_plugins; my @phase_plugins = map { findallmod $_ } @check_plugins;
# load worker plugins for our action
foreach my $plugin (@user_plugins, @check_plugins, @phase_plugins) { foreach my $plugin (@user_plugins, @check_plugins, @phase_plugins) {
$plugin =~ s/^X::/App::NetdiscoX::Worker::Plugin::/; $plugin =~ s/^X::/App::NetdiscoX::Worker::Plugin::/;
next unless $plugin =~ m/::Plugin::${action}(?:::|$)/i; next unless $plugin =~ m/::Plugin::${action}(?:::|$)/i;
@@ -24,6 +25,32 @@ sub import {
debug "loading worker plugin $plugin"; debug "loading worker plugin $plugin";
Module::Load::load $plugin; Module::Load::load $plugin;
} }
# now vars->{workers} is populated, we set the dispatch order
my $store = Dancer::Factory::Hook->instance();
# use DDP; p vars->{'workers'};
foreach my $phase (qw/check early main user/) {
$store->install_hooks("nd2_core_${phase}");
foreach my $namespace (sort keys %{ vars->{'workers'}->{$phase} }) {
hook "nd2_core_${phase}" => sub {
vars->{'last_worker_ok'} = false;
vars->{'last_worker_priority'} = 0;
};
foreach my $priority (sort {$b <=> $a} keys %{ vars->{'workers'}->{$phase}->{$namespace} }) {
# D::Factory::Hook::register_hook() does not work?!
hook "nd2_core_${phase}" => $_
for @{ vars->{'workers'}->{$phase}->{$namespace}->{$priority} };
hook "nd2_core_${phase}" => sub {
vars->{'last_worker_priority'} = $priority;
};
}
}
}
} }
true; true;

View File

@@ -2,17 +2,11 @@ package App::Netdisco::Worker::Plugin;
use Dancer ':syntax'; use Dancer ':syntax';
use Dancer::Plugin; use Dancer::Plugin;
use Dancer::Factory::Hook;
use Scope::Guard 'guard'; use Scope::Guard 'guard';
use aliased 'App::Netdisco::Worker::Status'; use aliased 'App::Netdisco::Worker::Status';
use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/; use App::Netdisco::Util::Permission qw/check_acl_no check_acl_only/;
my $store = Dancer::Factory::Hook->instance();
foreach my $phase (qw/check early main user/) {
$store->install_hooks("nd2_core_${phase}");
}
register 'register_worker' => sub { register 'register_worker' => sub {
my ($self, $first, $second) = plugin_args(@_); my ($self, $first, $second) = plugin_args(@_);
@@ -21,10 +15,28 @@ register 'register_worker' => sub {
return error "bad param to register_worker" return error "bad param to register_worker"
unless ((ref sub {} eq ref $code) and (ref {} eq ref $workerconf)); unless ((ref sub {} eq ref $code) and (ref {} eq ref $workerconf));
$workerconf->{phase} ||= 'user'; my $package = (caller)[0];
if ($package =~ m/Plugin::(\w+)(?:::(\w+))?/) {
$workerconf->{action} = lc($1);
$workerconf->{namespace} = lc($2) if $2;
}
return error "failed to parse action in '$package'"
unless $workerconf->{action};
$workerconf->{phase} ||= 'user';
$workerconf->{namespace} ||= '_base_';
$workerconf->{priority} ||= (exists $workerconf->{driver}
? setting('driver_priority')->{$workerconf->{driver}} : 0);
my $worker = sub { my $worker = sub {
my $job = shift or return Status->error('missing job param'); my $job = shift or return Status->error('missing job param');
# use DDP; p $workerconf;
# once workers at a given priority level in a namespace are successful,
# we can skip workers at lower priorities (that is, other drivers)
return Status->noop('skipped worker after previous namespace success')
if vars->{'last_worker_ok'}
and $workerconf->{priority} < vars->{'last_worker_priority'};
# worker might be vendor/platform specific # worker might be vendor/platform specific
if (ref $job->device) { if (ref $job->device) {
@@ -39,11 +51,14 @@ register 'register_worker' => sub {
my @newuserconf = (); my @newuserconf = ();
my @userconf = @{ setting('device_auth') || [] }; my @userconf = @{ setting('device_auth') || [] };
# reduce device_auth by driver # reduce device_auth by driver and action filters
foreach my $stanza (@userconf) { foreach my $stanza (@userconf) {
next if exists $stanza->{driver} and exists $workerconf->{driver} next if exists $stanza->{driver} and exists $workerconf->{driver}
and (($stanza->{driver} || '') ne ($workerconf->{driver} || '')); and (($stanza->{driver} || '') ne ($workerconf->{driver} || ''));
next if exists $stanza->{action}
and not _find_matchaction($workerconf, lc($stanza->{action}));
push @newuserconf, $stanza; push @newuserconf, $stanza;
} }
@@ -59,11 +74,25 @@ register 'register_worker' => sub {
return $code->($job, $workerconf); return $code->($job, $workerconf);
}; };
# D::Factory::Hook::register_hook() does not work?! # store the built worker as Worker.pm will build the dispatch order later on
my $hook = 'nd2_core_'. $workerconf->{phase}; push @{ vars->{'workers'}
hook $hook => $worker; ->{$workerconf->{phase}}
->{$workerconf->{namespace}}
->{$workerconf->{priority}} }, $worker;
}; };
sub _find_matchaction {
my ($conf, $action) = @_;
return true if !defined $action;
$action = [$action] if ref [] ne ref $action;
foreach my $f (@$action) {
return true if
$f eq $conf->{action} or $f eq "$conf->{action}::$conf->{namespace}";
}
return false;
}
register_plugin; register_plugin;
true; true;

View File

@@ -100,6 +100,12 @@ sub run_workers {
catch { catch {
debug "=> $_" if $_; debug "=> $_" if $_;
$self->jobstat->error($_) if $phase eq 'check'; $self->jobstat->error($_) if $phase eq 'check';
}
# allow workers to know whether previous worker of a different driver
# but the same namespace was successful
finally {
vars->{'last_worker_ok'} = $self->jobstat->is_ok
if not vars->{'last_worker_ok'};
}; };
} }
} }

View File

@@ -256,6 +256,13 @@ job_prio:
extra_worker_plugins: [] extra_worker_plugins: []
# - Discover::ConfigBackup::CLI # - Discover::ConfigBackup::CLI
driver_priority:
restconf: 500
netconf: 400
eapi: 300
cli: 200
snmp: 100
# --------------- # ---------------
# GraphViz Export # GraphViz Export
# --------------- # ---------------