File Coverage

blib/lib/App/MultiModule/Tasks/NagiosCmd.pm
Criterion Covered Total %
statement 17 100 17.0
branch 0 44 0.0
condition 0 13 0.0
subroutine 6 16 37.5
pod 3 3 100.0
total 26 176 14.7


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