From 351927d3842bf0a670b363f9f38160b5c44ec8ac Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Wed, 30 Dec 2020 20:38:45 +0000 Subject: [PATCH] add arpnip and macsuck hooks and exec hook implementation --- Build.PL | 1 + lib/App/Netdisco/JobQueue/PostgreSQL.pm | 3 +- lib/App/Netdisco/Worker/Plugin/Arpnip.pm | 4 ++ .../Netdisco/Worker/Plugin/Arpnip/Hooks.pm | 2 +- lib/App/Netdisco/Worker/Plugin/Hook/Exec.pm | 60 +++++++++++++++++++ lib/App/Netdisco/Worker/Plugin/Hook/HTTP.pm | 1 + lib/App/Netdisco/Worker/Plugin/Macsuck.pm | 4 ++ .../Netdisco/Worker/Plugin/Macsuck/Hooks.pm | 2 +- share/config.yml | 3 + 9 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 lib/App/Netdisco/Worker/Plugin/Hook/Exec.pm diff --git a/Build.PL b/Build.PL index c5fa6ce0..cf0ca36f 100644 --- a/Build.PL +++ b/Build.PL @@ -29,6 +29,7 @@ Module::Build->new( 'Authen::Radius' => '0', 'Authen::TacacsPlus' => '0', 'CGI::Expand' => '2.05', + 'Command::Runner' => 0, 'Data::Printer' => '0', 'Data::Visitor::Tiny' => '0', 'DBD::Pg' => '0', diff --git a/lib/App/Netdisco/JobQueue/PostgreSQL.pm b/lib/App/Netdisco/JobQueue/PostgreSQL.pm index 9beb7b4d..92b9c814 100644 --- a/lib/App/Netdisco/JobQueue/PostgreSQL.pm +++ b/lib/App/Netdisco/JobQueue/PostgreSQL.pm @@ -270,7 +270,8 @@ sub jq_complete { log => $job->log, started => $job->started, finished => $job->finished, - (($job->action eq 'hook') ? (subaction => undef) : ()), + (($job->action eq 'hook') ? (subaction => $job->subaction) : ()), + ($job->only_namespace ? (action => ($job->action .'::'. $job->only_namespace)) : ()), }); }); $happy = true; diff --git a/lib/App/Netdisco/Worker/Plugin/Arpnip.pm b/lib/App/Netdisco/Worker/Plugin/Arpnip.pm index 1637b5df..72bbb4cf 100644 --- a/lib/App/Netdisco/Worker/Plugin/Arpnip.pm +++ b/lib/App/Netdisco/Worker/Plugin/Arpnip.pm @@ -19,6 +19,10 @@ register_worker({ phase => 'check' }, sub { return Status->info("arpnip skipped: $device is not arpnipable") unless is_arpnipable_now($device); + # support for Hooks + vars->{'hook_data'} = { $device->get_columns }; + delete vars->{'hook_data'}->{'snmp_comm'}; # for privacy + return Status->done('arpnip is able to run'); }); diff --git a/lib/App/Netdisco/Worker/Plugin/Arpnip/Hooks.pm b/lib/App/Netdisco/Worker/Plugin/Arpnip/Hooks.pm index e99e4efc..9e713e78 100644 --- a/lib/App/Netdisco/Worker/Plugin/Arpnip/Hooks.pm +++ b/lib/App/Netdisco/Worker/Plugin/Arpnip/Hooks.pm @@ -20,7 +20,7 @@ register_worker({ phase => 'late' }, sub { if ($conf->{'event'} eq 'arpnip') { $count += queue_hook('arpnip', $conf); - sprintf ' [%s] hooks - %s queued', 'arpnip', $job->device; + debug sprintf ' [%s] hooks - %s queued', 'arpnip', $job->device; } } diff --git a/lib/App/Netdisco/Worker/Plugin/Hook/Exec.pm b/lib/App/Netdisco/Worker/Plugin/Hook/Exec.pm new file mode 100644 index 00000000..b186bf10 --- /dev/null +++ b/lib/App/Netdisco/Worker/Plugin/Hook/Exec.pm @@ -0,0 +1,60 @@ +package App::Netdisco::Worker::Plugin::Hook::Exec; + +use Dancer ':syntax'; +use App::Netdisco::Worker::Plugin; +use aliased 'App::Netdisco::Worker::Status'; + +use MIME::Base64 'decode_base64'; +use Command::Runner; +use Template; + +register_worker({ phase => 'main' }, sub { + my ($job, $workerconf) = @_; + my $extra = from_json( decode_base64( $job->extra || '' ) ); + + my $event_data = $extra->{'event_data'}; + my $action_conf = $extra->{'action_conf'}; + + return Status->error('missing cmd parameter to exec Hook') + if !defined $action_conf->{'cmd'}; + + my $tt = Template->new({ ENCODING => 'utf8' }); + my ($orig_cmd, $cmd) = ($action_conf->{'cmd'}, undef); + $action_conf->{'cmd_is_template'} ||= 1 + if !exists $action_conf->{'cmd_is_template'}; + if ($action_conf->{'cmd_is_template'}) { + if (ref $orig_cmd) { + foreach my $part (@$orig_cmd) { + my $tmp_part = undef; + $tt->process(\$part, $event_data, \$tmp_part); + push @$cmd, $tmp_part; + } + } + else { + $tt->process(\$orig_cmd, $event_data, \$cmd); + } + } + $cmd ||= $orig_cmd; + + my $result = Command::Runner->new( + command => $cmd, + timeout => ($action_conf->{'timeout'} || 60), + env => { + %ENV, + ND_EVENT => $action_conf->{'event'}, + ND_DEVICE_IP => $event_data->{'ip'}, + }, + )->run(); + + $result->{cmd} = $cmd; + $job->subaction(to_json($result)); + + if ($action_conf->{'ignore_failure'} or not $result->{'result'}) { + return Status->done(sprintf 'Exec Hook: exit status %s', $result->{'result'}); + } + else { + return Status->error(sprintf 'Exec Hook: exit status %s', $result->{'result'}); + } +}); + +true; diff --git a/lib/App/Netdisco/Worker/Plugin/Hook/HTTP.pm b/lib/App/Netdisco/Worker/Plugin/Hook/HTTP.pm index 1bd5234f..1c2d2c40 100644 --- a/lib/App/Netdisco/Worker/Plugin/Hook/HTTP.pm +++ b/lib/App/Netdisco/Worker/Plugin/Hook/HTTP.pm @@ -11,6 +11,7 @@ use Template; register_worker({ phase => 'main' }, sub { my ($job, $workerconf) = @_; my $extra = from_json( decode_base64( $job->extra || '' ) ); + $job->subaction(''); my $event_data = $extra->{'event_data'}; my $action_conf = $extra->{'action_conf'}; diff --git a/lib/App/Netdisco/Worker/Plugin/Macsuck.pm b/lib/App/Netdisco/Worker/Plugin/Macsuck.pm index 13b61065..26d8bac9 100644 --- a/lib/App/Netdisco/Worker/Plugin/Macsuck.pm +++ b/lib/App/Netdisco/Worker/Plugin/Macsuck.pm @@ -19,6 +19,10 @@ register_worker({ phase => 'check' }, sub { return Status->info("macsuck skipped: $device is not macsuckable") unless is_macsuckable_now($device); + # support for Hooks + vars->{'hook_data'} = { $device->get_columns }; + delete vars->{'hook_data'}->{'snmp_comm'}; # for privacy + return Status->done('Macsuck is able to run.'); }); diff --git a/lib/App/Netdisco/Worker/Plugin/Macsuck/Hooks.pm b/lib/App/Netdisco/Worker/Plugin/Macsuck/Hooks.pm index 0594fc62..1038cf3a 100644 --- a/lib/App/Netdisco/Worker/Plugin/Macsuck/Hooks.pm +++ b/lib/App/Netdisco/Worker/Plugin/Macsuck/Hooks.pm @@ -20,7 +20,7 @@ register_worker({ phase => 'late' }, sub { if ($conf->{'event'} eq 'macsuck') { $count += queue_hook('macsuck', $conf); - sprintf ' [%s] hooks - %s queued', 'macsuck', $job->device; + debug sprintf ' [%s] hooks - %s queued', 'macsuck', $job->device; } } diff --git a/share/config.yml b/share/config.yml index b2af71f3..478216e3 100644 --- a/share/config.yml +++ b/share/config.yml @@ -389,6 +389,7 @@ worker_plugins: - 'Arpnip' - 'Arpnip::Nodes' - 'Arpnip::Subnets' + - 'Arpnip::Hooks' - 'Arpwalk' - 'Contact' - 'Delete' @@ -411,11 +412,13 @@ worker_plugins: - 'ExpireNodes' - 'Graph' - 'Hook' + - 'Hook::Exec' - 'Hook::HTTP' - 'Location' - 'Macsuck' - 'Macsuck::Nodes' - 'Macsuck::WirelessNodes' + - 'Macsuck::Hooks' - 'Macwalk' - 'MakeRancidConf' - 'NodeMonitor'