File Coverage

blib/lib/App/MultiModule/Tasks/NagiosCmd.pm
Criterion Covered Total %
statement 17 103 16.5
branch 0 44 0.0
condition 0 13 0.0
subroutine 6 16 37.5
pod 3 3 100.0
total 26 179 14.5


line stmt bran cond sub pod time code
1             package App::MultiModule::Tasks::NagiosCmd;
2             $App::MultiModule::Tasks::NagiosCmd::VERSION = '1.161330';
3 2     2   1206 use 5.010;
  2         8  
4 2     2   6 use strict;
  2         2  
  2         40  
5 2     2   6 use warnings FATAL => 'all';
  2         0  
  2         62  
6 2     2   6 use Data::Dumper;
  2         2  
  2         80  
7 2     2   744 use Nagios::Passive;
  2         30398  
  2         48  
8              
9 2     2   10 use parent 'App::MultiModule::Task';
  2         2  
  2         8  
10              
11              
12             =head1 NAME
13              
14             App::MultiModule::Tasks::NagiosCmd - Submit passive checks to Nagios
15              
16             =cut
17              
18             =head2 message
19              
20             =cut
21              
22             sub message {
23 0     0 1   my $self = shift;
24 0           my $message = shift;
25 0           foreach my $field_name ('nagios_check_name', 'nagios_host_name', 'nagios_service_description', 'nagios_return_code', 'nagios_output') {
26 0 0         if(not defined $message->{$field_name}) {
27 0           $self->error("App::MultiModule::Tasks::NagiosCmd::message: required field '$field_name' not found", message => $message);
28 0           return;
29             }
30             }
31 0 0 0       if( $message->{nagios_return_code} != 0 and
      0        
      0        
32             $message->{nagios_return_code} != 1 and
33             $message->{nagios_return_code} != 2 and
34             $message->{nagios_return_code} != 3) {
35 0           $self->error("App::MultiModule::Tasks::NagiosCmd::message: required field 'nagios_output' must be one of 0, 1, 2 or 3", message => $message);
36 0           return;
37             }
38 0           my $nagios_commands = $self->{state}->{nagios_commands};
39 0           $message->{NagiosCmd_receive_ts} = time;
40 0           push @{$nagios_commands}, $message;
  0            
41              
42 0   0       my $max_messages = $self->{config}->{max_messages} || 10000;
43 0 0         if(scalar @{$nagios_commands} > $max_messages) {
  0            
44 0           $self->error('App::MultiModule::Tasks::NagiosCmd::message: max cached nagios command count exceeded, dropping oldest command',
45             max_messages => $max_messages,
46             dropped_message => $nagios_commands->[0]
47             );
48 0           shift @{$nagios_commands};
  0            
49             }
50             }
51              
52             sub _write_tick {
53 0     0     my $self = shift;
54 0           my $nagios_commands = $self->{state}->{nagios_commands};
55 0 0         return unless scalar @$nagios_commands; #no work
56 0 0         if(my $command_file_err = _validate_command_file($self->{state}->{command_file})) {
57 0           $self->error("App::MultiModule::Tasks::NagiosCmd::_write_tick: $command_file_err");
58 0           return;
59             }
60             WHILE:
61 0           while($nagios_commands->[0]) {
62 0           my $cmd = $nagios_commands->[0];
63 0           eval {
64 0     0     local $SIG{ALRM} = sub { die "timed out\n"; };
  0            
65 0           alarm 5;
66             my $np = Nagios::Passive->create(
67             command_file => $self->{state}->{command_file},
68             service_description => $cmd->{nagios_service_description},
69             host_name => $cmd->{nagios_host_name},
70             check_name => $cmd->{nagios_check_name},
71 0 0         ) or die 'Nagios::Passive->create() returned false';
72 0           my $ret = $np->return_code($cmd->{nagios_return_code});
73 0 0         die 'Nagios::Passive->return_code() returned undefined'
74             if not defined $ret;
75 0           $ret = $np->output($cmd->{nagios_output});
76 0 0         die 'Nagios::Passive->output() returned undefined'
77             if not defined $ret;
78 0 0         $np->submit
79             or die 'Nagios::Passive->submit() returned false';
80             };
81 0           alarm 0;
82 0 0         if($@) {
83 0           $self->error("App::MultiModule::Tasks::NagiosCmd::_write_tick: failed: $@", cmd => $cmd);
84 0           print STDERR "NagiosCmd: _write_tick: \$err=$@\n";
85 0           last WHILE;
86             }
87 0           $self->_cmd_log($cmd);
88 0           shift @$nagios_commands;
89             }
90             }
91              
92             sub _validate_command_file { #return false means good
93             #true return is the text of the problem
94 0     0     my $command_file = shift;
95              
96 0           my $ret = eval {
97 0     0     local $SIG{ALRM} = sub { die "timed out\n"; };
  0            
98 0           alarm 2;
99 0 0         return "command_file $command_file does not exist"
100             unless -e $command_file;
101 0 0         return "command_file $command_file is not writable"
102             unless -w $command_file;
103 0 0         return "command_file $command_file is not of file type pipe"
104             unless -p $command_file;
105 0           return 0;
106             };
107 0           alarm 0;
108 0 0         return "command_file $command_file _validate_command_file exception: $@"
109             if $@;
110 0           return $ret;
111             }
112              
113             sub _cmd_log {
114 0     0     my $self = shift;
115 0           my $config = $self->{config};
116 0           my $cmd = shift;
117 0   0       my $logfile = $config->{cmd_log} || 'nagios_cmd.log';
118 0           eval {
119 0     0     local $SIG{ALRM} = sub { die "timed out\n"; };
  0            
120 0           alarm 2;
121 0           my $now = scalar localtime;
122 0 0         open my $fh, '>>', $logfile
123             or die "failed to open $logfile for writing: $!";
124 0 0         print $fh "$now: \"$cmd->{nagios_service_description}\" \"$cmd->{nagios_host_name}\" $cmd->{nagios_return_code} \"$cmd->{nagios_check_name}\" \"$cmd->{nagios_output}\"\n"
125             or die "failed to write to $logfile: $!";
126 0 0         close $fh or die "failed to close $logfile: $!";
127             };
128 0           alarm 0;
129 0 0         if($@) {
130 0           $self->error("App::MultiModule::Tasks::NagiosCmd::_cmd_log failed: $@", cmd => $cmd);
131             }
132             }
133              
134             =head2 set_config
135              
136             =cut
137             sub set_config {
138 0     0 1   my $self = shift;
139 0           my $config = shift;
140 0           $self->{config} = $config;
141 0 0         $self->{state} = {} unless $self->{state};
142             $self->{state}->{nagios_commands} = []
143 0 0         unless $self->{state}->{nagios_commands};
144 0 0         if(not $self->{config}->{command_file}) {
145 0           $self->error("App::MultiModule::Tasks::NagiosCmd::set_config: required config 'command_file' not found");
146 0           return;
147             }
148 0 0         if(my $command_file_err = _validate_command_file($self->{config}->{command_file})) {
149 0           $self->error("App::MultiModule::Tasks::NagiosCmd::set_config: $command_file_err");
150 0           return;
151             }
152 0           $self->{state}->{command_file} = $self->{config}->{command_file};
153             $self->named_recur(
154             recur_name => 'NagiosCmd_write_tick',
155             repeat_interval => 1,
156             work => sub {
157 0     0     $self->_write_tick();
158             },
159 0           );
160             }
161              
162             =head2 is_stateful
163              
164             =cut
165             sub is_stateful {
166 0     0 1   return 'definitely, because we need to queue up failed writes';
167             }
168              
169             =head1 AUTHOR
170              
171             Dana M. Diederich, C<< <dana@realms.org> >>
172              
173             =head1 BUGS
174              
175             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
176             automatically be notified of progress on your bug as I make changes.
177              
178             =head1 SUPPORT
179              
180             You can find documentation for this module with the perldoc command.
181              
182             perldoc App::MultiModule::Tasks::NagiosCmd
183              
184              
185             You can also look for information at:
186              
187             =over 4
188              
189             =item * Report bugs here:
190              
191             L<https://github.com/dana/perl-App-MultiModule-Tasks-NagiosCmd/issues>
192              
193             =item * AnnoCPAN: Annotated CPAN documentation
194              
195             L<http://annocpan.org/dist/App-MultiModule-Tasks-NagiosCmd>
196              
197             =item * CPAN Ratings
198              
199             L<http://cpanratings.perl.org/d/App-MultiModule-Tasks-NagiosCmd>
200              
201             =item * Search CPAN
202              
203             L<https://metacpan.org/module/App::MultiModule::Tasks::NagiosCmd>
204              
205             =back
206              
207             =head1 ACKNOWLEDGEMENTS
208              
209             =head1 LICENSE AND COPYRIGHT
210              
211             Copyright 2016 Dana M. Diederich.
212              
213             This program is free software; you can redistribute it and/or modify it
214             under the terms of the the Artistic License (2.0). You may obtain a
215             copy of the full license at:
216              
217             L<http://www.perlfoundation.org/artistic_license_2_0>
218              
219             Any use, modification, and distribution of the Standard or Modified
220             Versions is governed by this Artistic License. By using, modifying or
221             distributing the Package, you accept this license. Do not use, modify,
222             or distribute the Package, if you do not accept this license.
223              
224             If your Modified Version has been derived from a Modified Version made
225             by someone other than you, you are nevertheless required to ensure that
226             your Modified Version complies with the requirements of this license.
227              
228             This license does not grant you the right to use any trademark, service
229             mark, tradename, or logo of the Copyright Holder.
230              
231             This license includes the non-exclusive, worldwide, free-of-charge
232             patent license to make, have made, use, offer to sell, sell, import and
233             otherwise transfer the Package with respect to any patent claims
234             licensable by the Copyright Holder that are necessarily infringed by the
235             Package. If you institute patent litigation (including a cross-claim or
236             counterclaim) against any party alleging that the Package constitutes
237             direct or contributory patent infringement, then this Artistic License
238             to you shall terminate on the date that such litigation is filed.
239              
240             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
241             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
242             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
243             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
244             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
245             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
246             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
247             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
248              
249              
250             =cut
251              
252             1; # End of App::MultiModule::Tasks::NagiosCmd