File Coverage

blib/lib/Monitoring/GLPlugin.pm
Criterion Covered Total %
statement 260 839 30.9
branch 90 346 26.0
condition 32 140 22.8
subroutine 33 89 37.0
pod 0 71 0.0
total 415 1485 27.9


line stmt bran cond sub pod time code
1             package Monitoring::GLPlugin;
2              
3             =head1 Monitoring::GLPlugin
4              
5             Monitoring::GLPlugin - infrastructure functions to build a monitoring plugin
6              
7             =cut
8              
9 3     3   95362 use strict;
  3         5  
  3         71  
10 3     3   1181 use IO::File;
  3         18449  
  3         313  
11 3     3   16 use File::Basename;
  3         6  
  3         154  
12 3     3   11 use Digest::MD5 qw(md5_hex);
  3         3  
  3         102  
13 3     3   420 use Errno;
  3         830  
  3         88  
14 3     3   1686 use Data::Dumper;
  3         14441  
  3         221  
15             our $AUTOLOAD;
16             *VERSION = \'2.1';
17              
18 3     3   16 use constant { OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => 3 };
  3         5  
  3         5290  
19              
20             {
21             our $mode = undef;
22             our $plugin = undef;
23             our $pluginname = basename($ENV{'NAGIOS_PLUGIN'} || $0);
24             our $blacklist = undef;
25             our $info = [];
26             our $extendedinfo = [];
27             our $summary = [];
28             our $variables = {};
29             }
30              
31             sub new {
32 3     3 0 745 my ($class, %params) = @_;
33 3         7 my $self = {};
34 3         7 bless $self, $class;
35             require Monitoring::GLPlugin::Commandline
36 3 100       1511 if ! grep /BEGIN/, keys %Monitoring::GLPlugin::Commandline::;
37             require Monitoring::GLPlugin::Item
38 3 100       1011 if ! grep /BEGIN/, keys %Monitoring::GLPlugin::Item::;
39             require Monitoring::GLPlugin::TableItem
40 3 100       950 if ! grep /BEGIN/, keys %Monitoring::GLPlugin::TableItem::;
41 3         26 $Monitoring::GLPlugin::plugin = Monitoring::GLPlugin::Commandline->new(%params);
42 3         17 return $self;
43             }
44              
45             sub init {
46 0     0 0 0 my ($self) = @_;
47 0 0 0     0 if ($self->opts->can("blacklist") && $self->opts->blacklist &&
      0        
48             -f $self->opts->blacklist) {
49 0         0 $self->opts->blacklist = do {
50 0         0 local (@ARGV, $/) = $self->opts->blacklist; <> };
  0         0  
51             }
52             }
53              
54             sub dumper {
55 0     0 0 0 my ($self, $object) = @_;
56 0         0 my $run = $object->{runtime};
57 0         0 delete $object->{runtime};
58 0         0 printf STDERR "%s\n", Data::Dumper::Dumper($object);
59 0         0 $object->{runtime} = $run;
60             }
61              
62             sub no_such_mode {
63 0     0 0 0 my ($self) = @_;
64 0         0 printf "Mode %s is not implemented for this type of device\n",
65             $self->opts->mode;
66 0         0 exit 3;
67             }
68              
69             #########################################################
70             # framework-related. setup, options
71             #
72             sub add_default_args {
73 3     3 0 17 my ($self) = @_;
74 3         14 $self->add_arg(
75             spec => 'mode=s',
76             help => "--mode
77             A keyword which tells the plugin what to do",
78             required => 1,
79             );
80 3         7 $self->add_arg(
81             spec => 'regexp',
82             help => "--regexp
83             Parameter name/name2/name3 will be interpreted as (perl) regular expression",
84             required => 0,);
85 3         6 $self->add_arg(
86             spec => 'warning=s',
87             help => "--warning
88             The warning threshold",
89             required => 0,);
90 3         6 $self->add_arg(
91             spec => 'critical=s',
92             help => "--critical
93             The critical threshold",
94             required => 0,);
95 3         5 $self->add_arg(
96             spec => 'warningx=s%',
97             help => '--warningx
98             The extended warning thresholds
99             e.g. --warningx db_msdb_free_pct=6: to override the threshold for a
100             specific item ',
101             required => 0,
102             );
103 3         6 $self->add_arg(
104             spec => 'criticalx=s%',
105             help => '--criticalx
106             The extended critical thresholds',
107             required => 0,
108             );
109 3         5 $self->add_arg(
110             spec => 'units=s',
111             help => "--units
112             One of %, B, KB, MB, GB, Bit, KBi, MBi, GBi. (used for e.g. mode interface-usage)",
113             required => 0,
114             );
115 3         5 $self->add_arg(
116             spec => 'name=s',
117             help => "--name
118             The name of a specific component to check",
119             required => 0,
120             );
121 3         26 $self->add_arg(
122             spec => 'name2=s',
123             help => "--name2
124             The secondary name of a component",
125             required => 0,
126             );
127 3         7 $self->add_arg(
128             spec => 'name3=s',
129             help => "--name3
130             The tertiary name of a component",
131             required => 0,
132             );
133 3         7 $self->add_arg(
134             spec => 'blacklist|b=s',
135             help => '--blacklist
136             Blacklist some (missing/failed) components',
137             required => 0,
138             default => '',
139             );
140 3         6 $self->add_arg(
141             spec => 'mitigation=s',
142             help => "--mitigation
143             The parameter allows you to change a critical error to a warning.",
144             required => 0,
145             );
146 3         5 $self->add_arg(
147             spec => 'lookback=s',
148             help => "--lookback
149             The amount of time you want to look back when calculating average rates.
150             Use it for mode interface-errors or interface-usage. Without --lookback
151             the time between two runs of check_nwc_health is the base for calculations.
152             If you want your checkresult to be based for example on the past hour,
153             use --lookback 3600. ",
154             required => 0,
155             );
156 3         6 $self->add_arg(
157             spec => 'environment|e=s%',
158             help => "--environment
159             Add a variable to the plugin's environment",
160             required => 0,
161             );
162 3         6 $self->add_arg(
163             spec => 'negate=s%',
164             help => "--negate
165             Emulate the negate plugin. --negate warning=critical --negate unknown=critical",
166             required => 0,
167             );
168 3         5 $self->add_arg(
169             spec => 'morphmessage=s%',
170             help => '--morphmessage
171             Modify the final output message',
172             required => 0,
173             );
174 3         5 $self->add_arg(
175             spec => 'morphperfdata=s%',
176             help => "--morphperfdata
177             The parameter allows you to change performance data labels.
178             It's a perl regexp and a substitution.
179             Example: --morphperfdata '(.*)ISATAP(.*)'='\$1patasi\$2'",
180             required => 0,
181             );
182 3         11 $self->add_arg(
183             spec => 'selectedperfdata=s',
184             help => "--selectedperfdata
185             The parameter allows you to limit the list of performance data. It's a perl regexp.
186             Only matching perfdata show up in the output",
187             required => 0,
188             );
189 3         8 $self->add_arg(
190             spec => 'report=s',
191             help => "--report
192             Can be used to shorten the output",
193             required => 0,
194             default => 'long',
195             );
196 3         7 $self->add_arg(
197             spec => 'multiline',
198             help => '--multiline
199             Multiline output',
200             required => 0,
201             );
202 3         6 $self->add_arg(
203             spec => 'with-mymodules-dyn-dir=s',
204             help => "--with-mymodules-dyn-dir
205             Add-on modules for the my-modes will be searched in this directory",
206             required => 0,
207             );
208 3         5 $self->add_arg(
209             spec => 'statefilesdir=s',
210             help => '--statefilesdir
211             An alternate directory where the plugin can save files',
212             required => 0,
213             env => 'STATEFILESDIR',
214             );
215 3         6 $self->add_arg(
216             spec => 'isvalidtime=i',
217             help => '--isvalidtime
218             Signals the plugin to return OK if now is not a valid check time',
219             required => 0,
220             default => 1,
221             );
222 3         8 $self->add_arg(
223             spec => 'reset',
224             help => "--reset
225             remove the state file",
226             aliasfor => "name",
227             required => 0,
228             hidden => 1,
229             );
230 3         6 $self->add_arg(
231             spec => 'drecksptkdb=s',
232             help => "--drecksptkdb
233             This parameter must be used instead of --name, because Devel::ptkdb is stealing the latter from the command line",
234             aliasfor => "name",
235             required => 0,
236             hidden => 1,
237             );
238             }
239              
240             sub add_modes {
241 0     0 0 0 my ($self, $modes) = @_;
242 0         0 my $modestring = "";
243 0         0 my @modes = @{$modes};
  0         0  
244 0         0 my $longest = length ((reverse sort {length $a <=> length $b} map { $_->[1] } @modes)[0]);
  0         0  
  0         0  
245             my $format = " %-".
246 0         0 (length ((reverse sort {length $a <=> length $b} map { $_->[1] } @modes)[0])).
  0         0  
  0         0  
247             "s\t(%s)\n";
248 0         0 foreach (@modes) {
249 0         0 $modestring .= sprintf $format, $_->[1], $_->[3];
250             }
251 0         0 $modestring .= sprintf "\n";
252 0         0 $Monitoring::GLPlugin::plugin->{modestring} = $modestring;
253             }
254              
255             sub add_arg {
256 75     75 0 133 my ($self, %args) = @_;
257 75 100       117 if ($args{help} =~ /^--mode/) {
258 3         9 $args{help} .= "\n".$Monitoring::GLPlugin::plugin->{modestring};
259             }
260 75         143 $Monitoring::GLPlugin::plugin->{opts}->add_arg(%args);
261             }
262              
263             sub mod_arg {
264 0     0 0 0 my ($self, @arg) = @_;
265 0         0 $Monitoring::GLPlugin::plugin->{opts}->mod_arg(@arg);
266             }
267              
268             sub add_mode {
269 3     3 0 27 my ($self, %args) = @_;
270 3         4 push(@{$Monitoring::GLPlugin::plugin->{modes}}, \%args);
  3         9  
271 3         4 my $longest = length ((reverse sort {length $a <=> length $b} map { $_->{spec} } @{$Monitoring::GLPlugin::plugin->{modes}})[0]);
  0         0  
  3         11  
  3         5  
272             my $format = " %-".
273 3         5 (length ((reverse sort {length $a <=> length $b} map { $_->{spec} } @{$Monitoring::GLPlugin::plugin->{modes}})[0])).
  0         0  
  3         11  
  3         6  
274             "s\t(%s)\n";
275 3         6 $Monitoring::GLPlugin::plugin->{modestring} = "";
276 3         2 foreach (@{$Monitoring::GLPlugin::plugin->{modes}}) {
  3         7  
277 3         13 $Monitoring::GLPlugin::plugin->{modestring} .= sprintf $format, $_->{spec}, $_->{help};
278             }
279 3         7 $Monitoring::GLPlugin::plugin->{modestring} .= "\n";
280             }
281              
282             sub validate_args {
283 1     1 0 4 my ($self) = @_;
284 1 50 33     3 if ($self->opts->mode =~ /^my-([^\-.]+)/) {
    50          
    50          
    50          
285 0         0 my $param = $self->opts->mode;
286 0         0 $param =~ s/\-/::/g;
287 0         0 $self->add_mode(
288             internal => $param,
289             spec => $self->opts->mode,
290             alias => undef,
291             help => 'my extension',
292             );
293             } elsif ($self->opts->mode eq 'encode') {
294 0         0 my $input = <>;
295 0         0 chomp $input;
296 0         0 $input =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;
  0         0  
297 0         0 printf "%s\n", $input;
298 0         0 exit 0;
299             } elsif ($self->opts->mode eq 'decode') {
300 0 0       0 if (! -t STDIN) {
301 0         0 my $input = <>;
302 0         0 chomp $input;
303 0         0 $input =~ s/%([A-Za-z0-9]{2})/chr(hex($1))/seg;
  0         0  
304 0         0 printf "%s\n", $input;
305 0         0 exit OK;
306             } else {
307 0 0       0 if ($self->opts->name) {
308 0         0 my $input = $self->opts->name;
309 0         0 $input =~ s/%([A-Za-z0-9]{2})/chr(hex($1))/seg;
  0         0  
310 0         0 printf "%s\n", $input;
311 0         0 exit OK;
312             } else {
313 0         0 printf "i can't find your encoded statement. use --name or pipe it in my stdin\n";
314 0         0 exit UNKNOWN;
315             }
316             }
317             } elsif ((! grep { $self->opts->mode eq $_ } map { $_->{spec} } @{$Monitoring::GLPlugin::plugin->{modes}}) &&
318             (! grep { $self->opts->mode eq $_ } map { defined $_->{alias} ? @{$_->{alias}} : () } @{$Monitoring::GLPlugin::plugin->{modes}})) {
319 0         0 printf "UNKNOWN - mode %s\n", $self->opts->mode;
320 0         0 $self->opts->print_help();
321 0         0 exit 3;
322             }
323 1 50 33     2 if ($self->opts->name && $self->opts->name =~ /(%22)|(%27)/) {
324 0         0 my $name = $self->opts->name;
325 0         0 $name =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
  0         0  
326 0         0 $self->override_opt('name', $name);
327             }
328             $Monitoring::GLPlugin::mode = (
329 1         3 map { $_->{internal} }
330             grep {
331             ($self->opts->mode eq $_->{spec}) ||
332 1 50 0     2 ( defined $_->{alias} && grep { $self->opts->mode eq $_ } @{$_->{alias}})
  0         0  
  0         0  
333 1         2 } @{$Monitoring::GLPlugin::plugin->{modes}}
  1         3  
334             )[0];
335 1 50       2 if ($self->opts->multiline) {
336 0         0 $ENV{NRPE_MULTILINESUPPORT} = 1;
337             } else {
338 1         5 $ENV{NRPE_MULTILINESUPPORT} = 0;
339             }
340 1 50 33     3 if ($self->opts->can("statefilesdir") && ! $self->opts->statefilesdir) {
341 0 0       0 if ($^O =~ /MSWin/) {
    0          
342 0 0       0 if (defined $ENV{TEMP}) {
    0          
    0          
343 0         0 $self->override_opt('statefilesdir', $ENV{TEMP}."/".$Monitoring::GLPlugin::plugin->{name});
344             } elsif (defined $ENV{TMP}) {
345 0         0 $self->override_opt('statefilesdir', $ENV{TMP}."/".$Monitoring::GLPlugin::plugin->{name});
346             } elsif (defined $ENV{windir}) {
347 0         0 $self->override_opt('statefilesdir', File::Spec->catfile($ENV{windir}, 'Temp')."/".$Monitoring::GLPlugin::plugin->{name});
348             } else {
349 0         0 $self->override_opt('statefilesdir', "C:/".$Monitoring::GLPlugin::plugin->{name});
350             }
351             } elsif (exists $ENV{OMD_ROOT}) {
352 0         0 $self->override_opt('statefilesdir', $ENV{OMD_ROOT}."/var/tmp/".$Monitoring::GLPlugin::plugin->{name});
353             } else {
354 0         0 $self->override_opt('statefilesdir', "/var/tmp/".$Monitoring::GLPlugin::plugin->{name});
355             }
356             }
357 1 50       2 $Monitoring::GLPlugin::plugin->{statefilesdir} = $self->opts->statefilesdir
358             if $self->opts->can("statefilesdir");
359 1 50 33     2 if ($self->opts->can("warningx") && $self->opts->warningx) {
360 0         0 foreach my $key (keys %{$self->opts->warningx}) {
  0         0  
361             $self->set_thresholds(metric => $key,
362 0         0 warning => $self->opts->warningx->{$key});
363             }
364             }
365 1 50 33     2 if ($self->opts->can("criticalx") && $self->opts->criticalx) {
366 0         0 foreach my $key (keys %{$self->opts->criticalx}) {
  0         0  
367             $self->set_thresholds(metric => $key,
368 0         0 critical => $self->opts->criticalx->{$key});
369             }
370             }
371 1 50       8 $self->set_timeout_alarm() if ! $SIG{'ALRM'};
372             }
373              
374             sub set_timeout_alarm {
375 1     1 0 2 my ($self, $timeout, $handler) = @_;
376 1   33     4 $timeout ||= $self->opts->timeout;
377             $handler ||= sub {
378             printf "UNKNOWN - %s timed out after %d seconds\n",
379 0     0   0 $Monitoring::GLPlugin::plugin->{name}, $self->opts->timeout;
380 0         0 exit 3;
381 1   50     8 };
382 3     3   1304 use POSIX ':signal_h';
  3         13540  
  3         35  
383 1 50       5 if ($^O =~ /MSWin/) {
384 0         0 local $SIG{'ALRM'} = $handler;
385             } else {
386 1         17 my $mask = POSIX::SigSet->new( SIGALRM );
387 1         7 my $action = POSIX::SigAction->new(
388             $handler, $mask
389             );
390 1         9 my $oldaction = POSIX::SigAction->new();
391 1         43 sigaction(SIGALRM ,$action ,$oldaction );
392             }
393 1         13 alarm(int($timeout)); # 1 second before the global unknown timeout
394             }
395              
396             #########################################################
397             # global helpers
398             #
399             sub set_variable {
400 2     2 0 4 my ($self, $key, $value) = @_;
401 2         5 $Monitoring::GLPlugin::variables->{$key} = $value;
402             }
403              
404             sub get_variable {
405 130     130 0 154 my ($self, $key, $fallback) = @_;
406             return exists $Monitoring::GLPlugin::variables->{$key} ?
407 130 50       494 $Monitoring::GLPlugin::variables->{$key} : $fallback;
408             }
409              
410             sub debug {
411 130     130 0 7008 my ($self, $format, @message) = @_;
412 130         228 my $tracefile = "/tmp/".$Monitoring::GLPlugin::pluginname.".trace";
413 130 50       1278 $self->{trace} = -f $tracefile ? 1 : 0;
414 130 50 33     248 if ($self->get_variable("verbose") &&
415             $self->get_variable("verbose") > $self->get_variable("verbosity", 10)) {
416 0         0 printf("%s: ", scalar localtime);
417 0         0 printf($format, @message);
418 0         0 printf "\n";
419             }
420 130 50       280 if ($self->{trace}) {
421 0         0 my $logfh = IO::File->new();
422 0         0 $logfh->autoflush(1);
423 0 0       0 if ($logfh->open($tracefile, "a")) {
424 0         0 $logfh->printf("%s: ", scalar localtime);
425 0         0 $logfh->printf($format, @message);
426 0         0 $logfh->printf("\n");
427 0         0 $logfh->close();
428             }
429             }
430             }
431              
432             sub filter_namex {
433 0     0 0 0 my ($self, $opt, $name) = @_;
434 0 0       0 if ($opt) {
435 0 0       0 if ($self->opts->regexp) {
436 0 0       0 if ($name =~ /$opt/i) {
437 0         0 return 1;
438             }
439             } else {
440 0 0       0 if (lc $opt eq lc $name) {
441 0         0 return 1;
442             }
443             }
444             } else {
445 0         0 return 1;
446             }
447 0         0 return 0;
448             }
449              
450             sub filter_name {
451 0     0 0 0 my ($self, $name) = @_;
452 0         0 return $self->filter_namex($self->opts->name, $name);
453             }
454              
455             sub filter_name2 {
456 0     0 0 0 my ($self, $name) = @_;
457 0         0 return $self->filter_namex($self->opts->name2, $name);
458             }
459              
460             sub filter_name3 {
461 0     0 0 0 my ($self, $name) = @_;
462 0         0 return $self->filter_namex($self->opts->name3, $name);
463             }
464              
465             sub version_is_minimum {
466 0     0 0 0 my ($self, $version) = @_;
467 0         0 my $installed_version;
468 0         0 my $newer = 1;
469 0 0       0 if ($self->get_variable("version")) {
    0          
470 0         0 $installed_version = $self->get_variable("version");
471             } elsif (exists $self->{version}) {
472 0         0 $installed_version = $self->{version};
473             } else {
474 0         0 return 0;
475             }
476 0 0       0 my @v1 = map { $_ eq "x" ? 0 : $_ } split(/\./, $version);
  0         0  
477 0         0 my @v2 = split(/\./, $installed_version);
478 0 0       0 if (scalar(@v1) > scalar(@v2)) {
    0          
479 0         0 push(@v2, (0) x (scalar(@v1) - scalar(@v2)));
480             } elsif (scalar(@v2) > scalar(@v1)) {
481 0         0 push(@v1, (0) x (scalar(@v2) - scalar(@v1)));
482             }
483 0         0 foreach my $pos (0..$#v1) {
484 0 0       0 if ($v2[$pos] > $v1[$pos]) {
    0          
485 0         0 $newer = 1;
486 0         0 last;
487             } elsif ($v2[$pos] < $v1[$pos]) {
488 0         0 $newer = 0;
489 0         0 last;
490             }
491             }
492 0         0 return $newer;
493             }
494              
495             sub accentfree {
496 0     0 0 0 my ($self, $text) = @_;
497             # thanks mycoyne who posted this accent-remove-algorithm
498             # http://www.experts-exchange.com/Programming/Languages/Scripting/Perl/Q_23275533.html#a21234612
499 0         0 my @transformed;
500 0         0 my %replace = (
501             '9a' => 's', '9c' => 'oe', '9e' => 'z', '9f' => 'Y', 'c0' => 'A', 'c1' => 'A',
502             'c2' => 'A', 'c3' => 'A', 'c4' => 'A', 'c5' => 'A', 'c6' => 'AE', 'c7' => 'C',
503             'c8' => 'E', 'c9' => 'E', 'ca' => 'E', 'cb' => 'E', 'cc' => 'I', 'cd' => 'I',
504             'ce' => 'I', 'cf' => 'I', 'd0' => 'D', 'd1' => 'N', 'd2' => 'O', 'd3' => 'O',
505             'd4' => 'O', 'd5' => 'O', 'd6' => 'O', 'd8' => 'O', 'd9' => 'U', 'da' => 'U',
506             'db' => 'U', 'dc' => 'U', 'dd' => 'Y', 'e0' => 'a', 'e1' => 'a', 'e2' => 'a',
507             'e3' => 'a', 'e4' => 'a', 'e5' => 'a', 'e6' => 'ae', 'e7' => 'c', 'e8' => 'e',
508             'e9' => 'e', 'ea' => 'e', 'eb' => 'e', 'ec' => 'i', 'ed' => 'i', 'ee' => 'i',
509             'ef' => 'i', 'f0' => 'o', 'f1' => 'n', 'f2' => 'o', 'f3' => 'o', 'f4' => 'o',
510             'f5' => 'o', 'f6' => 'o', 'f8' => 'o', 'f9' => 'u', 'fa' => 'u', 'fb' => 'u',
511             'fc' => 'u', 'fd' => 'y', 'ff' => 'y',
512             );
513 0         0 my @letters = split //, $text;;
514 0         0 for (my $i = 0; $i <= $#letters; $i++) {
515 0         0 my $hex = sprintf "%x", ord($letters[$i]);
516 0 0       0 $letters[$i] = $replace{$hex} if (exists $replace{$hex});
517             }
518 0         0 push @transformed, @letters;
519 0         0 return join '', @transformed;
520             }
521              
522             sub dump {
523 0     0 0 0 my ($self) = @_;
524 0         0 my $class = ref($self);
525 0         0 $class =~ s/^.*:://;
526 0 0       0 if (exists $self->{flat_indices}) {
527 0         0 printf "[%s_%s]\n", uc $class, $self->{flat_indices};
528             } else {
529 0         0 printf "[%s]\n", uc $class;
530             }
531 0         0 foreach (grep !/^(info|trace|warning|critical|blacklisted|extendedinfo|flat_indices|indices)$/, sort keys %{$self}) {
  0         0  
532 0 0 0     0 printf "%s: %s\n", $_, $self->{$_} if defined $self->{$_} && ref($self->{$_}) ne "ARRAY";
533             }
534 0 0       0 if ($self->{info}) {
535 0         0 printf "info: %s\n", $self->{info};
536             }
537 0         0 printf "\n";
538 0         0 foreach (grep !/^(info|trace|warning|critical|blacklisted|extendedinfo|flat_indices|indices)$/, sort keys %{$self}) {
  0         0  
539 0 0 0     0 if (defined $self->{$_} && ref($self->{$_}) eq "ARRAY") {
540 0         0 my $have_flat_indices = 1;
541 0         0 foreach my $obj (@{$self->{$_}}) {
  0         0  
542 0 0 0     0 $have_flat_indices = 0 if (ref($obj) ne "HASH" || ! exists $obj->{flat_indices});
543             }
544 0 0       0 if ($have_flat_indices) {
545 0         0 foreach my $obj (sort {
546 0         0 join('', map { sprintf("%30d",$_) } split( /\./, $a->{flat_indices})) cmp
547 0         0 join('', map { sprintf("%30d",$_) } split( /\./, $b->{flat_indices}))
  0         0  
548 0         0 } @{$self->{$_}}) {
549 0         0 $obj->dump();
550             }
551             } else {
552 0         0 foreach my $obj (@{$self->{$_}}) {
  0         0  
553 0 0 0     0 $obj->dump() if UNIVERSAL::can($obj, "isa") && $obj->can("dump");
554             }
555             }
556             }
557             }
558             }
559              
560             sub table_ascii {
561 0     0 0 0 my ($self, $table, $titles) = @_;
562 0         0 my $text = "";
563 0         0 my $column_length = {};
564 0         0 my $column = 0;
565 0         0 foreach (@{$titles}) {
  0         0  
566 0         0 $column_length->{$column++} = length($_);
567             }
568 0         0 foreach my $tr (@{$table}) {
  0         0  
569 0 0       0 @{$tr} = map { ref($_) eq "ARRAY" ? $_->[0] : $_; } @{$tr};
  0         0  
  0         0  
  0         0  
570 0         0 $column = 0;
571 0         0 foreach my $td (@{$tr}) {
  0         0  
572 0 0       0 if (length($td) > $column_length->{$column}) {
573 0         0 $column_length->{$column} = length($td);
574             }
575 0         0 $column++;
576             }
577             }
578 0         0 $column = 0;
579 0         0 foreach (@{$titles}) {
  0         0  
580 0         0 $column_length->{$column} = "%".($column_length->{$column} + 3)."s";
581 0         0 $column++;
582             }
583 0         0 $column = 0;
584 0         0 foreach (@{$titles}) {
  0         0  
585 0         0 $text .= sprintf $column_length->{$column++}, $_;
586             }
587 0         0 $text .= "\n";
588 0         0 foreach my $tr (@{$table}) {
  0         0  
589 0         0 $column = 0;
590 0         0 foreach my $td (@{$tr}) {
  0         0  
591 0         0 $text .= sprintf $column_length->{$column++}, $td;
592             }
593 0         0 $text .= "\n";
594             }
595 0         0 return $text;
596             }
597              
598             sub table_html {
599 0     0 0 0 my ($self, $table, $titles) = @_;
600 0         0 my $text = "";
601 0         0 $text .= ""; "; ", $_; "; "; ", $class, $td; ";
602 0         0 $text .= "
603 0         0 foreach (@{$titles}) {
  0         0  
604 0         0 $text .= sprintf "%s
605             }
606 0         0 $text .= "
607 0         0 foreach my $tr (@{$table}) {
  0         0  
608 0         0 $text .= "
609 0         0 foreach my $td (@{$tr}) {
  0         0  
610 0         0 my $class = "statusOK";
611 0 0       0 if (ref($td) eq "ARRAY") {
612             $class = {
613             0 => "statusOK",
614             1 => "statusWARNING",
615             2 => "statusCRITICAL",
616             3 => "statusUNKNOWN",
617 0         0 }->{$td->[1]};
618 0         0 $td = $td->[0];
619             }
620 0         0 $text .= sprintf "%s
621             }
622 0         0 $text .= "
623             }
624 0         0 $text .= "
";
625 0         0 return $text;
626             }
627              
628             sub load_my_extension {
629 0     0 0 0 my ($self) = @_;
630 0 0       0 if ($self->opts->mode =~ /^my-([^-.]+)/) {
631 0         0 my $class = $1;
632 0         0 my $loaderror = undef;
633 0         0 substr($class, 0, 1) = uc substr($class, 0, 1);
634 0 0       0 if (! $self->opts->get("with-mymodules-dyn-dir")) {
635 0         0 $self->override_opt("with-mymodules-dyn-dir", "");
636             }
637 0         0 my $plugin_name = $Monitoring::GLPlugin::pluginname;
638 0         0 $plugin_name =~ /check_(.*?)_health/;
639 0         0 $plugin_name = "Check".uc(substr($1, 0, 1)).substr($1, 1)."Health";
640 0         0 foreach my $libpath (split(":", $self->opts->get("with-mymodules-dyn-dir"))) {
641 0         0 foreach my $extmod (glob $libpath."/".$plugin_name."*.pm") {
642 0         0 my $stderrvar;
643 0         0 *SAVEERR = *STDERR;
644 0         0 open OUT ,'>',\$stderrvar;
645 0         0 *STDERR = *OUT;
646 0         0 eval {
647 0         0 $self->debug(sprintf "loading module %s", $extmod);
648 0         0 require $extmod;
649             };
650 0         0 *STDERR = *SAVEERR;
651 0 0       0 if ($@) {
652 0         0 $loaderror = $extmod;
653 0         0 $self->debug(sprintf "failed loading module %s: %s", $extmod, $@);
654             }
655             }
656             }
657 0         0 my $original_class = ref($self);
658 0         0 my $original_init = $self->can("init");
659 0 0       0 $self->compatibility_class() if $self->can('compatibility_class');
660 0         0 bless $self, "My$class";
661 0 0       0 $self->compatibility_methods() if $self->can('compatibility_methods');
662 0 0       0 if ($self->isa("Monitoring::GLPlugin")) {
663 0         0 my $new_init = $self->can("init");
664 0 0       0 if ($new_init == $original_init) {
665 0         0 $self->add_unknown(
666             sprintf "Class %s needs an init() method", ref($self));
667             } else {
668             # now go back to check_*_health.pl where init() will be called
669             }
670             } else {
671 0         0 bless $self, $original_class;
672 0 0       0 $self->add_unknown(
673             sprintf "Class %s is not a subclass of Monitoring::GLPlugin%s",
674             "My$class",
675             $loaderror ? sprintf " (syntax error in %s?)", $loaderror : "" );
676 0         0 my ($code, $message) = $self->check_messages(join => ', ', join_all => ', ');
677 0         0 $self->nagios_exit($code, $message);
678             }
679             }
680             }
681              
682             sub decode_password {
683 0     0 0 0 my ($self, $password) = @_;
684 0 0 0     0 if ($password && $password =~ /^rfc3986:\/\/(.*)/) {
685 0         0 $password = $1;
686 0         0 $password =~ s/%([A-Za-z0-9]{2})/chr(hex($1))/seg;
  0         0  
687             }
688 0         0 return $password;
689             }
690              
691             sub number_of_bits {
692 0     0 0 0 my ($self, $unit) = @_;
693             # https://en.wikipedia.org/wiki/Data_rate_units
694 0         0 my $bits = {
695             'bit' => 1, # Bit per second
696             'B' => 8, # Byte per second, 8 bits per second
697             'kbit' => 1000, # Kilobit per second, 1,000 bits per second
698             'kb' => 1000, # Kilobit per second, 1,000 bits per second
699             'Kibit' => 1024, # Kibibit per second, 1,024 bits per second
700             'kB' => 8000, # Kilobyte per second, 8,000 bits per second
701             'KiB' => 8192, # Kibibyte per second, 1,024 bytes per second
702             'Mbit' => 1000000, # Megabit per second, 1,000,000 bits per second
703             'Mb' => 1000000, # Megabit per second, 1,000,000 bits per second
704             'Mibit' => 1048576, # Mebibit per second, 1,024 kibibits per second
705             'MB' => 8000000, # Megabyte per second, 1,000 kilobytes per second
706             'MiB' => 8388608, # Mebibyte per second, 1,024 kibibytes per second
707             'Gbit' => 1000000000, # Gigabit per second, 1,000 megabits per second
708             'Gb' => 1000000000, # Gigabit per second, 1,000 megabits per second
709             'Gibit' => 1073741824, # Gibibit per second, 1,024 mebibits per second
710             'GB' => 8000000000, # Gigabyte per second, 1,000 megabytes per second
711             'GiB' => 8589934592, # Gibibyte per second, 8192 mebibits per second
712             'Tbit' => 1000000000000, # Terabit per second, 1,000 gigabits per second
713             'Tb' => 1000000000000, # Terabit per second, 1,000 gigabits per second
714             'Tibit' => 1099511627776, # Tebibit per second, 1,024 gibibits per second
715             'TB' => 8000000000000, # Terabyte per second, 1,000 gigabytes per second
716             # eigene kreationen
717             'Bits' => 1,
718             'Bit' => 1, # Bit per second
719             'KB' => 1024, # Kilobyte (like disk kilobyte)
720             'KBi' => 1024, # -"-
721             'MBi' => 1024 * 1024, # Megabyte (like disk megabyte)
722             'GBi' => 1024 * 1024 * 1024, # Gigybate (like disk gigybyte)
723             };
724 0 0       0 if (exists $bits->{$unit}) {
725 0         0 return $bits->{$unit};
726             } else {
727 0         0 return 0;
728             }
729             }
730              
731              
732             #########################################################
733             # runtime methods
734             #
735             sub mode : lvalue {
736 74     74 0 63 my ($self) = @_;
737 74         196 $Monitoring::GLPlugin::mode;
738             }
739              
740             sub statefilesdir {
741 231     231 0 551 my ($self) = @_;
742 231         1217 return $Monitoring::GLPlugin::plugin->{statefilesdir};
743             }
744              
745             sub opts { # die beiden _nicht_ in AUTOLOAD schieben, das kracht!
746 348     348 0 300 my ($self) = @_;
747 348         718 return $Monitoring::GLPlugin::plugin->opts();
748             }
749              
750             sub getopts {
751 2     2 0 11 my ($self, $envparams) = @_;
752 2   50     10 $envparams ||= [];
753 2         9 $Monitoring::GLPlugin::plugin->getopts();
754             # es kann sein, dass beim aufraeumen zum schluss als erstes objekt
755             # das $Monitoring::GLPlugin::plugin geloescht wird. in anderen destruktoren
756             # (insb. fuer dbi disconnect) steht dann $self->opts->verbose
757             # nicht mehr zur verfuegung bzw. $Monitoring::GLPlugin::plugin->opts ist undef.
758 2         11 $self->set_variable("verbose", $self->opts->verbose);
759             #
760             # die gueltigkeit von modes wird bereits hier geprueft und nicht danach
761             # in validate_args. (zwischen getopts und validate_args wird
762             # normalerweise classify aufgerufen, welches bereits eine verbindung
763             # zum endgeraet herstellt. bei falschem mode waere das eine verschwendung
764             # bzw. durch den exit3 ein evt. unsauberes beenden der verbindung.
765 2 50 33     2 if ((! grep { $self->opts->mode eq $_ } map { $_->{spec} } @{$Monitoring::GLPlugin::plugin->{modes}}) &&
766             (! grep { $self->opts->mode eq $_ } map { defined $_->{alias} ? @{$_->{alias}} : () } @{$Monitoring::GLPlugin::plugin->{modes}})) {
767 0 0       0 if ($self->opts->mode !~ /^my-/) {
768 0         0 printf "UNKNOWN - mode %s\n", $self->opts->mode;
769 0         0 $self->opts->print_help();
770 0         0 exit 3;
771             }
772             }
773             }
774              
775             sub add_ok {
776 0     0 0 0 my ($self, $message) = @_;
777 0   0     0 $message ||= $self->{info};
778 0         0 $self->add_message(OK, $message);
779             }
780              
781             sub add_warning {
782 0     0 0 0 my ($self, $message) = @_;
783 0   0     0 $message ||= $self->{info};
784 0         0 $self->add_message(WARNING, $message);
785             }
786              
787             sub add_critical {
788 0     0 0 0 my ($self, $message) = @_;
789 0   0     0 $message ||= $self->{info};
790 0         0 $self->add_message(CRITICAL, $message);
791             }
792              
793             sub add_unknown {
794 0     0 0 0 my ($self, $message) = @_;
795 0   0     0 $message ||= $self->{info};
796 0         0 $self->add_message(UNKNOWN, $message);
797             }
798              
799             sub add_ok_mitigation {
800 0     0 0 0 my ($self, $message) = @_;
801 0 0       0 if (defined $self->opts->mitigation()) {
802 0         0 $self->add_message($self->opts->mitigation(), $message);
803             } else {
804 0         0 $self->add_ok($message);
805             }
806             }
807              
808             sub add_warning_mitigation {
809 0     0 0 0 my ($self, $message) = @_;
810 0 0       0 if (defined $self->opts->mitigation()) {
811 0         0 $self->add_message($self->opts->mitigation(), $message);
812             } else {
813 0         0 $self->add_warning($message);
814             }
815             }
816              
817             sub add_critical_mitigation {
818 0     0 0 0 my ($self, $message) = @_;
819 0 0       0 if (defined $self->opts->mitigation()) {
820 0         0 $self->add_message($self->opts->mitigation(), $message);
821             } else {
822 0         0 $self->add_critical($message);
823             }
824             }
825              
826             sub add_unknown_mitigation {
827 0     0 0 0 my ($self, $message) = @_;
828 0 0       0 if (defined $self->opts->mitigation()) {
829 0         0 $self->add_message($self->opts->mitigation(), $message);
830             } else {
831 0         0 $self->add_unknown($message);
832             }
833             }
834              
835             sub add_message {
836 31     31 0 39 my ($self, $level, $message) = @_;
837 31   33     61 $message ||= $self->{info};
838 31 50       79 $Monitoring::GLPlugin::plugin->add_message($level, $message)
839             unless $self->is_blacklisted();
840 31 50       96 if (exists $self->{failed}) {
841 0 0 0     0 if ($level == UNKNOWN && $self->{failed} == OK) {
    0          
842 0         0 $self->{failed} = $level;
843             } elsif ($level > $self->{failed}) {
844 0         0 $self->{failed} = $level;
845             }
846             }
847             }
848              
849             sub clear_ok {
850 0     0 0 0 my ($self) = @_;
851 0         0 $self->clear_messages(OK);
852             }
853              
854             sub clear_warning {
855 0     0 0 0 my ($self) = @_;
856 0         0 $self->clear_messages(WARNING);
857             }
858              
859             sub clear_critical {
860 0     0 0 0 my ($self) = @_;
861 0         0 $self->clear_messages(CRITICAL);
862             }
863              
864             sub clear_unknown {
865 0     0 0 0 my ($self) = @_;
866 0         0 $self->clear_messages(UNKNOWN);
867             }
868              
869             sub clear_all { # deprecated, use clear_messages
870 0     0 0 0 my ($self) = @_;
871 0         0 $self->clear_ok();
872 0         0 $self->clear_warning();
873 0         0 $self->clear_critical();
874 0         0 $self->clear_unknown();
875             }
876              
877             sub set_level {
878 0     0 0 0 my ($self, $code) = @_;
879 0 0       0 $code = (qw(ok warning critical unknown))[$code] if $code =~ /^\d+$/;
880 0         0 $code = lc $code;
881 0 0       0 if (! exists $self->{tmp_level}) {
882             $self->{tmp_level} = {
883 0         0 ok => 0,
884             warning => 0,
885             critical => 0,
886             unknown => 0,
887             };
888             }
889 0         0 $self->{tmp_level}->{$code}++;
890             }
891              
892             sub get_level {
893 0     0 0 0 my ($self) = @_;
894 0 0       0 return OK if ! exists $self->{tmp_level};
895 0         0 my $code = OK;
896 0 0 0     0 $code ||= CRITICAL if $self->{tmp_level}->{critical};
897 0 0 0     0 $code ||= WARNING if $self->{tmp_level}->{warning};
898 0 0 0     0 $code ||= UNKNOWN if $self->{tmp_level}->{unknown};
899 0         0 return $code;
900             }
901              
902             #########################################################
903             # blacklisting
904             #
905             sub blacklist {
906 0     0 0 0 my ($self) = @_;
907 0         0 $self->{blacklisted} = 1;
908             }
909              
910             sub add_blacklist {
911 0     0 0 0 my ($self, $list) = @_;
912 0         0 $Monitoring::GLPlugin::blacklist = join('/',
913             (split('/', $self->opts->blacklist), $list));
914             }
915              
916             sub is_blacklisted {
917 31     31 0 30 my ($self) = @_;
918 31 50       53 if (! $self->opts->can("blacklist")) {
919 0         0 return 0;
920             }
921 31 100       69 if (! exists $self->{blacklisted}) {
922 1         2 $self->{blacklisted} = 0;
923             }
924 31 50 33     138 if (exists $self->{blacklisted} && $self->{blacklisted}) {
925 0         0 return $self->{blacklisted};
926             }
927             # FAN:459,203/TEMP:102229/ENVSUBSYSTEM
928             # FAN_459,FAN_203,TEMP_102229,ENVSUBSYSTEM
929 31 50       53 if ($self->opts->blacklist =~ /_/) {
930 0         0 foreach my $bl_item (split(/,/, $self->opts->blacklist)) {
931 0 0       0 if ($bl_item eq $self->internal_name()) {
932 0         0 $self->{blacklisted} = 1;
933             }
934             }
935             } else {
936 31         56 foreach my $bl_items (split(/\//, $self->opts->blacklist)) {
937 0 0       0 if ($bl_items =~ /^(\w+):([\:\d\-,]+)$/) {
    0          
938 0         0 my $bl_type = $1;
939 0         0 my $bl_names = $2;
940 0         0 foreach my $bl_name (split(/,/, $bl_names)) {
941 0 0       0 if ($bl_type."_".$bl_name eq $self->internal_name()) {
942 0         0 $self->{blacklisted} = 1;
943             }
944             }
945             } elsif ($bl_items =~ /^(\w+)$/) {
946 0 0       0 if ($bl_items eq $self->internal_name()) {
947 0         0 $self->{blacklisted} = 1;
948             }
949             }
950             }
951             }
952 31         152 return $self->{blacklisted};
953             }
954              
955             #########################################################
956             # additional info
957             #
958             sub add_info {
959 0     0 0 0 my ($self, $info) = @_;
960 0 0       0 $info = $self->is_blacklisted() ? $info.' (blacklisted)' : $info;
961 0         0 $self->{info} = $info;
962 0         0 push(@{$Monitoring::GLPlugin::info}, $info);
  0         0  
963             }
964              
965             sub annotate_info {
966 0     0 0 0 my ($self, $annotation) = @_;
967 0         0 my $lastinfo = pop(@{$Monitoring::GLPlugin::info});
  0         0  
968 0         0 $lastinfo .= sprintf ' (%s)', $annotation;
969 0         0 $self->{info} = $lastinfo;
970 0         0 push(@{$Monitoring::GLPlugin::info}, $lastinfo);
  0         0  
971             }
972              
973             sub add_extendedinfo { # deprecated
974 0     0 0 0 my ($self, $info) = @_;
975 0         0 $self->{extendedinfo} = $info;
976 0 0       0 return if ! $self->opts->extendedinfo;
977 0         0 push(@{$Monitoring::GLPlugin::extendedinfo}, $info);
  0         0  
978             }
979              
980             sub get_info {
981 0     0 0 0 my ($self, $separator) = @_;
982 0   0     0 $separator ||= ' ';
983 0         0 return join($separator , @{$Monitoring::GLPlugin::info});
  0         0  
984             }
985              
986             sub get_last_info {
987 0     0 0 0 my ($self) = @_;
988 0         0 return pop(@{$Monitoring::GLPlugin::info});
  0         0  
989             }
990              
991             sub get_extendedinfo {
992 0     0 0 0 my ($self, $separator) = @_;
993 0   0     0 $separator ||= ' ';
994 0         0 return join($separator, @{$Monitoring::GLPlugin::extendedinfo});
  0         0  
995             }
996              
997             sub add_summary { # deprecated
998 0     0 0 0 my ($self, $summary) = @_;
999 0         0 push(@{$Monitoring::GLPlugin::summary}, $summary);
  0         0  
1000             }
1001              
1002             sub get_summary {
1003 0     0 0 0 my ($self) = @_;
1004 0         0 return join(', ', @{$Monitoring::GLPlugin::summary});
  0         0  
1005             }
1006              
1007             #########################################################
1008             # persistency
1009             #
1010             sub valdiff {
1011 31     31 0 40023739 my ($self, $pparams, @keys) = @_;
1012 31         56 my %params = %{$pparams};
  31         215  
1013 31         72 my $now = time;
1014 31         46 my $newest_history_set = {};
1015 31 50       147 $params{freeze} = 0 if ! $params{freeze};
1016 31         83 my $mode = "normal";
1017 31 50 66     120 if ($self->opts->lookback && $self->opts->lookback == 99999 && $params{freeze} == 0) {
    50 33        
    50 66        
    100 33        
      66        
      33        
1018 0         0 $mode = "lookback_freeze_chill";
1019             } elsif ($self->opts->lookback && $self->opts->lookback == 99999 && $params{freeze} == 1) {
1020 0         0 $mode = "lookback_freeze_shockfrost";
1021             } elsif ($self->opts->lookback && $self->opts->lookback == 99999 && $params{freeze} == 2) {
1022 0         0 $mode = "lookback_freeze_defrost";
1023             } elsif ($self->opts->lookback) {
1024 21         38 $mode = "lookback";
1025             }
1026             # lookback=99999, freeze=0(default)
1027             # nimm den letzten lauf und schreib ihn nach {cold}
1028             # vergleich dann
1029             # wenn es frozen gibt, vergleich frozen und den letzten lauf
1030             # sonst den letzten lauf und den aktuellen lauf
1031             # lookback=99999, freeze=1
1032             # wird dann aufgerufen,wenn nach dem freeze=0 ein problem festgestellt wurde
1033             # (also als 2.valdiff hinterher)
1034             # schreib cold nach frozen
1035             # lookback=99999, freeze=2
1036             # wird dann aufgerufen,wenn nach dem freeze=0 wieder alles ok ist
1037             # (also als 2.valdiff hinterher)
1038             # loescht frozen
1039             #
1040 31   66     146 my $last_values = $self->load_state(%params) || eval {
1041             my $empty_events = {};
1042             foreach (@keys) {
1043             if (ref($self->{$_}) eq "ARRAY") {
1044             $empty_events->{$_} = [];
1045             } else {
1046             $empty_events->{$_} = 0;
1047             }
1048             }
1049             $empty_events->{timestamp} = 0;
1050             if ($mode eq "lookback") {
1051             $empty_events->{lookback_history} = {};
1052             } elsif ($mode eq "lookback_freeze_chill") {
1053             $empty_events->{cold} = {};
1054             $empty_events->{frozen} = {};
1055             }
1056             $empty_events;
1057             };
1058 31         100 $self->{'delta_timestamp'} = $now - $last_values->{timestamp};
1059 31         82 foreach (@keys) {
1060 51 50       152 if ($mode eq "lookback_freeze_chill") {
    100          
1061             # die werte vom letzten lauf wegsichern.
1062             # vielleicht gibts gleich einen freeze=1, dann muessen die eingefroren werden
1063 0 0       0 if (exists $last_values->{$_}) {
1064 0 0       0 if (ref($self->{$_}) eq "ARRAY") {
1065 0         0 $last_values->{cold}->{$_} = [];
1066 0         0 foreach my $value (@{$last_values->{$_}}) {
  0         0  
1067 0         0 push(@{$last_values->{cold}->{$_}}, $value);
  0         0  
1068             }
1069             } else {
1070 0         0 $last_values->{cold}->{$_} = $last_values->{$_};
1071             }
1072             } else {
1073 0 0       0 if (ref($self->{$_}) eq "ARRAY") {
1074 0         0 $last_values->{cold}->{$_} = [];
1075             } else {
1076 0         0 $last_values->{cold}->{$_} = 0;
1077             }
1078             }
1079             # es wird so getan, als sei der frozen wert vom letzten lauf
1080 0 0       0 if (exists $last_values->{frozen}->{$_}) {
1081 0 0       0 if (ref($self->{$_}) eq "ARRAY") {
1082 0         0 $last_values->{$_} = [];
1083 0         0 foreach my $value (@{$last_values->{frozen}->{$_}}) {
  0         0  
1084 0         0 push(@{$last_values->{$_}}, $value);
  0         0  
1085             }
1086             } else {
1087 0         0 $last_values->{$_} = $last_values->{frozen}->{$_};
1088             }
1089             }
1090             } elsif ($mode eq "lookback") {
1091             # find a last_value in the history which fits lookback best
1092             # and overwrite $last_values->{$_} with historic data
1093 37 100       112 if (exists $last_values->{lookback_history}->{$_}) {
1094 34         47 foreach my $date (sort {$a <=> $b} keys %{$last_values->{lookback_history}->{$_}}) {
  365         347  
  34         210  
1095 190         222 $newest_history_set->{$_} = $last_values->{lookback_history}->{$_}->{$date};
1096 190         192 $newest_history_set->{timestamp} = $date;
1097             }
1098 34         50 foreach my $date (sort {$a <=> $b} keys %{$last_values->{lookback_history}->{$_}}) {
  365         288  
  34         104  
1099 42 100       95 if ($date >= ($now - $self->opts->lookback)) {
1100 32         53 $last_values->{$_} = $last_values->{lookback_history}->{$_}->{$date};
1101 32         62 $last_values->{timestamp} = $date;
1102 32 100       93 if (ref($last_values->{$_}) eq "ARRAY") {
1103             $self->debug(sprintf "oldest value of %s within lookback is size %s (age %d)",
1104 14         20 $_, scalar(@{$last_values->{$_}}), time - $date);
  14         64  
1105             } else {
1106             $self->debug(sprintf "oldest value of %s within lookback is %s (age %d)",
1107 18         115 $_, $last_values->{$_}, time - $date);
1108             }
1109 32         62 last;
1110             } else {
1111 10         50 $self->debug(sprintf "deprecate %s of age %d", $_, time - $date);
1112 10         23 delete $last_values->{lookback_history}->{$_}->{$date};
1113             }
1114             }
1115             }
1116             }
1117 51 50 66     253 if ($mode eq "normal" || $mode eq "lookback" || $mode eq "lookback_freeze_chill") {
      33        
1118 51 100       385 if ($self->{$_} =~ /^\d+\.*\d*$/) {
    50          
1119 31 50       89 $last_values->{$_} = 0 if ! exists $last_values->{$_};
1120 31 100       105 if ($self->{$_} >= $last_values->{$_}) {
    50          
1121 15         50 $self->{'delta_'.$_} = $self->{$_} - $last_values->{$_};
1122             } elsif ($self->{$_} eq $last_values->{$_}) {
1123             # dawischt! in einem fall wurde 131071.999023438 >= 131071.999023438 da oben nicht erkannt
1124             # subtrahieren ging auch daneben, weil ein winziger negativer wert rauskam.
1125 0         0 $self->{'delta_'.$_} = 0;
1126             } else {
1127 16 50       63 if ($mode =~ /lookback_freeze/) {
    100          
1128             # hier koennen delta-werte auch negativ sein, wenn z.b. peers verschwinden
1129 0         0 $self->{'delta_'.$_} = $self->{$_} - $last_values->{$_};
1130             } elsif (exists $params{lastarray}) {
1131 15         67 $self->{'delta_'.$_} = $self->{$_} - $last_values->{$_};
1132             } else {
1133             # vermutlich db restart und zaehler alle auf null
1134 1         3 $self->{'delta_'.$_} = $self->{$_};
1135             }
1136             }
1137 31         376 $self->debug(sprintf "delta_%s %f", $_, $self->{'delta_'.$_});
1138             $self->{$_.'_per_sec'} = $self->{'delta_timestamp'} ?
1139 31 100       179 $self->{'delta_'.$_} / $self->{'delta_timestamp'} : 0;
1140             } elsif (ref($self->{$_}) eq "ARRAY") {
1141 20 50 33     325 if ((! exists $last_values->{$_} || ! defined $last_values->{$_}) && exists $params{lastarray}) {
    50 33        
    50 33        
      33        
1142             # innerhalb der lookback-zeit wurde nichts in der lookback_history
1143             # gefunden. allenfalls irgendwas aelteres. normalerweise
1144             # wuerde jetzt das array als [] initialisiert.
1145             # d.h. es wuerde ein delta geben, @found s.u.
1146             # wenn man das nicht will, sondern einfach aktuelles array mit
1147             # dem array des letzten laufs vergleichen will, setzt man lastarray
1148 0         0 $last_values->{$_} = %{$newest_history_set} ?
1149 0 0       0 $newest_history_set->{$_} : []
1150             } elsif ((! exists $last_values->{$_} || ! defined $last_values->{$_}) && ! exists $params{lastarray}) {
1151 0 0       0 $last_values->{$_} = [] if ! exists $last_values->{$_};
1152             } elsif (exists $last_values->{$_} && ! defined $last_values->{$_}) {
1153             # $_ kann es auch ausserhalb des lookback_history-keys als normalen
1154             # key geben. der zeigt normalerweise auf den entspr. letzten
1155             # lookback_history eintrag. wurde der wegen ueberalterung abgeschnitten
1156             # ist der hier auch undef.
1157 0         0 $last_values->{$_} = %{$newest_history_set} ?
1158 0 0       0 $newest_history_set->{$_} : []
1159             }
1160 20         27 my %saved = map { $_ => 1 } @{$last_values->{$_}};
  80         157  
  20         53  
1161 20         35 my %current = map { $_ => 1 } @{$self->{$_}};
  68         98  
  20         45  
1162 20         37 my @found = grep(!defined $saved{$_}, @{$self->{$_}});
  20         82  
1163 20         29 my @lost = grep(!defined $current{$_}, @{$last_values->{$_}});
  20         78  
1164 20         63 $self->{'delta_found_'.$_} = \@found;
1165 20         99 $self->{'delta_lost_'.$_} = \@lost;
1166             }
1167             }
1168             }
1169 31         35 $params{save} = eval {
1170 31         49 my $empty_events = {};
1171 31         65 foreach (@keys) {
1172 51         94 $empty_events->{$_} = $self->{$_};
1173 51 50       90 if ($mode =~ /lookback_freeze/) {
1174 0 0       0 if (exists $last_values->{frozen}->{$_}) {
1175 0 0       0 if (ref($last_values->{frozen}->{$_}) eq "ARRAY") {
1176 0         0 @{$empty_events->{cold}->{$_}} = @{$last_values->{frozen}->{$_}};
  0         0  
  0         0  
1177             } else {
1178 0         0 $empty_events->{cold}->{$_} = $last_values->{frozen}->{$_};
1179             }
1180             } else {
1181 0 0       0 if (ref($last_values->{cold}->{$_}) eq "ARRAY") {
1182 0         0 @{$empty_events->{cold}->{$_}} = @{$last_values->{cold}->{$_}};
  0         0  
  0         0  
1183             } else {
1184 0         0 $empty_events->{cold}->{$_} = $last_values->{cold}->{$_};
1185             }
1186             }
1187 0         0 $empty_events->{cold}->{timestamp} = $last_values->{cold}->{timestamp};
1188             }
1189 51 50       104 if ($mode eq "lookback_freeze_shockfrost") {
1190 0 0       0 if (ref($empty_events->{cold}->{$_}) eq "ARRAY") {
1191 0         0 @{$empty_events->{frozen}->{$_}} = @{$empty_events->{cold}->{$_}};
  0         0  
  0         0  
1192             } else {
1193 0         0 $empty_events->{frozen}->{$_} = $empty_events->{cold}->{$_};
1194             }
1195 0         0 $empty_events->{frozen}->{timestamp} = $now;
1196             }
1197             }
1198 31         50 $empty_events->{timestamp} = $now;
1199 31 100       64 if ($mode eq "lookback") {
1200 21         46 $empty_events->{lookback_history} = $last_values->{lookback_history};
1201 21         36 foreach (@keys) {
1202 37 100       86 if (ref($self->{$_}) eq "ARRAY") {
1203 16         26 @{$empty_events->{lookback_history}->{$_}->{$now}} = @{$self->{$_}};
  16         60  
  16         31  
1204             } else {
1205 21         69 $empty_events->{lookback_history}->{$_}->{$now} = $self->{$_};
1206             }
1207             }
1208             }
1209 31 50       58 if ($mode eq "lookback_freeze_defrost") {
1210 0         0 delete $empty_events->{freeze};
1211             }
1212 31         58 $empty_events;
1213             };
1214 31         118 $self->save_state(%params);
1215             }
1216              
1217             sub create_statefilesdir {
1218 31     31 0 35 my ($self) = @_;
1219 31 50       56 if (! -d $self->statefilesdir()) {
    0          
1220 31         32 eval {
1221 3     3   15168 use File::Path;
  3         5  
  3         4102  
1222 31         75 mkpath $self->statefilesdir();
1223             };
1224 31 50 33     124 if ($@ || ! -w $self->statefilesdir()) {
1225 31         61 $self->add_message(UNKNOWN,
1226             sprintf "cannot create status dir %s! check your filesystem (permissions/usage/integrity) and disk devices", $self->statefilesdir());
1227             }
1228             } elsif (! -w $self->statefilesdir()) {
1229 0         0 $self->add_message(UNKNOWN,
1230             sprintf "cannot write status dir %s! check your filesystem (permissions/usage/integrity) and disk devices", $self->statefilesdir());
1231             }
1232             }
1233              
1234             sub create_statefile {
1235 74     74 0 797 my ($self, %params) = @_;
1236 74         79 my $extension = "";
1237 74 100       190 $extension .= $params{name} ? '_'.$params{name} : '';
1238 74         133 $extension =~ s/\//_/g;
1239 74         63 $extension =~ s/\(/_/g;
1240 74         68 $extension =~ s/\)/_/g;
1241 74         72 $extension =~ s/\*/_/g;
1242 74         136 $extension =~ s/\s/_/g;
1243 74         158 return sprintf "%s/%s%s", $self->statefilesdir(),
1244             $self->clean_path($self->mode), $self->clean_path(lc $extension);
1245             }
1246              
1247             sub clean_path {
1248 148     148 0 141 my ($self, $path) = @_;
1249 148 50       354 if ($^O =~ /MSWin/) {
1250 0         0 $path =~ s/:/_/g;
1251             }
1252 148         1035 return $path;
1253             }
1254              
1255             sub schimpf {
1256 0     0 0 0 my ($self) = @_;
1257 0         0 printf "statefilesdir %s is not writable.\nYou didn't run this plugin as root, didn't you?\n", $self->statefilesdir();
1258             }
1259              
1260             # $self->protect_value('1.1-flat_index', 'cpu_busy', 'percent');
1261             sub protect_value {
1262 0     0 0 0 my ($self, $ident, $key, $validfunc) = @_;
1263 0 0 0     0 if (ref($validfunc) ne "CODE" && $validfunc eq "percent") {
    0 0        
1264             $validfunc = sub {
1265 0     0   0 my $value = shift;
1266 0 0       0 return 0 if $value !~ /^[-+]?([0-9]+(\.[0-9]+)?|\.[0-9]+)$/;
1267 0 0 0     0 return ($value < 0 || $value > 100) ? 0 : 1;
1268 0         0 };
1269             } elsif (ref($validfunc) ne "CODE" && $validfunc eq "positive") {
1270             $validfunc = sub {
1271 0     0   0 my $value = shift;
1272 0 0       0 return 0 if $value !~ /^[-+]?([0-9]+(\.[0-9]+)?|\.[0-9]+)$/;
1273 0 0       0 return ($value < 0) ? 0 : 1;
1274 0         0 };
1275             }
1276 0 0       0 if (&$validfunc($self->{$key})) {
1277             $self->save_state(name => 'protect_'.$ident.'_'.$key, save => {
1278 0         0 $key => $self->{$key},
1279             exception => 0,
1280             });
1281             } else {
1282             # if the device gives us an clearly wrong value, simply use the last value.
1283 0         0 my $laststate = $self->load_state(name => 'protect_'.$ident.'_'.$key);
1284             $self->debug(sprintf "self->{%s} is %s and invalid for the %dth time",
1285 0         0 $key, $self->{$key}, $laststate->{exception} + 1);
1286 0 0       0 if ($laststate->{exception} <= 5) {
1287             # but only 5 times.
1288             # if the error persists, somebody has to check the device.
1289 0         0 $self->{$key} = $laststate->{$key};
1290             }
1291             $self->save_state(name => 'protect_'.$ident.'_'.$key, save => {
1292             $key => $laststate->{$key},
1293             exception => ++$laststate->{exception},
1294 0         0 });
1295             }
1296             }
1297              
1298             sub save_state {
1299 31     31 0 98 my ($self, %params) = @_;
1300 31         80 $self->create_statefilesdir();
1301 31         104 my $statefile = $self->create_statefile(%params);
1302 31         70 my $tmpfile = $self->statefilesdir().'/check__health_tmp_'.$$;
1303 31 50 33     162 if ((ref($params{save}) eq "HASH") && exists $params{save}->{timestamp}) {
1304 31         860 $params{save}->{localtime} = scalar localtime $params{save}->{timestamp};
1305             }
1306 31         242 my $seekfh = IO::File->new();
1307 31 50       1070 if ($seekfh->open($tmpfile, "w")) {
1308 31         5076 $seekfh->printf("%s", Data::Dumper::Dumper($params{save}));
1309 31         5031 $seekfh->flush();
1310 31         120 $seekfh->close();
1311             $self->debug(sprintf "saved %s to %s",
1312 31         456 Data::Dumper::Dumper($params{save}), $statefile);
1313             }
1314 31 50       3351 if (! rename $tmpfile, $statefile) {
1315 0         0 $self->add_message(UNKNOWN,
1316             sprintf "cannot write status file %s! check your filesystem (permissions/usage/integrity) and disk devices", $statefile);
1317             }
1318             }
1319              
1320             sub load_state {
1321 31     31 0 87 my ($self, %params) = @_;
1322 31         132 my $statefile = $self->create_statefile(%params);
1323 31 100       938 if ( -f $statefile) {
1324 26         31 our $VAR1;
1325 26         72 eval {
1326 26 100       123 delete $INC{$statefile} if exists $INC{$statefile}; # else unit tests fail
1327 26         4801 require $statefile;
1328             };
1329 26 50       248 if($@) {
1330 0         0 printf "rumms\n";
1331             }
1332 26         152 $self->debug(sprintf "load %s from %s", Data::Dumper::Dumper($VAR1), $statefile);
1333 26         375 return $VAR1;
1334             } else {
1335 5         19 return undef;
1336             }
1337             }
1338              
1339             #########################################################
1340             # daemon mode
1341             #
1342             sub check_pidfile {
1343 0     0 0 0 my ($self) = @_;
1344 0         0 my $fh = IO::File->new();
1345 0 0       0 if ($fh->open($self->{pidfile}, "r")) {
1346 0         0 my $pid = $fh->getline();
1347 0         0 $fh->close();
1348 0 0       0 if (! $pid) {
1349             $self->debug("Found pidfile %s with no valid pid. Exiting.",
1350 0         0 $self->{pidfile});
1351 0         0 return 0;
1352             } else {
1353 0         0 $self->debug("Found pidfile %s with pid %d", $self->{pidfile}, $pid);
1354 0         0 kill 0, $pid;
1355 0 0       0 if ($! == Errno::ESRCH) {
1356 0         0 $self->debug("This pidfile is stale. Writing a new one");
1357 0         0 $self->write_pidfile();
1358 0         0 return 1;
1359             } else {
1360 0         0 $self->debug("This pidfile is held by a running process. Exiting");
1361 0         0 return 0;
1362             }
1363             }
1364             } else {
1365 0         0 $self->debug("Found no pidfile. Writing a new one");
1366 0         0 $self->write_pidfile();
1367 0         0 return 1;
1368             }
1369             }
1370              
1371             sub write_pidfile {
1372 0     0 0 0 my ($self) = @_;
1373 0 0       0 if (! -d dirname($self->{pidfile})) {
1374 0         0 eval "require File::Path;";
1375 0 0       0 if (defined(&File::Path::mkpath)) {
1376 0         0 import File::Path;
1377 0         0 eval { mkpath(dirname($self->{pidfile})); };
  0         0  
1378             } else {
1379 0         0 my @dirs = ();
1380             map {
1381 0         0 push @dirs, $_;
1382 0 0 0     0 mkdir(join('/', @dirs))
1383             if join('/', @dirs) && ! -d join('/', @dirs);
1384 0         0 } split(/\//, dirname($self->{pidfile}));
1385             }
1386             }
1387 0         0 my $fh = IO::File->new();
1388 0         0 $fh->autoflush(1);
1389 0 0       0 if ($fh->open($self->{pidfile}, "w")) {
1390 0         0 $fh->printf("%s", $$);
1391 0         0 $fh->close();
1392             } else {
1393 0         0 $self->debug("Could not write pidfile %s", $self->{pidfile});
1394 0         0 die "pid file could not be written";
1395             }
1396             }
1397              
1398             sub system_vartmpdir {
1399 0     0 0 0 my ($self) = @_;
1400 0 0       0 if ($^O =~ /MSWin/) {
1401 0         0 return $self->system_tmpdir();
1402             } else {
1403 0         0 return "/var/tmp/".$Monitoring::GLPlugin::pluginname;
1404             }
1405             }
1406              
1407             sub system_tmpdir {
1408 0     0 0 0 my ($self) = @_;
1409 0 0       0 if ($^O =~ /MSWin/) {
1410 0 0       0 return $ENV{TEMP} if defined $ENV{TEMP};
1411 0 0       0 return $ENV{TMP} if defined $ENV{TMP};
1412             return File::Spec->catfile($ENV{windir}, 'Temp')
1413 0 0       0 if defined $ENV{windir};
1414 0         0 return 'C:\Temp';
1415             } else {
1416 0         0 return "/tmp";
1417             }
1418             }
1419              
1420             sub convert_scientific_numbers {
1421 0     0 0 0 my ($self, $n) = @_;
1422             # mostly used to convert numbers in scientific notation
1423 0 0       0 if ($n =~ /^\s*\d+\s*$/) {
    0          
    0          
    0          
1424 0         0 return $n;
1425             } elsif ($n =~ /^\s*([-+]?)(\d*[\.,]*\d*)[eE]{1}([-+]?)(\d+)\s*$/) {
1426 0         0 my ($vor, $num, $sign, $exp) = ($1, $2, $3, $4);
1427 0         0 $n =~ s/E/e/g;
1428 0         0 $n =~ s/,/\./g;
1429 0         0 $num =~ s/,/\./g;
1430 0 0       0 my $sig = $sign eq '-' ? "." . ($exp - 1 + length $num) : '';
1431 0         0 my $dec = sprintf "%${sig}f", $n;
1432 0         0 $dec =~ s/\.[0]+$//g;
1433 0         0 return $dec;
1434             } elsif ($n =~ /^\s*([-+]?)(\d+)[\.,]*(\d*)\s*$/) {
1435 0         0 return $1.$2.".".$3;
1436             } elsif ($n =~ /^\s*(.*?)\s*$/) {
1437 0         0 return $1;
1438             } else {
1439 0         0 return $n;
1440             }
1441             }
1442              
1443             sub compatibility_methods {
1444 0     0 0 0 my ($self) = @_;
1445             # add_perfdata
1446             # add_message
1447             # nagios_exit
1448             # ->{warningrange}
1449             # ->{criticalrange}
1450             # ...
1451 0         0 $self->{warningrange} = ($self->get_thresholds())[0];
1452 0         0 $self->{criticalrange} = ($self->get_thresholds())[1];
1453 0         0 my $old_init = $self->can('init');
1454 0         0 my %params = (
1455             'mode' => join('::', split(/-/, $self->opts->mode)),
1456             'name' => $self->opts->name,
1457             'name2' => $self->opts->name2,
1458             );
1459             {
1460 3     3   23 no strict 'refs';
  3         3  
  3         96  
  0         0  
1461 3     3   10 no warnings 'redefine';
  3         2  
  3         2263  
1462 0         0 *{ref($self).'::init'} = sub {
1463 0     0   0 $self->$old_init(%params);
1464 0         0 $self->nagios(%params);
1465 0         0 };
1466 0         0 *{ref($self).'::add_nagios'} = \&{"Monitoring::GLPlugin::add_message"};
  0         0  
  0         0  
1467 0         0 *{ref($self).'::add_nagios_ok'} = \&{"Monitoring::GLPlugin::add_ok"};
  0         0  
  0         0  
1468 0         0 *{ref($self).'::add_nagios_warning'} = \&{"Monitoring::GLPlugin::add_warning"};
  0         0  
  0         0  
1469 0         0 *{ref($self).'::add_nagios_critical'} = \&{"Monitoring::GLPlugin::add_critical"};
  0         0  
  0         0  
1470 0         0 *{ref($self).'::add_nagios_unknown'} = \&{"Monitoring::GLPlugin::add_unknown"};
  0         0  
  0         0  
1471 0         0 *{ref($self).'::add_perfdata'} = sub {
1472 0     0   0 my $self = shift;
1473 0         0 my $message = shift;
1474 0         0 foreach my $perfdata (split(/\s+/, $message)) {
1475 0         0 my ($label, $perfstr) = split(/=/, $perfdata);
1476 0         0 my ($value, $warn, $crit, $min, $max) = split(/;/, $perfstr);
1477 0         0 $value =~ /^([\d\.\-\+]+)(.*)$/;
1478 0         0 $value = $1;
1479 0         0 my $uom = $2;
1480 0         0 $Monitoring::GLPlugin::plugin->add_perfdata(
1481             label => $label,
1482             value => $value,
1483             uom => $uom,
1484             warn => $warn,
1485             crit => $crit,
1486             min => $min,
1487             max => $max,
1488             );
1489             }
1490 0         0 };
1491 0         0 *{ref($self).'::check_thresholds'} = sub {
1492 0     0   0 my $self = shift;
1493 0         0 my $value = shift;
1494 0         0 my $defaultwarningrange = shift;
1495 0         0 my $defaultcriticalrange = shift;
1496 0         0 $Monitoring::GLPlugin::plugin->set_thresholds(
1497             metric => 'default',
1498             warning => $defaultwarningrange,
1499             critical => $defaultcriticalrange,
1500             );
1501 0         0 $self->{warningrange} = ($self->get_thresholds())[0];
1502 0         0 $self->{criticalrange} = ($self->get_thresholds())[1];
1503 0         0 return $Monitoring::GLPlugin::plugin->check_thresholds(
1504             metric => 'default',
1505             value => $value,
1506             warning => $defaultwarningrange,
1507             critical => $defaultcriticalrange,
1508             );
1509 0         0 };
1510             }
1511             }
1512              
1513              
1514             sub AUTOLOAD {
1515 6     6   2610 my ($self, @params) = @_;
1516 6 50       19 return if ($AUTOLOAD =~ /DESTROY/);
1517 6 50       14 $self->debug("AUTOLOAD %s\n", $AUTOLOAD)
1518             if $self->opts->verbose >= 2;
1519 6 50       76 if ($AUTOLOAD =~ /^(.*)::analyze_and_check_(.*)_subsystem$/) {
    50          
    50          
    50          
    0          
1520 0         0 my $class = $1;
1521 0         0 my $subsystem = $2;
1522 0         0 my $analyze = sprintf "analyze_%s_subsystem", $subsystem;
1523 0         0 my $check = sprintf "check_%s_subsystem", $subsystem;
1524 0 0       0 if (@params) {
1525             # analyzer class
1526 0         0 my $subsystem_class = shift @params;
1527 0         0 $self->{components}->{$subsystem.'_subsystem'} = $subsystem_class->new();
1528 0         0 $self->debug(sprintf "\$self->{components}->{%s_subsystem} = %s->new()",
1529             $subsystem, $subsystem_class);
1530             } else {
1531 0         0 $self->$analyze();
1532 0         0 $self->debug("call %s()", $analyze);
1533             }
1534 0         0 $self->$check();
1535             } elsif ($AUTOLOAD =~ /^(.*)::check_(.*)_subsystem$/) {
1536 0         0 my $class = $1;
1537 0         0 my $subsystem = sprintf "%s_subsystem", $2;
1538 0         0 $self->{components}->{$subsystem}->check();
1539 0 0       0 $self->{components}->{$subsystem}->dump()
1540             if $self->opts->verbose >= 2;
1541             } elsif ($AUTOLOAD =~ /^.*::(status_code|check_messages|nagios_exit|html_string|perfdata_string|selected_perfdata|check_thresholds|get_thresholds|opts)$/) {
1542 0         0 return $Monitoring::GLPlugin::plugin->$1(@params);
1543             } elsif ($AUTOLOAD =~ /^.*::(reduce_messages|reduce_messages_short|clear_messages|suppress_messages|add_html|add_perfdata|override_opt|create_opt|set_thresholds|force_thresholds)$/) {
1544 6         39 $Monitoring::GLPlugin::plugin->$1(@params);
1545             } elsif ($AUTOLOAD =~ /^.*::mod_arg_(.*)$/) {
1546 0           return $Monitoring::GLPlugin::plugin->mod_arg($1, @params);
1547             } else {
1548 0           $self->debug("AUTOLOAD: class %s has no method %s\n",
1549             ref($self), $AUTOLOAD);
1550             }
1551             }
1552              
1553             1;
1554              
1555             __END__