/[nagios-plugins-perl]/trunk/plugins/check_racvision-eqos-v2.0.pl
ViewVC logotype

Contents of /trunk/plugins/check_racvision-eqos-v2.0.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 193 - (show annotations) (download)
Mon Dec 18 14:45:38 2017 UTC (2 years, 11 months ago) by racvision
File MIME type: text/plain
File size: 14899 byte(s)
Remise en ordre XH 201712
1 #!/usr/bin/perl -w
2 #
3 # Copyright (c) 2002-2013 Stéphane Urbanovski <stephane.urbanovski@ac-nancy-metz.fr>
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty
12 # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # you should have received a copy of the GNU General Public License
16 # along with this program (or with Nagios); if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA
19 #
20
21 use strict; # should never be differently :-)
22 use warnings;
23
24
25 use Locale::gettext;
26 use File::Basename; # get basename()
27
28 use POSIX qw(setlocale);
29 use Unicode::String qw(latin1 utf8); # Convert between iso-8859-1 and utf-8
30 use Time::HiRes qw(time); # get microtime
31 use POSIX qw(mktime);
32
33 use Nagios::Plugin ;
34
35 use LWP::UserAgent; # http client
36 use HTTP::Request; # used by LWP::UserAgent
37 use HTTP::Status; # to get http err msg
38
39 use XML::Parser::Expat;
40
41 use Data::Dumper;
42
43
44 my %RETURN_CODE_VALUES = (
45 'UNKNOWN' => UNKNOWN,
46 'OK' => OK,
47 'WARN' => WARNING,
48 'CRIT' => CRITICAL,
49 'MAINT' => UNKNOWN
50 );
51
52
53 my $PROGNAME = basename($0);
54 '$Revision: 2.0 $' =~ /^.*(\d+\.\d+) \$$/; # Use The Revision from RCS/CVS/SVN
55 my $VERSION = $1;
56
57 my $DEBUG = 0;
58 my $TIMEOUT = 9;
59
60 # i18n :
61 setlocale(LC_MESSAGES, '');
62 textdomain('nagios-plugins-perl');
63
64
65 my $np = Nagios::Plugin->new(
66 version => $VERSION,
67 blurb => _gt('Plugin to check Racvision web url'),
68 usage => "Usage: %s [ -v|--verbose ] -u <url> [-t <timeout>] [ -c|--critical=<threshold> ] [ -w|--warning=<threshold> ]",
69 timeout => $TIMEOUT+1
70 );
71 $np->add_arg (
72 spec => 'debug|d',
73 help => _gt('Debug level'),
74 default => 0,
75 );
76 $np->add_arg (
77 spec => 'w=f',
78 help => _gt('Warning request time threshold (in seconds)'),
79 default => 2,
80 label => 'FLOAT'
81 );
82 $np->add_arg (
83 spec => 'c=f',
84 help => _gt('Critical request time threshold (in seconds)'),
85 default => 10,
86 label => 'FLOAT'
87 );
88 $np->add_arg (
89 spec => 'url|u=s',
90 help => _gt('URL of the racvision xml page.'),
91 required => 1,
92 );
93 $np->add_arg (
94 spec => 'encoding|e:s',
95 help => _gt('Enforce caracters encoding (\'utf-8\',\'iso-8859-1\', ...) when parsing XML DATA'),
96 default => '',
97 );
98 $np->add_arg (
99 spec => 'ignore|i=s@',
100 help => _gt('Ignore listed tests'),
101 );
102
103 $np->getopts;
104
105 $DEBUG = $np->opts->get('debug');
106 my $verbose = $np->opts->verbose;
107
108 # Thresholds :
109 # time
110 my $warn_t = $np->opts->get('w');
111 my $crit_t = $np->opts->get('c');
112
113 my $url = $np->opts->get('url');
114 my $encoding = $np->opts->get('encoding');
115 my $ignore = $np->opts->get('ignore');
116
117
118 # Create a LWP user agent object:
119 my $ua = new LWP::UserAgent(
120 'env_proxy' => 0,
121 'timeout' => $TIMEOUT,
122 );
123 $ua->agent(basename($0));
124
125 # Workaround for LWP bug :
126 $ua->parse_head(0);
127
128
129 # Handle specific availability computing
130 my $availability = OK;
131 my $availability_mode = 'NAGIOS'; # Default to Nagios mode
132
133 if ( defined($ENV{'http_proxy'}) ) {
134 # Normal http proxy :
135 $ua->proxy(['http'], $ENV{'http_proxy'});
136 # Https must use Crypt::SSLeay https proxy (to use CONNECT method instead of GET)
137 $ENV{'HTTPS_PROXY'} = $ENV{'http_proxy'};
138 }
139
140 # Build and submit an http request :
141 my $request = HTTP::Request->new('GET', $url);
142 my $timer = time();
143 my $http_response = $ua->request( $request );
144 $timer = time()-$timer;
145
146
147 my $status = $np->check_threshold(
148 'check' => $timer,
149 'warning' => $warn_t,
150 'critical' => $crit_t,
151 );
152
153 $np->add_perfdata(
154 'label' => 't',
155 'value' => sprintf('%.6f',$timer),
156 'min' => 0,
157 'uom' => 's',
158 'threshold' => $np->threshold()
159 );
160
161 if ( $status > OK ) {
162 $np->add_message($status, sprintf(_gt("Response time degraded: %.6fs !"),$timer) );
163 }
164
165
166 my $message = 'msg';
167
168
169 if ( $http_response->is_error() ) {
170 my $err = $http_response->code." ".status_message($http_response->code)." (".$http_response->message.")";
171 $np->add_message(CRITICAL, _gt("HTTP error: ").$err );
172
173 } elsif ( ! $http_response->is_success() ) {
174 my $err = $http_response->code." ".status_message($http_response->code)." (".$http_response->message.")";
175 $np->add_message(CRITICAL, _gt("Internal error: ").$err );
176 }
177
178
179 ($status, $message) = $np->check_messages();
180
181 if ( $http_response->is_success() ) {
182
183 # Get xml content ...
184 my $xml = $http_response->content;
185 if ($DEBUG) {
186 print "------------------===http output===------------------\n$xml\n-----------------------------------------------------\n";
187 print "t=".$timer."s\n";
188 };
189
190 # Remove DOCTYPE and new lines:
191 $xml =~ s/\<\!DOCTYPE .*?\>// ;
192 my $fxml = '';
193 foreach ( split("[\r\n]+",$xml) ) {
194 s/^\s+//;
195 $fxml .= $_;
196 }
197 $xml = $fxml ;
198
199 if ($DEBUG) {
200 print "------------------===sanitized===------------------\n$xml\n-----------------------------------------------------\n";
201 };
202
203 # Get XML tools:
204 my $parser;
205
206 # Manage encoding :
207 if ( $encoding eq 'iso-8859-1' || $encoding eq 'iso-8859-15') {
208 # transcode iso-8859-1 to utf8 :
209 my $tmp = latin1($xml);
210 $xml = $tmp->utf8;
211 }
212
213 #Force xml output to utf-8
214 utf8::upgrade($xml);
215
216
217 my %d = (
218 '_ERROR' => '',
219 'DATE' => '',
220 'APPLICATION' => {
221 'NAME' => '',
222 'VERSION' => '',
223 'DESCRIPTION' => '',
224 'AVAILABILITY' => '',
225 'TEST' => [],
226 'PERIOD' => {
227 'START' => '',
228 'END' => ''
229 }
230 },
231 );
232
233 if ( !&xmlParse($xml,\%d) ) {
234 $np->nagios_exit(CRITICAL, _gt("Xml parse error: ").$d{'_ERROR'} );
235 }
236
237 # Now that we have something parsable, check if we are in application driven availability computing mode (aka EQOS)
238 if ( defined($ENV{'AVAILABILITY_MODE'}) && $ENV{'AVAILABILITY_MODE'} eq 'EQOS') {
239 $availability_mode = 'EQOS';
240 }
241 logD ('AVAILABILITY_MODE='.$availability_mode);
242
243
244
245
246 logD ('name['.$d{'APPLICATION'}{'NAME'}.'] - version['.$d{'APPLICATION'}{'VERSION'}.']');
247
248 $np->shortname($d{'APPLICATION'}{'NAME'}.' ('.$d{'APPLICATION'}{'VERSION'}.')');
249
250
251
252 #
253 # Handle racvision tests
254 ################################
255
256 my $nb_test = scalar($@{$d{'APPLICATION'}{'TEST'}});
257 my $nb_test_done = 0;
258 my $nb_test_ignored = 0;
259
260 for ( my $i = 0 ; $i <= $nb_test ; $i++ ) {
261 my $test = $d{'APPLICATION'}{'TEST'}[$i];
262
263 $nb_test_done++;
264
265 logD ($i.'/'.$nb_test.') id =['.$test->{'ID'}.'] - description['.$test->{'DESCRIPTION'}.'] - state['.$test->{'STATE_VAL'}.'] - msg['.$test->{'STATE'}.']');
266
267 if ( defined($RETURN_CODE_VALUES{$test->{'STATE_VAL'}}) ) {
268 $status = $RETURN_CODE_VALUES{$test->{'STATE_VAL'}};
269 } else {
270 # FIXME: UNKNOWN status is not handled by $np->add_message
271 $np->add_message(WARNING, sprintf(_gt("Bad status for test n°%d"),$i+1) );
272 $status = OK;
273 }
274
275 if ( $test->{'VALUE'} =~ /^\d+\.?\d*$/ ) {
276 if ( $test->{'ID'} =~ /^[\w_][\w\d\-_\.]*$/ ) {
277 $np->add_perfdata(
278 'label' => $test->{'ID'},
279 'value' => sprintf('%.6f',$test->{'VALUE'}),
280 'uom' => $test->{'VALUE_UNIT'},
281 );
282
283 logD ('DEBUG: value['.$test->{'VALUE'}.'] - unit['.$test->{'VALUE_UNIT'}.']');
284 } elsif ($DEBUG) {
285 logW ('Bad Id for test n°'.$i.": '".$test->{'ID'});
286 }
287 }
288
289 if ( defined($ignore) ) {
290 if ( grep ($_ eq $test->{'ID'}, @{$ignore}) ) {
291 logD ('Ignoring id='.$test->{'ID'});
292 $nb_test_ignored++;
293 $status = OK;
294 }
295 }
296 $np->add_message($status, sprintf(_gt("%s - %s : %s"),$test->{'STATE_VAL'},$test->{'DESCRIPTION'},$test->{'STATE'}) );
297
298 if ( ($availability_mode eq 'EQOS') && ($status != OK) ) {
299 if ( $test->{'AVAILABILITY'} ne 'ignore' ) {
300 $availability = CRITICAL;
301 } else {
302 logD ("Ignoring this test (".$test->{'ID'}.") for AVAILABILITY report !");
303 }
304 }
305 }
306
307 if ( $verbose ) {
308 ($status, $message) = $np->check_messages('join' => '<br/>','join_all' => '<br/>');
309 } else {
310 ($status, $message) = $np->check_messages('join' => '<br/>');
311 }
312
313 if ( $status == OK ) {
314 $message = sprintf(_gt("%i test(s) done"),$nb_test_done);
315 if ($nb_test_ignored) {
316 $message .= sprintf(_gt(" and %i test(s) ignored"),$nb_test_ignored);
317 }
318 $np->add_message(OK, $message );
319 }
320
321
322 #
323 # Handle check periods
324 ################################
325
326 my $time_start = 0;
327 my $time_end = 0;
328 if ( $d{'APPLICATION'}{'PERIOD'}{'START'} ne '' ) {
329 if ( $d{'APPLICATION'}{'PERIOD'}{'START'} =~ /^(\d{4})\-(\d{2})\-(\d{2})\s(\d{2}):(\d{2}):(\d{2})/) { #2005-09-15 08:00:00
330 $time_start = mktime($6, $5, $4, $3, $2-1, $1-1900)||0;
331 logD ('Start period: '.$d{'APPLICATION'}{'PERIOD'}{'START'});
332 } else {
333 logW ('Invalid value for start period: '.$d{'APPLICATION'}{'PERIOD'}{'START'});
334 }
335 }
336 if ( $d{'APPLICATION'}{'PERIOD'}{'END'} ne '' ) {
337 if ( $d{'APPLICATION'}{'PERIOD'}{'END'} =~ /^(\d{4})\-(\d{2})\-(\d{2})\s(\d{2}):(\d{2}):(\d{2})/) { #2005-09-15 08:00:00
338 $time_end = mktime($6, $5, $4, $3, $2-1, $1-1900)||0;
339 logD ('End period: '.$d{'APPLICATION'}{'PERIOD'}{'END'});
340 } else {
341 logW ('Invalid value for end period: '.$d{'APPLICATION'}{'PERIOD'}{'END'});
342 }
343 }
344 my $time_now = time();
345 my $out_of_period = 0;
346 logD("period : actual=$time_now start=$time_start end=$time_end");
347 if ( $time_start && ($time_now < $time_start) ) {
348 $message .= ' '.sprintf(_gt("(before campaign starting at %s)"),$d{'APPLICATION'}{'PERIOD'}{'START'});
349 $out_of_period = 1;
350 } elsif ( $time_end && ($time_now > $time_end) ) {
351 $message .= ' '.sprintf(_gt("(after campaign ending at %s)"),$d{'APPLICATION'}{'PERIOD'}{'END'});
352 $out_of_period = 1;
353 }
354 if ( $out_of_period && ($status == CRITICAL) ) {
355 # Lower the status to WARNING if out of period
356 $status = WARNING;
357 }
358
359 if ( $availability_mode eq 'EQOS' ) {
360 if ( $d{'APPLICATION'}{'AVAILABILITY'} eq 'UP' ) {
361 logD ("Force AVAILABILITY to OK due to application requirement");
362 $availability = OK;
363 } elsif ( $d{'APPLICATION'}{'AVAILABILITY'} eq 'DOWN' ) {
364 logD ("Force AVAILABILITY to DOWN due to application requirement");
365 $availability = CRITICAL;
366 }
367 }
368
369 }
370
371 if ( $availability_mode eq 'EQOS' ) {
372 # Bypass normal Nagios exit status if we are in EQOS mode.
373 $np->nagios_exit($availability, $message );
374 }
375
376 $np->nagios_exit($status, $message );
377
378
379 sub xmlParse {
380 our ( $xml, $racvision ) = @_;
381
382 our @xpath = ();
383 our $currentTag = '';
384
385 our $curDataRef = undef;
386
387 my $parser = new XML::Parser::Expat('ProtocolEncoding' => 'utf-8');
388
389 $parser->setHandlers(
390 'Start' => \&start_handler,
391 'End' => \&end_handler,
392 'Char' => \&char_handler,
393 );
394
395 eval { $parser->parse($xml) };
396
397 if ( $@ ) {
398 $racvision->{'_ERROR'} = "Could not parse XML : $@";
399 $racvision->{'_ERROR'} =~ s/\n//g;
400 $racvision->{'_ERROR'} =~ s/at $0 line \d+//g;
401 return 0;
402 }
403
404 return 1;
405
406
407 # start element callback
408 sub start_handler {
409 my ($p, $el, %attr) = @_;
410 $el = uc($el);
411 my $unknownTag = '';
412
413 # logD ("start_handler for <$el>");
414
415 if ($currentTag eq '' && $el ne 'APPTEST') {
416 $unknownTag = $el;
417
418 } elsif ($currentTag eq 'APPTEST' ) {
419 if ( defined($racvision->{$el}) ) {
420 $curDataRef = \$racvision->{$el};
421 } else {
422 $unknownTag = $el;
423 $curDataRef = undef;
424 }
425 } elsif ($currentTag eq 'APPLICATION' ) {
426 if ( defined($racvision->{'APPLICATION'}{$el}) ) {
427 $curDataRef = \$racvision->{'APPLICATION'}{$el};
428 # print Dumper(\%attr);
429 if ($el eq 'TEST' ) {
430 push(@{$racvision->{'APPLICATION'}{'TEST'}}, {'DESCRIPTION' => '' , 'STATE' => '', 'STATE_VAL' => '', 'VALUE' => '', 'VALUE_UNIT' => '', 'AVAILABILITY' => ''});
431
432 if ( defined($attr{'id'}) ) {
433 $racvision->{'APPLICATION'}{'TEST'}[-1]{'ID'} = $attr{'id'};
434 } else {
435 logW ("No id attibute define for the current test");
436 }
437
438 if ( defined($attr{'availability'}) ) {
439 $racvision->{'APPLICATION'}{'TEST'}[-1]{'AVAILABILITY'} = $attr{'availability'};
440 }
441 } elsif ($el eq 'AVAILABILITY' ) {
442 if ( defined($attr{'available'}) ) {
443 $racvision->{'APPLICATION'}{'AVAILABILITY'} = $attr{'available'};
444 }
445 }
446 } else {
447 $unknownTag = $el;
448 $curDataRef = undef;
449 }
450 } elsif ($currentTag eq 'TEST' ) {
451 if ( $el eq 'DESCRIPTION' ) {
452 $curDataRef = \$racvision->{'APPLICATION'}{'TEST'}[-1]{$el};
453 } elsif ($el eq 'STATE' ) {
454 $curDataRef = \$racvision->{'APPLICATION'}{'TEST'}[-1]{$el};
455 if ( defined($attr{'val'}) ) {
456 $racvision->{'APPLICATION'}{'TEST'}[-1]{'STATE_VAL'} = $attr{'val'};
457 } else {
458 logW ("No state val attibute define for the current test");
459 }
460 } elsif ($el eq 'VALUE' ) {
461 $curDataRef = \$racvision->{'APPLICATION'}{'TEST'}[-1]{$el};
462 if ( defined($attr{'unit'}) ) {
463 $racvision->{'APPLICATION'}{'TEST'}[-1]{'VALUE_UNIT'} = $attr{'unit'};
464 }
465 } else {
466 $unknownTag = $el;
467 $curDataRef = undef;
468 }
469 } elsif ($currentTag eq 'PERIOD' ) {
470 if ( defined($racvision->{'APPLICATION'}{'PERIOD'}{$el}) ) {
471 $curDataRef = \$racvision->{'APPLICATION'}{'PERIOD'}{$el};
472 } else {
473 $unknownTag = $el;
474 $curDataRef = undef;
475 }
476 }
477
478 # logD ("ref (curDataRef)=" .ref($curDataRef));
479 if ( $unknownTag ne '' ) {
480 logW ("WARNING: Unknown tag in /".join('/',@xpath).": $el");
481 }
482 # print STDERR 'PATH /'.join('/',@xpath)." >> $el\n";
483
484 $currentTag = $el;
485 push (@xpath, $el);
486 }
487
488 # end element callback
489 sub end_handler {
490 my ($p, $el) = @_;
491 $el = uc($el);
492 # logD ("end_handler for <$el>");
493
494 if ( $currentTag eq $el ) {
495 pop(@xpath);
496 $currentTag = $xpath[-1];
497 } else {
498 logW ("BUG: el=$el currentTag=$currentTag");
499 }
500 $curDataRef = undef;
501 }
502
503 # characters beetwen elements callback
504 sub char_handler {
505 my ($p, $data) = @_;
506 if ( defined($curDataRef) && ref($curDataRef) eq 'SCALAR') {
507 # logD ("Set $currentTag=$data ref=".ref($curDataRef));
508 $$curDataRef = $data;
509 } else {
510 logD ("Can't set value '$data' for currentTag=$currentTag ref=".ref($curDataRef));
511 }
512 }
513
514 }
515 sub logD {
516 print STDERR 'DEBUG: '.$_[0]."\n" if ($DEBUG);
517 }
518 sub logW {
519 print STDERR 'WARNING: '.$_[0]."\n" if ($DEBUG);
520 }
521 # Gettext wrapper
522 sub _gt {
523 return gettext($_[0]);
524 }
525
526
527 __END__
528
529 =head1 NAME
530
531 This Nagios plugins check a specified Racvision url (xml document) returned by an application and parse its content.
532
533
534 =head1 NAGIOS CONGIGURATIONS
535
536 In F<checkcommands.cfg> you have to add :
537
538 define command {
539 command_name check_racvision
540 command_line $USER1$/check_racvision.pl -u $ARG1$
541 }
542
543
544 In F<services.cfg> you just have to add something like :
545
546 define service {
547 host_name www.exemple.org
548 normal_check_interval 10
549 retry_check_interval 5
550 contact_groups linux-admins
551 service_description My great web application
552 check_command check_racvision!http://www.exemple.org/myApplication/racvision
553 }
554
555 =head1 AUTHOR
556
557 Stéphane Urbanovski <stephane.urbanovski@ac-nancy-metz.fr>
558
559 =cut

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.8