line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package App::MonM; # $Id: MonM.pm 89 2019-07-15 05:19:11Z abalama $ |
2
|
1
|
|
|
1
|
|
53719
|
use warnings; |
|
1
|
|
|
|
|
9
|
|
|
1
|
|
|
|
|
29
|
|
3
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
16
|
|
4
|
1
|
|
|
1
|
|
525
|
use utf8; |
|
1
|
|
|
|
|
12
|
|
|
1
|
|
|
|
|
4
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=encoding utf-8 |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 NAME |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
App::MonM - Simple monitoring tool |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 VERSION |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
Version 1.07 |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 SYNOPSIS |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# monm checkit |
19
|
|
|
|
|
|
|
# monm report |
20
|
|
|
|
|
|
|
# monm show |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 DESCRIPTION |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
Simple monitoring tool |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head2 FEATURES |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=over 4 |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=item Checking availability of sites (http/https) |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=item Checking of database health (DBI) |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=item Checking internal and external counters using system commands and tools (command) |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=item Supports SMTP, POP3, FTP, SSH protocols, and etc. |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=item Interface for SMS sending |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=item Easy installation and configuration |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=item A small number of system dependencies |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=back |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=head2 SYSTEM REQUIREMENTS |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=over 4 |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=item Perl v5.16+ |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=item libwww |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=item libnet |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=item L |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
To use this module, you must have Net-SNMP installed on your system. |
59
|
|
|
|
|
|
|
More specifically you need the Perl modules that come with it. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
DO NOT INSTALL SNMP or Net::SNMP from CPAN! |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
The SNMP module is matched to an install of net-snmp, and must be installed |
64
|
|
|
|
|
|
|
from the net-snmp source tree. |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
The Perl module C is found inside the net-snmp distribution. Go to the |
67
|
|
|
|
|
|
|
F directory of the distribution to install it, or run |
68
|
|
|
|
|
|
|
C<./configure --with-perl-modules> from the top directory of the net-snmp |
69
|
|
|
|
|
|
|
distribution. |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
Net-SNMP can be found at http://net-snmp.sourceforge.net |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=back |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=head2 INSTALLATION |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# sudo cpan install App::MonM |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
...and then: |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# sudo monm configure |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=head2 CONFIGURATION |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
By default configuration file located in C directory |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Every configuration directive detailed described in C file, also |
88
|
|
|
|
|
|
|
see C file for MonM checkit configuration |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=head2 CRONTAB |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
To automatically launch the program, we recommend using standard scheduling tools, such as crontab |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
* * * * * monm -l checkit >/dev/null 2>>/var/log/monm-error.log |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
For daily reporting: |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
0 8 * * * monm -l report >/dev/null 2>>/var/log/monm-error.log |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=head1 INTERNAL METHODS |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=over 4 |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=item B |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
The CTK method for classes extension. For internal use only! |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
See L |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=item B |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
The internal method for initializing the project |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=item B |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
my $dbi = $app->getdbi; |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
Returns DBI object |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=item B, B, B, B |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
my $status = $app->nope("Format %s", "text"); |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
Prints status message and returns status. |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
For nope returns - 0; for skip, wow, yep - 1 |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=item B |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
$app->notify(); |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
Sends notifications |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=item B |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
$app->trigger(); |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
Runs triggers |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=back |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=head1 HISTORY |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
See C file |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=head1 DEPENDENCIES |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
L |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=head1 TO DO |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
See C file |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=head1 BUGS |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
* none noted |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=head1 SEE ALSO |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
L |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=head1 AUTHOR |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
Serż Minus (Sergey Lepenkov) L Eabalama@cpan.orgE |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=head1 COPYRIGHT |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
Copyright (C) 1998-2019 D&D Corporation. All Rights Reserved |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=head1 LICENSE |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or |
173
|
|
|
|
|
|
|
modify it under the same terms as Perl itself. |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
See C file and L |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=cut |
178
|
|
|
|
|
|
|
|
179
|
1
|
|
|
1
|
|
50
|
use vars qw/ $VERSION /; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
47
|
|
180
|
|
|
|
|
|
|
$VERSION = '1.07'; |
181
|
|
|
|
|
|
|
|
182
|
1
|
|
|
1
|
|
5
|
use feature qw/ say /; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
387
|
|
183
|
|
|
|
|
|
|
|
184
|
1
|
|
|
1
|
|
5
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
43
|
|
185
|
1
|
|
|
1
|
|
398
|
use Text::SimpleTable; |
|
1
|
|
|
|
|
1963
|
|
|
1
|
|
|
|
|
25
|
|
186
|
1
|
|
|
1
|
|
5
|
use File::Spec; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
24
|
|
187
|
1
|
|
|
1
|
|
5
|
use File::Path; # mkpath / rmtree |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
57
|
|
188
|
1
|
|
|
1
|
|
414
|
use Try::Tiny; |
|
1
|
|
|
|
|
1665
|
|
|
1
|
|
|
|
|
49
|
|
189
|
1
|
|
|
1
|
|
359
|
use Text::ParseWords qw/shellwords/; |
|
1
|
|
|
|
|
1050
|
|
|
1
|
|
|
|
|
46
|
|
190
|
|
|
|
|
|
|
|
191
|
1
|
|
|
1
|
|
386
|
use CTK::Skel; |
|
1
|
|
|
|
|
160275
|
|
|
1
|
|
|
|
|
36
|
|
192
|
1
|
|
|
1
|
|
8
|
use CTK::Util qw/ preparedir dformat execute dtf sendmail variant_stf /; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
55
|
|
193
|
1
|
|
|
1
|
|
6
|
use CTK::ConfGenUtil; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
46
|
|
194
|
1
|
|
|
1
|
|
5
|
use CTK::TFVals qw/ :ALL /; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
149
|
|
195
|
|
|
|
|
|
|
|
196
|
1
|
|
|
1
|
|
392
|
use App::MonM::Const; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
55
|
|
197
|
1
|
|
|
|
|
69
|
use App::MonM::Util qw/ |
198
|
|
|
|
|
|
|
blue green red yellow cyan |
199
|
|
|
|
|
|
|
getBit setBit |
200
|
|
|
|
|
|
|
getExpireOffset explain |
201
|
1
|
|
|
1
|
|
342
|
/; |
|
1
|
|
|
|
|
2
|
|
202
|
1
|
|
|
1
|
|
361
|
use App::MonM::Store; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
28
|
|
203
|
1
|
|
|
1
|
|
397
|
use App::MonM::Checkit; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
31
|
|
204
|
|
|
|
|
|
|
|
205
|
1
|
|
|
1
|
|
6
|
use base qw/ CTK::App /; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
397
|
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
use constant { |
208
|
1
|
|
|
|
|
4840
|
TAB9 => " " x 9, |
209
|
|
|
|
|
|
|
EXPIRES => 24*60*60, # 1 day |
210
|
|
|
|
|
|
|
SMSSBJ => 'MONM CHECKIT REPORT', |
211
|
|
|
|
|
|
|
DATE_FORMAT => '%YYYY-%MM-%DD %hh:%mm:%ss', |
212
|
|
|
|
|
|
|
TABLE_HEADERS => [( |
213
|
|
|
|
|
|
|
[32, 'NAME'], |
214
|
|
|
|
|
|
|
[7, 'TYPE'], |
215
|
|
|
|
|
|
|
[19, 'LAST CHECK DATE'], |
216
|
|
|
|
|
|
|
[7, 'STATUS'], |
217
|
|
|
|
|
|
|
)], |
218
|
1
|
|
|
1
|
|
5333
|
}; |
|
1
|
|
|
|
|
2
|
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
eval { require App::MonM::Notifier::Agent }; |
221
|
|
|
|
|
|
|
my $NOTIFIER_LOADED = 1 unless $@; |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub again { |
224
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# Datadir & Tempdir |
227
|
0
|
0
|
|
|
|
|
if ($self->option("datadir")) { |
228
|
0
|
|
|
|
|
|
preparedir( $self->datadir() ); |
229
|
|
|
|
|
|
|
} else { |
230
|
0
|
|
|
|
|
|
$self->datadir($self->tempdir()); |
231
|
|
|
|
|
|
|
} |
232
|
0
|
|
|
|
|
|
preparedir( $self->tempdir() ); |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
# Notifier agent init |
235
|
0
|
|
|
|
|
|
$self->{notifier} = undef; |
236
|
|
|
|
|
|
|
|
237
|
0
|
|
|
|
|
|
return $self->SUPER::again; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
sub configure { |
240
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
241
|
0
|
|
|
|
|
|
my $config = $self->configobj; |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# DBI object |
244
|
0
|
|
|
|
|
|
my $dbi_file = File::Spec->catfile($self->datadir, App::MonM::Store::DB_FILENAME()); |
245
|
0
|
|
0
|
|
|
|
my $dbi_conf = $self->config('dbi') || {file => $dbi_file}; |
246
|
0
|
0
|
|
|
|
|
$dbi_conf = {file => $dbi_file} unless is_hash($dbi_conf); |
247
|
0
|
|
|
|
|
|
my $dbi = new App::MonM::Store(%$dbi_conf); |
248
|
0
|
|
|
|
|
|
$self->{_dbi} = $dbi; |
249
|
0
|
0
|
|
|
|
|
if ($config->status) { |
250
|
0
|
0
|
|
|
|
|
$self->error($dbi->error) if $dbi->error; |
251
|
0
|
|
|
|
|
|
return 1; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# Creting DB |
255
|
0
|
0
|
|
|
|
|
if ($dbi->is_sqlite) { |
256
|
0
|
|
|
|
|
|
printf("Creating local database %s...\n", $dbi->{file}); |
257
|
|
|
|
|
|
|
} else { |
258
|
0
|
|
|
|
|
|
printf("Checking database %s...\n", $dbi->dsn); |
259
|
|
|
|
|
|
|
} |
260
|
0
|
0
|
|
|
|
|
if ($dbi->error) { |
261
|
0
|
|
|
|
|
|
say( IS_TTY ? red("Fail") : "Fail"); |
262
|
0
|
|
|
|
|
|
$self->error($dbi->error); |
263
|
|
|
|
|
|
|
} else { |
264
|
0
|
|
|
|
|
|
say( IS_TTY ? green("Done") : "Done"); |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
# Creating configuration |
268
|
0
|
|
|
|
|
|
my $skel = new CTK::Skel ( |
269
|
|
|
|
|
|
|
-name => PROJECTNAME, |
270
|
|
|
|
|
|
|
-root => $self->root, |
271
|
|
|
|
|
|
|
-skels => { |
272
|
|
|
|
|
|
|
config => 'App::MonM::ConfigSkel', |
273
|
|
|
|
|
|
|
}, |
274
|
|
|
|
|
|
|
-vars => { |
275
|
|
|
|
|
|
|
PROJECT => PROJECTNAME, |
276
|
|
|
|
|
|
|
PROJECTNAME => PROJECTNAME, |
277
|
|
|
|
|
|
|
PREFIX => PREFIX, |
278
|
|
|
|
|
|
|
}, |
279
|
|
|
|
|
|
|
-debug => $self->debugmode, |
280
|
|
|
|
|
|
|
); |
281
|
|
|
|
|
|
|
#say("Skel object: ", explain($skel)); |
282
|
0
|
|
|
|
|
|
printf("Creating configuration to %s...\n", $self->root); |
283
|
0
|
0
|
|
|
|
|
if ($skel->build("config")) { |
284
|
0
|
|
|
|
|
|
$self->CTK::Plugin::Config::init; |
285
|
0
|
|
|
|
|
|
$config = $self->configobj; |
286
|
0
|
0
|
|
|
|
|
unless ($config->status) { |
287
|
0
|
|
|
|
|
|
say( IS_TTY ? red("Fail") : "Fail"); |
288
|
0
|
|
|
|
|
|
return 0; |
289
|
|
|
|
|
|
|
} |
290
|
0
|
|
|
|
|
|
say( IS_TTY ? green("Done") : "Done"); |
291
|
|
|
|
|
|
|
} else { |
292
|
0
|
|
|
|
|
|
say( IS_TTY ? red("Fail") : "Fail"); |
293
|
0
|
|
|
|
|
|
$self->error(sprintf("Can't %s initialize: %s", PREFIX, $self->root)); |
294
|
0
|
|
|
|
|
|
return 0; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
0
|
|
|
|
|
|
return 1; |
298
|
|
|
|
|
|
|
} |
299
|
0
|
|
|
0
|
1
|
|
sub getdbi {shift->{_dbi}} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
__PACKAGE__->register_handler( |
302
|
|
|
|
|
|
|
handler => "configure", |
303
|
|
|
|
|
|
|
description => sprintf("Configure %s", PROJECTNAME), |
304
|
|
|
|
|
|
|
code => sub { shift->configure }); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
__PACKAGE__->register_handler( |
307
|
|
|
|
|
|
|
handler => "config", |
308
|
|
|
|
|
|
|
description => "Alias for configure command", |
309
|
|
|
|
|
|
|
code => sub { shift->configure }); |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
__PACKAGE__->register_handler( |
312
|
|
|
|
|
|
|
handler => "checkit", |
313
|
|
|
|
|
|
|
description => "Checkit", |
314
|
|
|
|
|
|
|
code => sub { |
315
|
|
|
|
|
|
|
### CODE: |
316
|
|
|
|
|
|
|
my ($self, $meta, @arguments) = @_; |
317
|
|
|
|
|
|
|
$self->configure or return 0; |
318
|
|
|
|
|
|
|
my $status = 1; |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
printf("Start of checking for %s...\n", HOSTNAME); |
321
|
|
|
|
|
|
|
$self->wow("Will checked: %s", join(", ", @arguments)) if @arguments; |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# Get DBI |
324
|
|
|
|
|
|
|
my $dbi = $self->getdbi; |
325
|
|
|
|
|
|
|
return 0 if $dbi->error; |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# Get checkits |
328
|
|
|
|
|
|
|
my @checkits = $self->_getCheckits(@arguments); |
329
|
|
|
|
|
|
|
unless (scalar(@checkits)) { |
330
|
|
|
|
|
|
|
$self->log_warn("No enabled configuration section found"); |
331
|
|
|
|
|
|
|
return 1; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
# Create Checkit object |
335
|
|
|
|
|
|
|
my $checker = new App::MonM::Checkit; |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
# Get all records from DB |
338
|
|
|
|
|
|
|
my %all; |
339
|
|
|
|
|
|
|
foreach my $r ($dbi->getall) { |
340
|
|
|
|
|
|
|
$all{$r->{name}} = $r; |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
if ($dbi->error) { |
343
|
|
|
|
|
|
|
$self->error($dbi->error); |
344
|
|
|
|
|
|
|
return 0; |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
# Init notifier and sending messages |
348
|
|
|
|
|
|
|
if ($NOTIFIER_LOADED) { |
349
|
|
|
|
|
|
|
$self->{notifier} = App::MonM::Notifier::Agent->new( |
350
|
|
|
|
|
|
|
configobj => $self->configobj, |
351
|
|
|
|
|
|
|
); |
352
|
|
|
|
|
|
|
my $agent = $self->{notifier}; |
353
|
|
|
|
|
|
|
unless ($agent->status) { |
354
|
|
|
|
|
|
|
$self->error($agent->error); |
355
|
|
|
|
|
|
|
return 0; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
# Run sending messages |
359
|
|
|
|
|
|
|
$agent->trysend() or do { |
360
|
|
|
|
|
|
|
$self->log_error($agent->error); |
361
|
|
|
|
|
|
|
}; |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
# Start |
365
|
|
|
|
|
|
|
foreach my $checkit (sort {$a->{name} cmp $b->{name}} @checkits) { |
366
|
|
|
|
|
|
|
my $ostat = 1; # Operation status |
367
|
|
|
|
|
|
|
my $name = $checkit->{name}; |
368
|
|
|
|
|
|
|
my $info = $all{$name} || {}; |
369
|
|
|
|
|
|
|
my $id = $info->{id} || 0; |
370
|
|
|
|
|
|
|
my $old = $info->{status} || 0; |
371
|
|
|
|
|
|
|
my $got = ($old << 1) & 15; |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
# Check |
374
|
|
|
|
|
|
|
$ostat = $checker->check($checkit); |
375
|
|
|
|
|
|
|
$self->log_info("Checking %s (%s >>> %s): %s", $name, $checker->source, $checker->message, $ostat ? 'OK' : "FAIL"); |
376
|
|
|
|
|
|
|
if ($ostat) { |
377
|
|
|
|
|
|
|
$self->yep("Checking %s (%s >>> %s)", $name, $checker->source, $checker->message); |
378
|
|
|
|
|
|
|
$got = setBit($got, 0); # Set first bit |
379
|
|
|
|
|
|
|
} else { |
380
|
|
|
|
|
|
|
$self->nope("Checking %s (%s >>> %s)", $name, $checker->source, $checker->message); |
381
|
|
|
|
|
|
|
say(TAB9, red($checker->error)); |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
# Save data to database |
385
|
|
|
|
|
|
|
my %rec = ( |
386
|
|
|
|
|
|
|
id => $id, |
387
|
|
|
|
|
|
|
name => $name, |
388
|
|
|
|
|
|
|
type => $checker->type, |
389
|
|
|
|
|
|
|
source => $checker->source, |
390
|
|
|
|
|
|
|
status => $got, |
391
|
|
|
|
|
|
|
message => $checker->message, |
392
|
|
|
|
|
|
|
); |
393
|
|
|
|
|
|
|
if ($id) { |
394
|
|
|
|
|
|
|
$dbi->set(%rec) or do { |
395
|
|
|
|
|
|
|
$self->error($dbi->error); |
396
|
|
|
|
|
|
|
$status = 0; |
397
|
|
|
|
|
|
|
next; |
398
|
|
|
|
|
|
|
}; |
399
|
|
|
|
|
|
|
} else { |
400
|
|
|
|
|
|
|
$dbi->add(%rec) or do { |
401
|
|
|
|
|
|
|
$self->error($dbi->error); |
402
|
|
|
|
|
|
|
$status = 0; |
403
|
|
|
|
|
|
|
next; |
404
|
|
|
|
|
|
|
}; |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# Triggers, Sending and notifies |
408
|
|
|
|
|
|
|
# [0-0-1-1] = 3 -- OK |
409
|
|
|
|
|
|
|
# [1-1-0-0] = 12 -- PROBLEM |
410
|
|
|
|
|
|
|
if ($got == 3 or $got == 12 or $self->testmode) { |
411
|
|
|
|
|
|
|
my %data = ( |
412
|
|
|
|
|
|
|
name => $name, |
413
|
|
|
|
|
|
|
type => $checker->type, |
414
|
|
|
|
|
|
|
source => $checker->source, |
415
|
|
|
|
|
|
|
status => $ostat, |
416
|
|
|
|
|
|
|
error => $checker->error, |
417
|
|
|
|
|
|
|
message => $checker->message, |
418
|
|
|
|
|
|
|
sendto => array($checkit, "sendto"), |
419
|
|
|
|
|
|
|
trigger => array($checkit, "trigger"), |
420
|
|
|
|
|
|
|
); |
421
|
|
|
|
|
|
|
$self->notify(%data); |
422
|
|
|
|
|
|
|
$self->trigger(%data); |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
# General status |
426
|
|
|
|
|
|
|
$status = 0 unless $ostat; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
# Cleaning DB |
430
|
|
|
|
|
|
|
my $expire = getExpireOffset($self->config("expires") || $self->config("expire") || EXPIRES); |
431
|
|
|
|
|
|
|
$dbi->clean(period => $expire) or do { |
432
|
|
|
|
|
|
|
$self->error($dbi->error); |
433
|
|
|
|
|
|
|
return 0; |
434
|
|
|
|
|
|
|
}; |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
# Finish |
437
|
|
|
|
|
|
|
printf("Finish of checking for %s (%s)\n", HOSTNAME, $self->tms); |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
return $status; |
440
|
|
|
|
|
|
|
}); |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
__PACKAGE__->register_handler( |
443
|
|
|
|
|
|
|
handler => "report", |
444
|
|
|
|
|
|
|
description => "Checkit report", |
445
|
|
|
|
|
|
|
code => sub { |
446
|
|
|
|
|
|
|
### CODE: |
447
|
|
|
|
|
|
|
my ($self, $meta, @arguments) = @_; |
448
|
|
|
|
|
|
|
$self->configure or return 0; |
449
|
|
|
|
|
|
|
my (@header, @errors, @report, @table); |
450
|
|
|
|
|
|
|
my $status = 1; |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# Init |
453
|
|
|
|
|
|
|
my $tbl = Text::SimpleTable->new(@{(TABLE_HEADERS)}); |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
# Start reporting |
456
|
|
|
|
|
|
|
printf("Start of the checkit reporting for %s...\n", HOSTNAME); |
457
|
|
|
|
|
|
|
$self->wow("Will checked: %s", join(", ", @arguments)) if @arguments; |
458
|
|
|
|
|
|
|
$self->log_info("Start of the checkit reporting for \"%s\"", HOSTNAME); |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
# Header |
461
|
|
|
|
|
|
|
push @header, ["Hostname", HOSTNAME]; |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
# Get DBI |
464
|
|
|
|
|
|
|
my $dbi = $self->getdbi; |
465
|
|
|
|
|
|
|
push @header, ["Database DSN", $dbi->dsn]; |
466
|
|
|
|
|
|
|
if ($dbi->error) { |
467
|
|
|
|
|
|
|
push @errors, $dbi->dsn, $dbi->error, ""; |
468
|
|
|
|
|
|
|
$self->log_error("%s: %s", $dbi->dsn, $dbi->error); |
469
|
|
|
|
|
|
|
$self->nope($dbi->dsn); |
470
|
|
|
|
|
|
|
say(TAB9, red($dbi->error)); |
471
|
|
|
|
|
|
|
$status = 0; |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
# Get checkits |
475
|
|
|
|
|
|
|
my @checkits = $self->_getCheckits(@arguments); |
476
|
|
|
|
|
|
|
my $noc = scalar(@checkits); |
477
|
|
|
|
|
|
|
push @header, ["Number of checks", $noc ? $noc : "no checks"]; |
478
|
|
|
|
|
|
|
unless ($noc) { |
479
|
|
|
|
|
|
|
$self->log_warn("No enabled configuration section found"); |
480
|
|
|
|
|
|
|
$status = 0; |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
# Get all records from DB |
484
|
|
|
|
|
|
|
my %all; |
485
|
|
|
|
|
|
|
if ($status) { |
486
|
|
|
|
|
|
|
foreach my $r ($dbi->getall) { |
487
|
|
|
|
|
|
|
$all{$r->{name}} = $r; |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
if ($dbi->error) { |
490
|
|
|
|
|
|
|
push @errors, $dbi->dsn, $dbi->error, ""; |
491
|
|
|
|
|
|
|
$self->log_error("%s: %s", $dbi->dsn, $dbi->error); |
492
|
|
|
|
|
|
|
$self->nope($dbi->dsn); |
493
|
|
|
|
|
|
|
say(TAB9, red($dbi->error)); |
494
|
|
|
|
|
|
|
$status = 0; |
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
# |
499
|
|
|
|
|
|
|
# General cycle |
500
|
|
|
|
|
|
|
# |
501
|
|
|
|
|
|
|
foreach my $checkit (sort {$a->{name} cmp $b->{name}} @checkits) { |
502
|
|
|
|
|
|
|
my $name = $checkit->{name}; |
503
|
|
|
|
|
|
|
my $info = $all{$name} || {}; |
504
|
|
|
|
|
|
|
my $last = $info->{"time"} || 0; |
505
|
|
|
|
|
|
|
my $v = $info->{status} || 0; |
506
|
|
|
|
|
|
|
my $ostat = -1; |
507
|
|
|
|
|
|
|
if (getBit($v, 0) && getBit($v, 1) && getBit($v, 2)) { # Ok |
508
|
|
|
|
|
|
|
$ostat = 1; |
509
|
|
|
|
|
|
|
} elsif ((getBit($v, 0) + getBit($v, 1)) == 0) { # Problem |
510
|
|
|
|
|
|
|
$ostat = 0; |
511
|
|
|
|
|
|
|
$status = 0; |
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
$tbl->row($name, $info->{type} || 'http', |
514
|
|
|
|
|
|
|
$last ? dtf(DATE_FORMAT, $last) : "", |
515
|
|
|
|
|
|
|
$ostat ? $ostat > 0 ? 'OK' : 'UNKNOWN' : 'PROBLEM', |
516
|
|
|
|
|
|
|
); |
517
|
|
|
|
|
|
|
unless ($ostat) { |
518
|
|
|
|
|
|
|
push @errors, sprintf("%s (%s >>> %s)", $name, $info->{source} || '', $info->{message} || ''), ""; |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
#say(explain($info)); |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
$tbl->hr; |
523
|
|
|
|
|
|
|
$tbl->row('SUMMARY', "", "", $noc ? $status ? 'OK' : 'PROBLEM' : 'UNKNOWN'); |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
# Get SendMail config |
526
|
|
|
|
|
|
|
my $sendmail = hash($self->config('sendmail')); |
527
|
|
|
|
|
|
|
my $to = uv2null(value($sendmail, "to")); |
528
|
|
|
|
|
|
|
my $send_report = 1 if $to && $to !~ /\@example.com$/; |
529
|
|
|
|
|
|
|
push @header, ["Send report to", $to] if $send_report; |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
# |
532
|
|
|
|
|
|
|
# Report generate |
533
|
|
|
|
|
|
|
# |
534
|
|
|
|
|
|
|
push @header, ["Summary status", $status ? 'OK' : 'PROBLEM']; |
535
|
|
|
|
|
|
|
my $report_name = $status ? "checking report" : "error report"; |
536
|
|
|
|
|
|
|
push @report, $self->_report_common(@header); # Common information |
537
|
|
|
|
|
|
|
push @report, $self->_report_summary($status ? "All last checks successful" : "Errors occurred while checking"); # Summary table |
538
|
|
|
|
|
|
|
push @report, $tbl->draw(); # Report table |
539
|
|
|
|
|
|
|
push @report, $self->_report_errors(@errors); # List of occurred errors |
540
|
|
|
|
|
|
|
if (IS_TTY || $self->verbosemode) { # Draw to TTY |
541
|
|
|
|
|
|
|
printf("%s\n\n", "~" x SCREENWIDTH); |
542
|
|
|
|
|
|
|
printf("The %s for last checks on %s\n\n", $report_name, HOSTNAME); |
543
|
|
|
|
|
|
|
print join("\n", @report, ""); |
544
|
|
|
|
|
|
|
} |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
# |
547
|
|
|
|
|
|
|
# SendMail (Send report) |
548
|
|
|
|
|
|
|
# |
549
|
|
|
|
|
|
|
if ($send_report) { |
550
|
|
|
|
|
|
|
unshift @report, $self->_report_title($report_name, "last checks"); |
551
|
|
|
|
|
|
|
push @report, $self->_report_footer(); |
552
|
|
|
|
|
|
|
my %ma = (); foreach my $k (keys %$sendmail) { $ma{"-".$k} = $sendmail->{$k} }; |
553
|
|
|
|
|
|
|
$ma{"-subject"} = sprintf("%s %s (%s on %s)", PROJECTNAME, $report_name, "last checks", HOSTNAME); |
554
|
|
|
|
|
|
|
$ma{"-message"} = join("\n", @report); |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
# Send! |
557
|
|
|
|
|
|
|
my $sent = sendmail(%ma); |
558
|
|
|
|
|
|
|
if ($sent) { |
559
|
|
|
|
|
|
|
my $msg = sprintf("Mail has been sent to: %s", $to); |
560
|
|
|
|
|
|
|
$self->wow($msg); |
561
|
|
|
|
|
|
|
$self->log_info($msg); |
562
|
|
|
|
|
|
|
} else { |
563
|
|
|
|
|
|
|
my $msg = sprintf("Mail was not sent to: %s", $to); |
564
|
|
|
|
|
|
|
$self->skip($msg); |
565
|
|
|
|
|
|
|
$self->log_warning($msg); |
566
|
|
|
|
|
|
|
} |
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
# Finish reporting |
570
|
|
|
|
|
|
|
printf("Finish of the checkit reporting for %s (%s)\n", HOSTNAME, $self->tms); |
571
|
|
|
|
|
|
|
$self->log_info("Finish of the checkit reporting for \"%s\" (%s)", HOSTNAME, $self->tms); |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
return $status; |
574
|
|
|
|
|
|
|
}); |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
__PACKAGE__->register_handler( |
577
|
|
|
|
|
|
|
handler => "show", |
578
|
|
|
|
|
|
|
description => "Show table data", |
579
|
|
|
|
|
|
|
code => sub { |
580
|
|
|
|
|
|
|
### CODE: |
581
|
|
|
|
|
|
|
my ($self, $meta, @arguments) = @_; |
582
|
|
|
|
|
|
|
$self->configure or return 0; |
583
|
|
|
|
|
|
|
my (@header, @errors, @report, @table); |
584
|
|
|
|
|
|
|
my $status = 1; |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
# Start |
587
|
|
|
|
|
|
|
printf("Getting checkit data for %s...\n", HOSTNAME); |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
# Get DBI |
590
|
|
|
|
|
|
|
my $dbi = $self->getdbi; |
591
|
|
|
|
|
|
|
if ($dbi->error) { |
592
|
|
|
|
|
|
|
$self->log_error("%s: %s", $dbi->dsn, $dbi->error); |
593
|
|
|
|
|
|
|
$self->nope($dbi->dsn); |
594
|
|
|
|
|
|
|
say(TAB9, red($dbi->error)); |
595
|
|
|
|
|
|
|
return 0; |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
# Get all records from DB |
599
|
|
|
|
|
|
|
my %all; |
600
|
|
|
|
|
|
|
foreach my $r ($dbi->getall) { |
601
|
|
|
|
|
|
|
$all{$r->{name}} = $r; |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
if ($dbi->error) { |
604
|
|
|
|
|
|
|
$self->log_error("%s: %s", $dbi->dsn, $dbi->error); |
605
|
|
|
|
|
|
|
$self->nope($dbi->dsn); |
606
|
|
|
|
|
|
|
say(TAB9, red($dbi->error)); |
607
|
|
|
|
|
|
|
return 0 |
608
|
|
|
|
|
|
|
} |
609
|
|
|
|
|
|
|
my $n = scalar(keys %all) || 0; |
610
|
|
|
|
|
|
|
unless ($n) { |
611
|
|
|
|
|
|
|
$self->skip("No data"); |
612
|
|
|
|
|
|
|
return 1; |
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
if ($self->verbosemode) { |
616
|
|
|
|
|
|
|
print(explain(\%all)); |
617
|
|
|
|
|
|
|
$self->yep("Number of records: %d", $n); |
618
|
|
|
|
|
|
|
return 1; |
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
# Show table |
622
|
|
|
|
|
|
|
eval <<'FORMATTING'; |
623
|
|
|
|
|
|
|
my @arr; |
624
|
|
|
|
|
|
|
my $total; |
625
|
|
|
|
|
|
|
say ""; |
626
|
|
|
|
|
|
|
say "Actual table data: |
627
|
|
|
|
|
|
|
----------------------+----------------------------------+---------------------+---------"; |
628
|
|
|
|
|
|
|
format STDOUT_TOP = |
629
|
|
|
|
|
|
|
Name | Source string | Date | Status |
630
|
|
|
|
|
|
|
----------------------+----------------------------------+---------------------+--------- |
631
|
|
|
|
|
|
|
. |
632
|
|
|
|
|
|
|
format STDOUT = |
633
|
|
|
|
|
|
|
@<<<<<<<<<<<<<<<<<<< | @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | @<<<<<<<<<<<<<<<<<< | @|||||| |
634
|
|
|
|
|
|
|
@arr |
635
|
|
|
|
|
|
|
. |
636
|
|
|
|
|
|
|
format STDOUTBOT = |
637
|
|
|
|
|
|
|
----------------------+----------------------------------+---------------------+--------- |
638
|
|
|
|
|
|
|
SUMMARY | @|||||| |
639
|
|
|
|
|
|
|
$total |
640
|
|
|
|
|
|
|
. |
641
|
|
|
|
|
|
|
foreach my $v (sort {$a->{name} cmp $b->{name}} values %all) { |
642
|
|
|
|
|
|
|
@arr = (); |
643
|
|
|
|
|
|
|
my $stv = $v->{status} || 0; |
644
|
|
|
|
|
|
|
my $ostat = -1; |
645
|
|
|
|
|
|
|
if (getBit($stv, 0) && getBit($stv, 1) && getBit($stv, 2)) { # Ok |
646
|
|
|
|
|
|
|
$ostat = 1; |
647
|
|
|
|
|
|
|
} elsif ((getBit($stv, 0) + getBit($stv, 1)) == 0) { # Problem |
648
|
|
|
|
|
|
|
$ostat = 0; |
649
|
|
|
|
|
|
|
$status = 0; |
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
push @arr, variant_stf($v->{name} // '', 20); |
652
|
|
|
|
|
|
|
push @arr, variant_stf($v->{source} // '', 32); |
653
|
|
|
|
|
|
|
push @arr, $v->{"time"} ? dtf(DATE_FORMAT, $v->{"time"}) : ''; |
654
|
|
|
|
|
|
|
push @arr, $ostat ? $ostat > 0 ? 'OK' : 'UNKNOWN' : 'PROBLEM'; |
655
|
|
|
|
|
|
|
write; |
656
|
|
|
|
|
|
|
} |
657
|
|
|
|
|
|
|
local $~ = "STDOUTBOT"; |
658
|
|
|
|
|
|
|
$total = $status ? "OK" : "PROBLEM"; |
659
|
|
|
|
|
|
|
write; |
660
|
|
|
|
|
|
|
FORMATTING |
661
|
|
|
|
|
|
|
say ""; |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
$self->yep("Number of records: %d", $n); |
664
|
|
|
|
|
|
|
return $status; |
665
|
|
|
|
|
|
|
}); |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
sub notify { |
668
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
669
|
0
|
|
|
|
|
|
my %args = @_; |
670
|
0
|
|
0
|
|
|
|
my $name = $args{name} || 'virtual'; |
671
|
0
|
|
|
|
|
|
my @errors; |
672
|
0
|
0
|
|
|
|
|
push @errors, $args{error} if $args{error}; |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
# Get SendMail config |
675
|
0
|
|
|
|
|
|
my $sendmail = hash($self->config('sendmail')); |
676
|
|
|
|
|
|
|
#say(explain($sendmail)); |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
# Get SMSGW |
679
|
0
|
|
|
|
|
|
my $smsgw = $self->config('smsgw'); |
680
|
|
|
|
|
|
|
#say(explain($sendmail)); |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
# |
683
|
|
|
|
|
|
|
# Sorting receivers |
684
|
|
|
|
|
|
|
# |
685
|
0
|
|
0
|
|
|
|
my $sendto = $args{sendto} || []; |
686
|
0
|
|
|
|
|
|
my (@for_sendmail, @for_smsgw, @for_notifier); |
687
|
0
|
|
|
|
|
|
foreach my $rec (@$sendto) { |
688
|
0
|
0
|
|
|
|
|
next unless $rec; |
689
|
0
|
0
|
|
|
|
|
if ($rec =~ /\@/) { push @for_sendmail, $rec } |
|
0
|
0
|
|
|
|
|
|
690
|
|
|
|
|
|
|
elsif ($rec =~ /^[\(+]*\d+/) { |
691
|
0
|
|
|
|
|
|
$rec =~ s/[^0-9]//g; |
692
|
0
|
|
|
|
|
|
push @for_smsgw, $rec; |
693
|
|
|
|
|
|
|
} |
694
|
0
|
|
|
|
|
|
else { push @for_notifier, $rec } |
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
# |
698
|
|
|
|
|
|
|
# Make subject and sms body |
699
|
|
|
|
|
|
|
# |
700
|
|
|
|
|
|
|
my $subject = sprintf("%s: Available %s [%s]", |
701
|
0
|
0
|
|
|
|
|
$args{status} ? 'OK' : 'PROBLEM', |
702
|
|
|
|
|
|
|
$name, |
703
|
|
|
|
|
|
|
HOSTNAME, |
704
|
|
|
|
|
|
|
); |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
# |
707
|
|
|
|
|
|
|
# Send SMS |
708
|
|
|
|
|
|
|
# |
709
|
0
|
|
|
|
|
|
foreach my $phone (@for_smsgw) { |
710
|
0
|
0
|
|
|
|
|
unless ($smsgw) { |
711
|
0
|
|
|
|
|
|
my $msg = sprintf("Can't send SMS to %s: SMSGW is not defined!", $phone); |
712
|
0
|
|
|
|
|
|
$self->skip($msg); |
713
|
0
|
|
|
|
|
|
$self->log_error($msg); |
714
|
0
|
|
|
|
|
|
push @errors, $msg; |
715
|
0
|
|
|
|
|
|
next; |
716
|
|
|
|
|
|
|
} |
717
|
0
|
|
|
|
|
|
my $cmd = dformat($smsgw, { |
718
|
|
|
|
|
|
|
PHONE => $phone, |
719
|
|
|
|
|
|
|
NUM => $phone, |
720
|
|
|
|
|
|
|
TEL => $phone, |
721
|
|
|
|
|
|
|
PHONE => $phone, |
722
|
|
|
|
|
|
|
NUM => $phone, |
723
|
|
|
|
|
|
|
NUMBER => $phone, |
724
|
|
|
|
|
|
|
SUBJECT => SMSSBJ, |
725
|
|
|
|
|
|
|
SUBJ => SMSSBJ, |
726
|
|
|
|
|
|
|
MSG => $subject, |
727
|
|
|
|
|
|
|
MESSAGE => $subject, |
728
|
|
|
|
|
|
|
}); |
729
|
0
|
|
|
|
|
|
my $exe_err = ''; |
730
|
0
|
|
|
|
|
|
my $exe_out = execute($cmd, undef, \$exe_err); |
731
|
0
|
0
|
|
|
|
|
my $exe_stt = ($? >> 8) ? 0 : 1; |
732
|
0
|
0
|
|
|
|
|
if ($exe_stt) { |
733
|
0
|
|
|
|
|
|
my $msg = sprintf("# %s", $cmd); |
734
|
0
|
|
|
|
|
|
$self->wow($msg); |
735
|
0
|
|
|
|
|
|
$self->log_info($msg); |
736
|
0
|
0
|
0
|
|
|
|
if (defined($exe_out) && length($exe_out) && $self->verbosemode) { |
|
|
|
0
|
|
|
|
|
737
|
0
|
|
|
|
|
|
say(TAB9, cyan($exe_out)) if IS_TTY; |
738
|
0
|
|
|
|
|
|
$self->log_info($exe_out); |
739
|
|
|
|
|
|
|
} |
740
|
|
|
|
|
|
|
} else { |
741
|
0
|
|
|
|
|
|
my $msg = sprintf("Can't send SMS: %s", $cmd); |
742
|
0
|
|
|
|
|
|
$self->skip($msg); |
743
|
0
|
|
|
|
|
|
$self->log_warning($msg); |
744
|
0
|
|
|
|
|
|
push @errors, $msg; |
745
|
0
|
0
|
|
|
|
|
if ($exe_err) { |
746
|
0
|
|
|
|
|
|
chomp($exe_err); |
747
|
0
|
|
|
|
|
|
IS_TTY ? say(TAB9, yellow($exe_err)) : say($exe_err); |
748
|
0
|
|
|
|
|
|
$self->log_error($exe_err); |
749
|
0
|
|
|
|
|
|
push @errors, $exe_err; |
750
|
|
|
|
|
|
|
} |
751
|
0
|
|
|
|
|
|
push @errors, ""; |
752
|
|
|
|
|
|
|
} |
753
|
|
|
|
|
|
|
} |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
# |
756
|
|
|
|
|
|
|
# Make headers |
757
|
|
|
|
|
|
|
# |
758
|
0
|
|
|
|
|
|
my @header; |
759
|
|
|
|
|
|
|
push @header, ( |
760
|
|
|
|
|
|
|
["Checkit", $name], |
761
|
|
|
|
|
|
|
["Type", $args{type} || 'http'], |
762
|
|
|
|
|
|
|
["Status", $args{status} ? 'OK' : 'PROBLEM'], |
763
|
|
|
|
|
|
|
["Source", $args{source} || "UNKNOWN"], |
764
|
0
|
0
|
0
|
|
|
|
["Message", $args{message} // ""], |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
765
|
|
|
|
|
|
|
); |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
# |
768
|
|
|
|
|
|
|
# Make email report message |
769
|
|
|
|
|
|
|
# |
770
|
0
|
|
|
|
|
|
my @report; |
771
|
0
|
0
|
|
|
|
|
my $report_name = $args{status} ? "checking report" : "error report"; |
772
|
0
|
|
|
|
|
|
push @report, $self->_report_common(@header); # Common information |
773
|
0
|
0
|
|
|
|
|
push @report, $self->_report_summary($args{status} ? "All checks successful" : "Errors occurred while checking"); # Summary table |
774
|
0
|
|
|
|
|
|
push @report, $self->_report_errors(@errors); # List of occurred errors |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
# Data for Emails only |
777
|
0
|
|
|
|
|
|
unshift @report, $self->_report_title($report_name, $name); |
778
|
0
|
|
|
|
|
|
push @report, $self->_report_footer(); |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
# |
781
|
|
|
|
|
|
|
# Send report to Notifier (if installed) |
782
|
|
|
|
|
|
|
# |
783
|
0
|
|
|
|
|
|
my $agent = $self->{notifier}; |
784
|
0
|
0
|
0
|
|
|
|
if ($NOTIFIER_LOADED && $agent && @for_notifier) { |
|
|
|
0
|
|
|
|
|
785
|
0
|
|
|
|
|
|
foreach my $to (shellwords(@for_notifier)) { |
786
|
|
|
|
|
|
|
$agent->create( |
787
|
|
|
|
|
|
|
to => $to, |
788
|
|
|
|
|
|
|
subject => $subject, |
789
|
|
|
|
|
|
|
message => join("\n", @report), |
790
|
0
|
0
|
|
|
|
|
) or do { |
791
|
0
|
|
|
|
|
|
my $msg = sprintf("Can't send message via notifier: %s", $agent->error); |
792
|
0
|
|
|
|
|
|
$self->skip($msg); |
793
|
0
|
|
|
|
|
|
$self->log_warning($msg); |
794
|
|
|
|
|
|
|
}; |
795
|
0
|
0
|
|
|
|
|
if ($agent->status) { |
796
|
0
|
|
|
|
|
|
my $msg = sprintf("The message has been successfully queued for sending to: %s", $to); |
797
|
0
|
|
|
|
|
|
$self->wow($msg); |
798
|
0
|
|
|
|
|
|
$self->log_info($msg); |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
} |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
# |
804
|
|
|
|
|
|
|
# SendMail (Send report) |
805
|
|
|
|
|
|
|
# |
806
|
0
|
|
|
|
|
|
my %ma = (); foreach my $k (keys %$sendmail) { $ma{"-".$k} = $sendmail->{$k} }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
807
|
0
|
|
|
|
|
|
$ma{"-subject"} = $subject; |
808
|
0
|
|
|
|
|
|
$ma{"-message"} = join("\n", @report); |
809
|
0
|
|
|
|
|
|
foreach my $to (@for_sendmail) { |
810
|
0
|
|
|
|
|
|
$ma{"-to"} = $to; |
811
|
0
|
0
|
|
|
|
|
my $sent = sendmail(%ma) if $to !~ /\@example.com$/; |
812
|
0
|
0
|
|
|
|
|
if ($sent) { |
813
|
0
|
|
|
|
|
|
my $msg = sprintf("Mail has been sent to: %s", $to); |
814
|
0
|
|
|
|
|
|
$self->wow($msg); |
815
|
0
|
|
|
|
|
|
$self->log_info($msg); |
816
|
|
|
|
|
|
|
} else { |
817
|
0
|
|
|
|
|
|
my $msg = sprintf("Mail was not sent to: %s", $to); |
818
|
0
|
|
|
|
|
|
$self->skip($msg); |
819
|
0
|
|
|
|
|
|
$self->log_warning($msg); |
820
|
|
|
|
|
|
|
} |
821
|
|
|
|
|
|
|
} |
822
|
|
|
|
|
|
|
|
823
|
0
|
|
|
|
|
|
return 1; |
824
|
|
|
|
|
|
|
} |
825
|
|
|
|
|
|
|
sub trigger { |
826
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
827
|
0
|
|
|
|
|
|
my %args = @_; |
828
|
0
|
|
0
|
|
|
|
my $name = $args{name} || 'virtual'; |
829
|
0
|
|
0
|
|
|
|
my $message = $args{message} || ""; |
830
|
0
|
|
0
|
|
|
|
my $source = $args{source} || ""; |
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
# |
833
|
|
|
|
|
|
|
# Make subject and sms body |
834
|
|
|
|
|
|
|
# |
835
|
|
|
|
|
|
|
my $subject = sprintf("%s: Available %s [%s]", |
836
|
0
|
0
|
|
|
|
|
$args{status} ? 'OK' : 'PROBLEM', |
837
|
|
|
|
|
|
|
$name, |
838
|
|
|
|
|
|
|
HOSTNAME, |
839
|
|
|
|
|
|
|
); |
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
# |
842
|
|
|
|
|
|
|
# Execute |
843
|
|
|
|
|
|
|
# |
844
|
0
|
|
0
|
|
|
|
my $triggers = $args{trigger} || []; |
845
|
0
|
|
|
|
|
|
foreach my $trg (@$triggers) { |
846
|
0
|
0
|
|
|
|
|
next unless $trg; |
847
|
|
|
|
|
|
|
my $cmd = dformat($trg, { |
848
|
|
|
|
|
|
|
SUBJECT => $subject, |
849
|
|
|
|
|
|
|
SUBJ => $subject, |
850
|
|
|
|
|
|
|
MSG => $message, |
851
|
|
|
|
|
|
|
MESSAGE => $message, |
852
|
|
|
|
|
|
|
SOURCE => $source, |
853
|
|
|
|
|
|
|
NAME => $name, |
854
|
|
|
|
|
|
|
TYPE => $args{type} || "http", |
855
|
0
|
0
|
0
|
|
|
|
STATUS => $args{status} ? 1 : 0, |
856
|
|
|
|
|
|
|
}); |
857
|
0
|
|
|
|
|
|
my $exe_err = ''; |
858
|
0
|
|
|
|
|
|
my $exe_out = execute($cmd, undef, \$exe_err); |
859
|
0
|
0
|
|
|
|
|
my $exe_stt = ($? >> 8) ? 0 : 1; |
860
|
0
|
0
|
|
|
|
|
if ($exe_stt) { |
861
|
0
|
|
|
|
|
|
my $msg = sprintf("# %s", $cmd); |
862
|
0
|
|
|
|
|
|
$self->yep($msg); |
863
|
0
|
|
|
|
|
|
$self->log_info($msg); |
864
|
0
|
0
|
0
|
|
|
|
if (defined($exe_out) && length($exe_out) && $self->verbosemode) { |
|
|
|
0
|
|
|
|
|
865
|
0
|
|
|
|
|
|
say(TAB9, green($exe_out)) if IS_TTY; |
866
|
0
|
|
|
|
|
|
$self->log_info($exe_out); |
867
|
|
|
|
|
|
|
} |
868
|
|
|
|
|
|
|
} else { |
869
|
0
|
|
|
|
|
|
my $msg = sprintf("Can't execute trigger: %s", $cmd); |
870
|
0
|
|
|
|
|
|
$self->nope($msg); |
871
|
0
|
|
|
|
|
|
$self->log_error($msg); |
872
|
0
|
0
|
|
|
|
|
if ($exe_err) { |
873
|
0
|
|
|
|
|
|
chomp($exe_err); |
874
|
0
|
|
|
|
|
|
IS_TTY ? say(TAB9, red($exe_err)) : say($exe_err); |
875
|
0
|
|
|
|
|
|
$self->log_error($exe_err); |
876
|
|
|
|
|
|
|
} |
877
|
|
|
|
|
|
|
} |
878
|
|
|
|
|
|
|
} |
879
|
|
|
|
|
|
|
|
880
|
0
|
|
|
|
|
|
return 1; |
881
|
|
|
|
|
|
|
} |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
####################### |
884
|
|
|
|
|
|
|
# Colored says methods |
885
|
|
|
|
|
|
|
####################### |
886
|
|
|
|
|
|
|
sub yep { |
887
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
888
|
0
|
|
|
|
|
|
print(IS_TTY ? green('[ OK ]') : '[ OK ]', ' ', IS_TTY ? green(shift, @_) : sprintf(shift, @_), "\n"); |
889
|
0
|
|
|
|
|
|
return 1; |
890
|
|
|
|
|
|
|
} |
891
|
|
|
|
|
|
|
sub nope { |
892
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
893
|
0
|
|
|
|
|
|
print(IS_TTY ? red('[ FAIL ]') : '[ FAIL ]', ' ', IS_TTY ? red(shift, @_) : sprintf(shift, @_), "\n"); |
894
|
0
|
|
|
|
|
|
return 0; |
895
|
|
|
|
|
|
|
} |
896
|
|
|
|
|
|
|
sub skip { |
897
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
898
|
0
|
|
|
|
|
|
print(IS_TTY ? yellow('[ SKIP ]') : '[ SKIP ]', ' ', IS_TTY ? yellow(shift, @_) : sprintf(shift, @_), "\n"); |
899
|
0
|
|
|
|
|
|
return 1; |
900
|
|
|
|
|
|
|
} |
901
|
|
|
|
|
|
|
sub wow { |
902
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
903
|
0
|
|
|
|
|
|
print(IS_TTY ? blue('[ INFO ]') : '[ INFO ]', ' ', IS_TTY ? blue(shift, @_) : sprintf(shift, @_), "\n"); |
904
|
0
|
|
|
|
|
|
return 1; |
905
|
|
|
|
|
|
|
} |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
# Private methods |
908
|
|
|
|
|
|
|
sub _getCheckits { |
909
|
0
|
|
|
0
|
|
|
my $self = shift; |
910
|
0
|
|
|
|
|
|
my @names = @_; |
911
|
0
|
|
|
|
|
|
my $sects = $self->config("checkit"); |
912
|
0
|
|
|
|
|
|
my $i = 0; |
913
|
0
|
|
|
|
|
|
my @j = (); |
914
|
0
|
0
|
0
|
|
|
|
if (ref($sects) eq 'ARRAY') { # Array |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
915
|
0
|
|
|
|
|
|
foreach my $r (@$sects) { |
916
|
0
|
0
|
0
|
|
|
|
if ((ref($r) eq 'HASH') && exists $r->{enable}) { # Anonymous |
|
|
0
|
|
|
|
|
|
917
|
0
|
|
|
|
|
|
$r->{name} = sprintf("virtual%d", ++$i); |
918
|
0
|
0
|
0
|
|
|
|
next unless (!@names || grep {$r->{name} eq lc($_)} @names); |
|
0
|
|
|
|
|
|
|
919
|
0
|
|
|
|
|
|
push @j, $r; |
920
|
|
|
|
|
|
|
} elsif (ref($r) eq 'HASH') { # Named |
921
|
0
|
|
|
|
|
|
foreach my $k (keys %$r) { |
922
|
0
|
|
|
|
|
|
my $v = $r->{$k}; |
923
|
0
|
0
|
|
|
|
|
next unless ref($v) eq 'HASH'; |
924
|
0
|
|
|
|
|
|
$v->{name} = lc($k); |
925
|
0
|
0
|
0
|
|
|
|
next unless (!@names || grep {$v->{name} eq lc($_)} @names); |
|
0
|
|
|
|
|
|
|
926
|
0
|
|
|
|
|
|
push @j, $v; |
927
|
|
|
|
|
|
|
} |
928
|
|
|
|
|
|
|
} |
929
|
|
|
|
|
|
|
} |
930
|
|
|
|
|
|
|
} elsif ((ref($sects) eq 'HASH') && !exists $sects->{enable}) { # Hash {name => {...}} |
931
|
0
|
|
|
|
|
|
foreach my $k (keys %$sects) { |
932
|
0
|
|
|
|
|
|
my $v = $sects->{$k}; |
933
|
0
|
0
|
|
|
|
|
next unless ref($v) eq 'HASH'; |
934
|
0
|
|
|
|
|
|
$v->{name} = lc($k); |
935
|
0
|
0
|
0
|
|
|
|
next unless (!@names || grep {$v->{name} eq lc($_)} @names); |
|
0
|
|
|
|
|
|
|
936
|
0
|
|
|
|
|
|
push @j, $v; |
937
|
|
|
|
|
|
|
} |
938
|
|
|
|
|
|
|
} elsif (ref($sects) eq 'HASH') { # Hash {...} |
939
|
0
|
|
|
|
|
|
$sects->{name} = sprintf("virtual%d", ++$i); |
940
|
0
|
0
|
0
|
|
|
|
push @j, $sects if (!@names || grep {$sects->{name} eq lc($_)} @names); |
|
0
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
} |
942
|
0
|
|
|
|
|
|
return grep {$_->{enable}} @j; |
|
0
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
} |
944
|
|
|
|
|
|
|
sub _report_title { |
945
|
0
|
|
|
0
|
|
|
my $self = shift; |
946
|
0
|
|
0
|
|
|
|
my $title = shift || "report"; |
947
|
0
|
|
0
|
|
|
|
my $name = shift || "virtual"; |
948
|
|
|
|
|
|
|
return ( |
949
|
0
|
|
|
|
|
|
sprintf("Dear %s user,", PROJECTNAME),"", |
950
|
|
|
|
|
|
|
sprintf("This is a automatic-generated %s for %s\non %s, created by %s/%s", |
951
|
|
|
|
|
|
|
$title, $name, HOSTNAME, __PACKAGE__, $VERSION),"", |
952
|
|
|
|
|
|
|
"Sections of this report:","", |
953
|
|
|
|
|
|
|
" * Common information", |
954
|
|
|
|
|
|
|
" * Summary", |
955
|
|
|
|
|
|
|
" * List of occurred errors","", |
956
|
|
|
|
|
|
|
); |
957
|
|
|
|
|
|
|
} |
958
|
|
|
|
|
|
|
sub _report_common { |
959
|
0
|
|
|
0
|
|
|
my $self = shift; |
960
|
0
|
|
|
|
|
|
my @hdr = @_; |
961
|
0
|
|
|
|
|
|
my @rep = ( |
962
|
|
|
|
|
|
|
"-"x32, |
963
|
|
|
|
|
|
|
"COMMON INFORMATION", |
964
|
|
|
|
|
|
|
"-"x32,"", |
965
|
|
|
|
|
|
|
); |
966
|
0
|
|
|
|
|
|
my $maxlen = 0; |
967
|
0
|
|
|
|
|
|
foreach my $r (@hdr) { |
968
|
0
|
0
|
|
|
|
|
$maxlen = length($r->[0]) if $maxlen < length($r->[0]) |
969
|
|
|
|
|
|
|
} |
970
|
0
|
|
|
|
|
|
foreach my $r (@hdr) { |
971
|
0
|
|
|
|
|
|
push @rep, sprintf("%s %s: %s", $r->[0], " "x($maxlen-length($r->[0])), $r->[1]); |
972
|
|
|
|
|
|
|
} |
973
|
0
|
|
|
|
|
|
push @rep, ""; |
974
|
0
|
|
|
|
|
|
return (@rep); |
975
|
|
|
|
|
|
|
} |
976
|
|
|
|
|
|
|
sub _report_summary { |
977
|
0
|
|
|
0
|
|
|
my $self = shift; |
978
|
0
|
|
0
|
|
|
|
my $summary = shift || "Ok"; |
979
|
0
|
|
|
|
|
|
my @rep = ( |
980
|
|
|
|
|
|
|
"-"x32, |
981
|
|
|
|
|
|
|
"SUMMARY", |
982
|
|
|
|
|
|
|
"-"x32,"", |
983
|
|
|
|
|
|
|
); |
984
|
0
|
|
|
|
|
|
push @rep, $summary, ""; |
985
|
0
|
|
|
|
|
|
return (@rep); |
986
|
|
|
|
|
|
|
} |
987
|
|
|
|
|
|
|
sub _report_errors { |
988
|
0
|
|
|
0
|
|
|
my $self = shift; |
989
|
0
|
|
|
|
|
|
my @errs = @_; |
990
|
0
|
|
|
|
|
|
my @rep = ( |
991
|
|
|
|
|
|
|
"-"x32, |
992
|
|
|
|
|
|
|
"LIST OF OCCURRED ERRORS", |
993
|
|
|
|
|
|
|
"-"x32,"", |
994
|
|
|
|
|
|
|
); |
995
|
0
|
0
|
|
|
|
|
if (@errs) { |
996
|
0
|
|
|
|
|
|
push @rep, @errs; |
997
|
|
|
|
|
|
|
} else { |
998
|
0
|
|
|
|
|
|
push @rep, "No errors occurred"; |
999
|
|
|
|
|
|
|
} |
1000
|
0
|
|
|
|
|
|
return (@rep, ""); |
1001
|
|
|
|
|
|
|
} |
1002
|
|
|
|
|
|
|
sub _report_footer { |
1003
|
0
|
|
|
0
|
|
|
my $self = shift; |
1004
|
0
|
|
|
|
|
|
return sprintf(join("\n", |
1005
|
|
|
|
|
|
|
"", |
1006
|
|
|
|
|
|
|
"---", |
1007
|
|
|
|
|
|
|
"Hostname : %s", |
1008
|
|
|
|
|
|
|
"Program : %s (%s, Perl %s)", |
1009
|
|
|
|
|
|
|
"Version : %s/%s", |
1010
|
|
|
|
|
|
|
"Config file : %s", |
1011
|
|
|
|
|
|
|
"PID : %d", |
1012
|
|
|
|
|
|
|
"Work time : %s", |
1013
|
|
|
|
|
|
|
"Generated : %s" |
1014
|
|
|
|
|
|
|
), |
1015
|
|
|
|
|
|
|
HOSTNAME, $0, $^O, $^V, PROJECTNAME, $VERSION, $self->configfile(), |
1016
|
|
|
|
|
|
|
$$, $self->tms(), dtf("%w, %DD %MON %YYYY %hh:%mm:%ss"), |
1017
|
|
|
|
|
|
|
); |
1018
|
|
|
|
|
|
|
} |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
1; |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
__END__ |