File Coverage

blib/lib/App/MonM/Checkit.pm
Criterion Covered Total %
statement 27 153 17.6
branch 0 70 0.0
condition 0 28 0.0
subroutine 9 24 37.5
pod 12 12 100.0
total 48 287 16.7


line stmt bran cond sub pod time code
1             package App::MonM::Checkit; # $Id: Checkit.pm 116 2022-08-27 08:57:12Z abalama $
2 1     1   6 use warnings;
  1         1  
  1         28  
3 1     1   4 use strict;
  1         1  
  1         14  
4 1     1   3 use utf8;
  1         1  
  1         3  
5              
6             =encoding utf-8
7              
8             =head1 NAME
9              
10             App::MonM::Checkit - App::MonM checkit class
11              
12             =head1 VIRSION
13              
14             Version 1.03
15              
16             =head1 SYNOPSIS
17              
18             use App::MonM::Checkit;
19              
20             =head1 DESCRIPTION
21              
22             App::MonM checkit class
23              
24             =head2 new
25              
26             my $checker = App::MonM::Checkit->new;
27              
28             Returns checker object
29              
30             =head2 check
31              
32             my $ostat = $checker->check({ ... });
33              
34             Performs checking of checkit-sources by checkit rules (checkit config sections)
35              
36             Returns status: 0 - PASS; 1 - FAIL
37              
38             =head2 cleanup
39              
40             my $self = $checker->cleanup;
41              
42             Flushes all working variables to defaults
43              
44             =head2 code
45              
46             my $code = $checker->code;
47             my $newcode = $checker->code(200);
48              
49             Sets and returns response code (rc)
50              
51             =head2 config
52              
53             my $conf = $checker->config;
54              
55             Returns Checkit config structure
56              
57             =head2 content
58              
59             my $content = $checker->content;
60             my $newcontent = $checker->content("Foo Bar Baz");
61              
62             Sets and returns the content value
63              
64             =head2 error
65              
66             my $error = $checker->error;
67             my $newerror = $checker->error("Blah-Blah-Blah");
68              
69             Sets and returns the error value
70              
71             =head2 message
72              
73             my $message = $checker->message;
74             my $newmessage = $checker->message("Foo Bar Baz");
75              
76             Sets and returns the message value
77              
78             =head2 note
79              
80             my $note = $checker->note;
81             $checker->note("Blah-Blah-Blah");
82              
83             Sets and returns the note value
84              
85             =head2 source
86              
87             my $source = $checker->source;
88             my $newsource = $checker->source("http://foo.example.com");
89              
90             Sets and returns the source value
91              
92             =head2 status
93              
94             my $status = $checker->status;
95             my $newstatus = $checker->status(1);
96              
97             Sets and returns the status value
98              
99             =head2 type
100              
101             my $type = $checker->type;
102             my $newtype = $checker->type(1);
103              
104             Sets and returns the type value
105              
106             =head1 CONFIGURATION DIRECTIVES
107              
108             General configuration options (directives) detailed describes in L
109              
110             The checkit configuration directives are specified in named
111             sections where NAME is the name of the checkit section.
112             The NAME is REQUIRED attribute. For example:
113              
114            
115             Enable yes
116             URL https://www.example.com
117             Target code
118             IsTrue 200
119            
120              
121             Each the checkit section can contain the following basic directives:
122              
123             =over 4
124              
125             =item B
126              
127             Enable yes
128              
129             The main switcher of the checkit section
130              
131             Default: no
132              
133             =item B
134              
135             Interval 20s
136              
137             Defines the time interval between two checks
138              
139             Format for time can be in any of the following forms:
140              
141             20 -- in 20 seconds
142             180s -- in 180 seconds
143             2m -- in 2 minutes
144             12h -- in 12 hours
145             1d -- in 1 day
146             3M -- in 3 months
147             2y -- in 2 years
148             3m -- 3 minutes ago(!)
149              
150             Default: 0
151              
152             =item B
153              
154             IsFalse Error.
155              
156             The definition of "What is bad?"
157              
158             Default: !!perl/regexp (?i-xsm:^\s*(0|error|fail|no|false))
159              
160             Examples:
161              
162             IsFalse !!perl/regexp (?i-xsm:^\s*(0|error|fail|no|false))
163             IsFalse 0
164             IsFalse Error.
165              
166             =item B
167              
168             IsTrue Ok.
169              
170             The definition of "What is good?"
171              
172             Default: !!perl/regexp (?i-xsm:^\s*(1|ok|pass|yes|true))
173              
174             Examples:
175              
176             IsTrue !!perl/regexp (?i-xsm:^\s*(1|ok|pass|yes|true))
177             IsTrue 1
178             IsTrue Ok.
179              
180             =item B
181              
182             OrderBy True,False
183              
184             Controls the order in which True and False are evaluated.
185             The OrderBy directive, along with the IsTrue and IsFalse directives,
186             controls a two-pass resolve system. The first pass processes IsTrue
187             or IsFalse directive, as specified by the OrderBy directive.
188             The second pass parses the rest of the directive (IsFalse or IsTrue).
189              
190             Ordering is one of:
191              
192             OrderBy True,False
193              
194             First, IsTrue directive is evaluated. Next, IsFalse directive is evaluated.
195             If matches IsTrue, the check's result sets to true (PASSED), otherwise
196             result sets to false (FAILED)
197              
198             OrderBy False,True
199              
200             First, IsFalse directive is evaluated. Next, IsTrue directive is evaluated.
201             If matches IsFalse, the check's result sets to false (FAILED), otherwise
202             result sets to true (PASSED)
203              
204             Default: "True,False"
205              
206             Examples:
207              
208             OrderBy True,False
209             OrderBy ASC # Is same as: "True,False"
210             OrderBy False,True
211             OrderBy DESC # Is same as: "False,True"
212              
213             =item B
214              
215             SendTo Alice
216              
217             Defines a List of Recipients for notifications.
218             There can be several such directives
219              
220             Email addresses for sending notifications directly (See Channel SendMail):
221              
222             SendTo foo@example.com
223             SendTo bar@example.com
224              
225             ...or SMS phone numbers (See Channel SMSGW):
226              
227             SendTo 11231230002
228             SendTo +11231230001
229             SendTo +1-123-123-0003
230              
231             ...or a notify users:
232              
233             SendTo Bob, Alice
234             SendTo Fred
235              
236             ...or a notify groups:
237              
238             SendTo @Foo, @Bar
239             SendTo @Baz
240              
241             =item B
242              
243             Target content
244              
245             Defines a target for analysis of results
246              
247             status - the status of the check operation is analyzed
248             code - the return code is analyzed (HTTP code, error code and etc.)
249             content - the content is analyzed (data from HTTP response, data
250             from command's STDOUT or data from DB)
251             message - the message is analyzed (HTTP message, eg.)
252              
253             Default: status
254              
255             =item B
256              
257             Trigger "curl http://cam.com/[NAME]/[ID]?[MSISDN] >/tmp/photo.jpg"
258              
259             Defines triggers (system commands) that runs before sending notifications
260             There can be several such directives
261             Each trigger can contents the variables for auto replacement, for example:
262              
263             Trigger "mycommand1 "[MESSAGE]""
264              
265             Replacement variables:
266              
267             [ID] -- Internal ID of the message
268             [MESSAGE], [MSG] -- The checker message content
269             [MSISDN] -- Phone number, recipient
270             [NAME] -- Checkit section name
271             [NOTE] -- The checker notes
272             [RESULT] -- The check result: PASSED/FAILED
273             [SOURCE], [SRC] -- Source string (URL, Command, etc.)
274             [STATUS] -- The checker status: OK/ERROR
275             [SUBJECT], [SBJ] -- Subject of message (MIME)
276             [TYPE] -- Type of checkit: http/dbi/command
277              
278             =item B
279              
280             Type https
281              
282             Defines checking type. As of today, three types are supported:
283             http(s), command and dbi(db)
284              
285             Default: http
286              
287             Examples:
288              
289             Type http
290             Type dbi
291             Type command
292              
293             =back
294              
295             The HTTP checkit directives are describes in L,
296             the "Command" checkit directives are describes in L,
297             the DBI checkit directives are describes in L
298              
299             =head1 HISTORY
300              
301             See C file
302              
303             =head1 TO DO
304              
305             See C file
306              
307             =head1 BUGS
308              
309             * none noted
310              
311             =head1 SEE ALSO
312              
313             L
314              
315             =head1 AUTHOR
316              
317             Serż Minus (Sergey Lepenkov) L Eabalama@cpan.orgE
318              
319             =head1 COPYRIGHT
320              
321             Copyright (C) 1998-2022 D&D Corporation. All Rights Reserved
322              
323             =head1 LICENSE
324              
325             This program is free software; you can redistribute it and/or
326             modify it under the same terms as Perl itself.
327              
328             See C file and L
329              
330             =cut
331              
332 1     1   52 use vars qw/$VERSION/;
  1         1  
  1         34  
333             $VERSION = '1.03';
334              
335 1     1   4 use mro;
  1         1  
  1         5  
336              
337 1     1   31 use CTK::ConfGenUtil;
  1         2  
  1         60  
338 1     1   6 use CTK::TFVals qw/ :ALL /;
  1         1  
  1         192  
339              
340 1         9 use parent qw/
341             App::MonM::Checkit::HTTP
342             App::MonM::Checkit::Command
343             App::MonM::Checkit::DBI
344 1     1   6 /;
  1         1  
345              
346             use constant {
347             TRUERX => qr/^\s*(1|ok|pass|yes|true)/i, # True regexp
348             FALSERX => qr/^\s*(0|error|fail|no|false)/i, # False regexp
349             ORDERBY => "true,false",
350             TARGET => "status",
351             FAIL => 0,
352             PASS => 1,
353             QRTYPES => {
354 0           '' => sub { qr{$_[0]} },
355 0           x => sub { qr{$_[0]}x },
356 0           i => sub { qr{$_[0]}i },
357 0           s => sub { qr{$_[0]}s },
358 0           m => sub { qr{$_[0]}m },
359 0           ix => sub { qr{$_[0]}ix },
360 0           sx => sub { qr{$_[0]}sx },
361 0           mx => sub { qr{$_[0]}mx },
362 0           si => sub { qr{$_[0]}si },
363 0           mi => sub { qr{$_[0]}mi },
364 0           ms => sub { qr{$_[0]}sm },
365 0           six => sub { qr{$_[0]}six },
366 0           mix => sub { qr{$_[0]}mix },
367 0           msx => sub { qr{$_[0]}msx },
368 0           msi => sub { qr{$_[0]}msi },
369 0           msix => sub { qr{$_[0]}msix },
370             },
371 1     1   351 };
  1         2  
  1         1149  
372              
373             sub new {
374 0     0 1   my $class = shift;
375 0           my %args = @_;
376 0           my $self = bless {%args}, $class;
377 0           return $self->cleanup;
378             }
379             sub cleanup {
380 0     0 1   my $self = shift;
381 0           $self->{config} = {}; # Config
382 0           $self->{status} = undef; # 1 - Ok; 0 - Error
383 0           $self->{error} = ''; # Error string
384 0           $self->{code} = undef; # 200
385 0           $self->{type} = undef; # http/dbi/command
386 0           $self->{source} = ''; # URL/DSN/Command
387 0           $self->{message} = ''; # Message string or error
388 0           $self->{content} = ''; # Content data or STDOUT data
389 0           $self->{note} = ''; # Note
390 0           return $self;
391             }
392             sub config {
393 0     0 1   my $self = shift;
394 0           return $self->{config};
395             }
396             sub status {
397 0     0 1   my $self = shift;
398 0           my $v = shift;
399 0 0         $self->{status} = $v if defined $v;
400 0           return $self->{status};
401             }
402             sub error {
403 0     0 1   my $self = shift;
404 0           my $v = shift;
405 0 0         $self->{error} = $v if defined $v;
406 0           return $self->{error};
407             }
408             sub code {
409 0     0 1   my $self = shift;
410 0           my $v = shift;
411 0 0         $self->{code} = $v if defined $v;
412 0           return $self->{code};
413             }
414             sub type {
415 0     0 1   my $self = shift;
416 0           my $v = shift;
417 0 0         $self->{type} = $v if defined $v;
418 0           return $self->{type};
419             }
420             sub source {
421 0     0 1   my $self = shift;
422 0           my $v = shift;
423 0 0         $self->{source} = $v if defined $v;
424 0           return $self->{source};
425             }
426             sub message {
427 0     0 1   my $self = shift;
428 0           my $v = shift;
429 0 0         $self->{message} = $v if defined $v;
430 0           return $self->{message};
431             }
432             sub content {
433 0     0 1   my $self = shift;
434 0           my $v = shift;
435 0 0         $self->{content} = $v if defined $v;
436 0           return $self->{content};
437             }
438             sub note {
439 0     0 1   my $self = shift;
440 0           my $v = shift;
441 0 0         $self->{note} = $v if defined $v;
442 0           return $self->{note};
443             }
444             sub check {
445 0     0 1   my $self = shift;
446 0           my $conf = shift;
447 0           my $result = FAIL;
448 0           $self->cleanup;
449 0 0         $self->{config} = $conf if ref($conf) eq 'HASH';
450 0   0       $self->type(lc(lvalue($conf, 'type') || 'http'));
451 0           $self->maybe::next::method();
452              
453             # Check response
454 0           my $true_regexp = _qrreconstruct(lvalue($conf, 'istrue'));
455 0           my $false_regexp= _qrreconstruct(lvalue($conf, 'isfalse'));
456 0   0       my $orderby = lvalue($conf, 'orderby') || ORDERBY;
457 0   0       my $target = lc(lvalue($conf, 'target') || TARGET);
458 0           my $test; # Value for testing
459 0 0         if ($target eq 'code') { $test = $self->code } # code
  0 0          
    0          
460 0           elsif ($target eq 'message') { $test = $self->message } # message
461 0           elsif ($target eq 'content') { $test = $self->content } # content
462             else { # status (default)
463 0           $target = TARGET;
464 0           $test = $self->status;
465             }
466 0   0       $test //= '';
467              
468             # Check test value
469 0           my ($direct, $rule);
470 0 0 0       if (($orderby =~ /false\s*\,\s*true/i) || ($orderby =~ /desc/i)) { # DESC
471 0           $direct = "DESC";
472 0 0         if (defined $false_regexp) {
    0          
473 0           $result = _cmp($test, $false_regexp, [FAIL, PASS]);
474 0 0         $rule = $result ? "!= FALSE" : "== FALSE";
475             } elsif (defined $true_regexp) {
476 0           $result = _cmp($test, $true_regexp, [PASS, FAIL]);
477 0 0         $rule = $result ? "== TRUE" : "!= TRUE";
478             } else {
479 0           $result = _cmp($test, FALSERX, [FAIL, PASS]);
480 0 0         $rule = $result ? "!= FALSE-DEFAULT" : "== FALSE-DEFAULT";
481             }
482             } else { # ASC
483 0           $direct = "ASC";
484 0 0         if (defined $true_regexp) {
    0          
485 0           $result = _cmp($test, $true_regexp, [PASS, FAIL]);
486 0 0         $rule = $result ? "== TRUE" : "!= TRUE";
487             } elsif (defined $false_regexp) {
488 0           $result = _cmp($test, $false_regexp, [FAIL, PASS]);
489 0 0         $rule = $result ? "!= FALSE" : "== FALSE";
490             } else {
491 0           $result = _cmp($test, TRUERX, [PASS, FAIL]);
492 0 0         $rule = $result ? "== TRUE-DEFAULT" : "!= TRUE-DEFAULT";
493             }
494             }
495              
496             # Set errors and note
497 0 0 0       my $rtt = (defined($true_regexp) && ref($true_regexp)) ? ref($true_regexp) : 'String';
498 0 0 0       my $rtf = (defined($false_regexp) && ref($false_regexp)) ? ref($false_regexp) : 'String';
499 0 0         my $note = sprintf("Check [%s] %s: RESULT [%s] %s (%s) [%s]",
    0          
    0          
500             $self->type,
501             $result ? "PASSED" : "FAILED",
502             $target, $rule, $direct,
503             $rule =~ /DEF/ ? 'Regexp (DEFAULT)' : $rule =~ /TRUE/ ? $rtt : $rtf);
504 0           $self->note($note);
505 0 0 0       $self->error($note) if !$result && !$self->error; # Set error if NO erorrs from backends
506              
507 0           return $result;
508             }
509              
510             sub _qrreconstruct {
511             # Returns regular expression (QR)
512             # Gets from YAML::Type::regexp of YAML::Types
513             # To input:
514             # !!perl/regexp (?i-xsm:^\s*(error|fault|no))
515             # Translate to:
516             # qr/^\s*(error|fault|no)/i
517 0     0     my $v = shift;
518 0 0         return undef unless defined $v;
519 0 0         return $v unless $v =~ /^\s*\!\!perl\/regexp\s*/i;
520 0           $v =~ s/\s*\!\!perl\/regexp\s*//i;
521 0 0         return qr{$v} unless $v =~ /^\(\?([\^\-xism]*):(.*)\)\z/s;
522 0           my ($flags, $re) = ($1, $2);
523 0           $flags =~ s/-.*//;
524 0           $flags =~ s/^\^//;
525 0   0 0     my $sub = QRTYPES->{$flags} || sub { qr{$_[0]} };
  0            
526 0           return $sub->($re);
527             }
528             sub _cmp {
529 0   0 0     my $s = shift || ''; # Text
530 0   0       my $x = shift || ''; # Regext
531 0   0       my $r = shift || [PASS, FAIL]; # Select [OK, ERROR]
532 0 0         if (ref($x) eq 'Regexp') {
533 0 0         return $r->[0] if $s =~ $x;
534             } else {
535 0 0         return $r->[0] if $s eq $x;
536             }
537 0           return $r->[1];
538             }
539              
540             1;
541              
542             __END__