App-MultiModule-Tasks-NagiosCmd
view release on metacpan or search on metacpan
lib/App/MultiModule/Tasks/NagiosCmd.pm view on Meta::CPAN
package App::MultiModule::Tasks::NagiosCmd;
$App::MultiModule::Tasks::NagiosCmd::VERSION = '1.161330';
use 5.010;
use strict;
use warnings FATAL => 'all';
use Data::Dumper;
use Nagios::Passive;
use parent 'App::MultiModule::Task';
=head1 NAME
App::MultiModule::Tasks::NagiosCmd - Submit passive checks to Nagios
=cut
=head2 message
=cut
sub message {
my $self = shift;
my $message = shift;
foreach my $field_name ('nagios_check_name', 'nagios_host_name', 'nagios_service_description', 'nagios_return_code', 'nagios_output') {
if(not defined $message->{$field_name}) {
$self->error("App::MultiModule::Tasks::NagiosCmd::message: required field '$field_name' not found", message => $message);
return;
}
}
if( $message->{nagios_return_code} != 0 and
$message->{nagios_return_code} != 1 and
$message->{nagios_return_code} != 2 and
$message->{nagios_return_code} != 3) {
$self->error("App::MultiModule::Tasks::NagiosCmd::message: required field 'nagios_output' must be one of 0, 1, 2 or 3", message => $message);
return;
}
my $nagios_commands = $self->{state}->{nagios_commands};
$message->{NagiosCmd_receive_ts} = time;
push @{$nagios_commands}, $message;
my $max_messages = $self->{config}->{max_messages} || 10000;
if(scalar @{$nagios_commands} > $max_messages) {
$self->error('App::MultiModule::Tasks::NagiosCmd::message: max cached nagios command count exceeded, dropping oldest command',
max_messages => $max_messages,
dropped_message => $nagios_commands->[0]
);
shift @{$nagios_commands};
}
}
sub _write_tick {
my $self = shift;
my $nagios_commands = $self->{state}->{nagios_commands};
return unless scalar @$nagios_commands; #no work
if(my $command_file_err = _validate_command_file($self->{state}->{command_file})) {
$self->error("App::MultiModule::Tasks::NagiosCmd::_write_tick: $command_file_err");
return;
}
WHILE:
while($nagios_commands->[0]) {
my $cmd = $nagios_commands->[0];
eval {
local $SIG{ALRM} = sub { die "timed out\n"; };
alarm 5;
my $np = Nagios::Passive->create(
command_file => $self->{state}->{command_file},
service_description => $cmd->{nagios_service_description},
host_name => $cmd->{nagios_host_name},
check_name => $cmd->{nagios_check_name},
) or die 'Nagios::Passive->create() returned false';
my $ret = $np->return_code($cmd->{nagios_return_code});
die 'Nagios::Passive->return_code() returned undefined'
if not defined $ret;
$ret = $np->output($cmd->{nagios_output});
die 'Nagios::Passive->output() returned undefined'
if not defined $ret;
$np->submit
or die 'Nagios::Passive->submit() returned false';
};
alarm 0;
if($@) {
$self->error("App::MultiModule::Tasks::NagiosCmd::_write_tick: failed: $@", cmd => $cmd);
print STDERR "NagiosCmd: _write_tick: \$err=$@\n";
last WHILE;
}
$self->_cmd_log($cmd);
shift @$nagios_commands;
}
}
sub _validate_command_file { #return false means good
#true return is the text of the problem
my $command_file = shift;
my $ret = eval {
local $SIG{ALRM} = sub { die "timed out\n"; };
alarm 2;
return "command_file $command_file does not exist"
unless -e $command_file;
return "command_file $command_file is not writable"
unless -w $command_file;
return "command_file $command_file is not of file type pipe"
unless -p $command_file;
return 0;
};
alarm 0;
return "command_file $command_file _validate_command_file exception: $@"
if $@;
return $ret;
}
sub _cmd_log {
my $self = shift;
my $config = $self->{config};
my $cmd = shift;
my $logfile = $config->{cmd_log} || 'nagios_cmd.log';
eval {
local $SIG{ALRM} = sub { die "timed out\n"; };
alarm 2;
my $now = scalar localtime;
open my $fh, '>>', $logfile
or die "failed to open $logfile for writing: $!";
print $fh "$now: \"$cmd->{nagios_service_description}\" \"$cmd->{nagios_host_name}\" $cmd->{nagios_return_code} \"$cmd->{nagios_check_name}\" \"$cmd->{nagios_output}\"\n"
or die "failed to write to $logfile: $!";
close $fh or die "failed to close $logfile: $!";
};
alarm 0;
if($@) {
$self->error("App::MultiModule::Tasks::NagiosCmd::_cmd_log failed: $@", cmd => $cmd);
}
}
=head2 set_config
=cut
sub set_config {
my $self = shift;
my $config = shift;
$self->{config} = $config;
$self->{state} = {} unless $self->{state};
$self->{state}->{nagios_commands} = []
unless $self->{state}->{nagios_commands};
if(not $self->{config}->{command_file}) {
$self->error("App::MultiModule::Tasks::NagiosCmd::set_config: required config 'command_file' not found");
return;
}
if(my $command_file_err = _validate_command_file($self->{config}->{command_file})) {
$self->error("App::MultiModule::Tasks::NagiosCmd::set_config: $command_file_err");
return;
}
$self->{state}->{command_file} = $self->{config}->{command_file};
$self->named_recur(
recur_name => 'NagiosCmd_write_tick',
repeat_interval => 1,
work => sub {
$self->_write_tick();
},
);
}
=head2 is_stateful
=cut
sub is_stateful {
return 'definitely, because we need to queue up failed writes';
}
=head1 AUTHOR
Dana M. Diederich, C<< <dana@realms.org> >>
=head1 BUGS
Please report any bugs or feature requests through L<https://github.com/dana/perl-App-MultiModule-Tasks-NagiosCmd/issues>. I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.
=head1 SUPPORT
You can find documentation for this module with the perldoc command.
perldoc App::MultiModule::Tasks::NagiosCmd
You can also look for information at:
=over 4
=item * Report bugs here:
L<https://github.com/dana/perl-App-MultiModule-Tasks-NagiosCmd/issues>
=item * AnnoCPAN: Annotated CPAN documentation
L<http://annocpan.org/dist/App-MultiModule-Tasks-NagiosCmd>
=item * CPAN Ratings
L<http://cpanratings.perl.org/d/App-MultiModule-Tasks-NagiosCmd>
=item * Search CPAN
L<https://metacpan.org/module/App::MultiModule::Tasks::NagiosCmd>
=back
=head1 ACKNOWLEDGEMENTS
( run in 1.945 second using v1.01-cache-2.11-cpan-5a3173703d6 )