line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Nagios::Report; |
2
|
|
|
|
|
|
|
|
3
|
11
|
|
|
11
|
|
84734
|
use strict; |
|
11
|
|
|
|
|
25
|
|
|
11
|
|
|
|
|
470
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
# $Id: Report.pm,v 1.87 2006-08-23 14:26:17+10 sh1517 Exp sh1517 $ |
6
|
|
|
|
|
|
|
|
7
|
11
|
|
|
11
|
|
67
|
use base 'Exporter' ; |
|
11
|
|
|
|
|
63
|
|
|
11
|
|
|
|
|
1760
|
|
8
|
11
|
|
|
11
|
|
12282
|
use Time::Local ; |
|
11
|
|
|
|
|
21782
|
|
|
11
|
|
|
|
|
853
|
|
9
|
|
|
|
|
|
|
# use POSIX qw(mktime) ; |
10
|
|
|
|
|
|
|
|
11
|
11
|
|
|
11
|
|
73
|
use vars qw($VERSION @EXPORT @EXPORT_OK %stime_etime); |
|
11
|
|
|
|
|
23
|
|
|
11
|
|
|
|
|
1514
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
*t2hms = \&time2ddhhmmss ; |
14
|
|
|
|
|
|
|
*d2t = \&date2time ; |
15
|
|
|
|
|
|
|
*i2t = \&interval2time ; |
16
|
|
|
|
|
|
|
*st_et = \%stime_etime ; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
@EXPORT = qw(d2t t2hms comp max_l %st_et i2t) ; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
$VERSION = '0.003'; |
21
|
|
|
|
|
|
|
|
22
|
11
|
|
|
11
|
|
58
|
use constant REQUEST_METHOD => 'GET' ; |
|
11
|
|
|
|
|
31
|
|
|
11
|
|
|
|
|
523
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# Will be hacked by Makefile.PL |
25
|
|
|
|
|
|
|
|
26
|
11
|
|
|
11
|
|
54
|
use constant CGI_PATH => '' ; |
|
11
|
|
|
|
|
18
|
|
|
11
|
|
|
|
|
431
|
|
27
|
11
|
|
|
11
|
|
51
|
use constant LYNX => '' ; |
|
11
|
|
|
|
|
19
|
|
|
11
|
|
|
|
|
502
|
|
28
|
11
|
|
|
11
|
|
52
|
use constant WGET => '/usr/bin/wget' ; |
|
11
|
|
|
|
|
20
|
|
|
11
|
|
|
|
|
548
|
|
29
|
|
|
|
|
|
|
# EURO_DATE => \d\d?-\d\d?-\d\d\d\d |
30
|
|
|
|
|
|
|
# will be interpreted as DD-MM-YYYY |
31
|
11
|
|
|
11
|
|
52
|
use constant EURO_DATE => 1 ; |
|
11
|
|
|
|
|
18
|
|
|
11
|
|
|
|
|
704
|
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# End scope of expected changes by Makefile.PL |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# NB. I choose lynx etc over LWP because |
36
|
|
|
|
|
|
|
# LWP is a big module (LWP::Simple doesn't |
37
|
|
|
|
|
|
|
# fetch protected pages). |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
|
40
|
11
|
|
|
11
|
|
142
|
use constant NAG_AVAIL_CGI => CGI_PATH . 'avail.cgi' ; |
|
11
|
|
|
|
|
23
|
|
|
11
|
|
|
|
|
889
|
|
41
|
11
|
|
|
11
|
|
52
|
use constant WEB_PAGE => !! (LYNX || WGET) ; |
|
11
|
|
|
|
|
16
|
|
|
11
|
|
|
|
|
544
|
|
42
|
11
|
|
|
11
|
|
54
|
use constant LOCAL_CGI => !! CGI_PATH ; |
|
11
|
|
|
|
|
18
|
|
|
11
|
|
|
|
|
808
|
|
43
|
11
|
|
|
11
|
|
56
|
use constant USE_LYNX => !! (WEB_PAGE && LYNX) ; |
|
11
|
|
|
|
|
21
|
|
|
11
|
|
|
|
|
450
|
|
44
|
|
|
|
|
|
|
|
45
|
11
|
|
|
11
|
|
59
|
use constant EXCEL_FILENAME => './Nagios_Avail.xls' ; |
|
11
|
|
|
|
|
14
|
|
|
11
|
|
|
|
|
531
|
|
46
|
|
|
|
|
|
|
|
47
|
11
|
|
|
|
|
462
|
use constant QS_TEMP_HOSTREP => |
48
|
11
|
|
|
11
|
|
51
|
q(show_log_entries=&host=all&t1=T1&t2=T2&rpttimeperiod=REPORT_PERIOD&assumeinitialstates=yes&assumestateretention=yes&assumestatesduringnotrunning=yes&includesoftstates=no&initialassumedhoststate=3&initialassumedservicestate=6&backtrack=0&csvoutput) ; |
|
11
|
|
|
|
|
17
|
|
49
|
|
|
|
|
|
|
|
50
|
11
|
|
|
|
|
436
|
use constant QS_TEMP_SVCREP => |
51
|
11
|
|
|
11
|
|
49
|
q(show_log_entries=&host=FOO&service=all&t1=T1&t2=T2&rpttimeperiod=REPORT_PERIOD&assumeinitialstates=yes&assumestateretention=yes&assumestatesduringnotrunning=yes&includesoftstates=no&initialassumedservicestate=6&backtrack=0&csvoutput=) ; |
|
11
|
|
|
|
|
18
|
|
52
|
|
|
|
|
|
|
|
53
|
11
|
|
|
|
|
463
|
use constant AVAIL_URL_TEMP_HOST => |
54
|
11
|
|
|
11
|
|
48
|
q(http://SERVER/nagios/cgi-bin/avail.cgi?host=HOST&t1=T1&t2=T2&show_log_entries=&assumeinitialstates=yes&assumestateretention=yes&includesoftstates=no&backtrack=0) ; |
|
11
|
|
|
|
|
19
|
|
55
|
|
|
|
|
|
|
|
56
|
11
|
|
|
|
|
515
|
use constant TREND_URL_TEMP_HOST => |
57
|
11
|
|
|
11
|
|
53
|
q(http://SERVER/nagios/cgi-bin/trends.cgi?host=HOST&t1=T1&t2=T2&assumeinitialstates=yes&assumestateretention=yes&includesoftstates=no) ; |
|
11
|
|
|
|
|
30
|
|
58
|
|
|
|
|
|
|
|
59
|
11
|
|
|
|
|
566
|
use constant AVAIL_URL_TEMP_SVC => |
60
|
11
|
|
|
11
|
|
57
|
q(http://SERVER/nagios/cgi-bin/avail.cgi?host=HOST&service=SVC&t1=T1&t2=T2&show_log_entries=&assumeinitialstates=yes&assumestateretention=yes&includesoftstates=no&assumestatesduringnotrunning=yes&backtrack=0&initialassumedservicestate=6) ; |
|
11
|
|
|
|
|
17
|
|
61
|
|
|
|
|
|
|
|
62
|
11
|
|
|
|
|
739
|
use constant TREND_URL_TEMP_SVC => |
63
|
11
|
|
|
11
|
|
50
|
q(http://SERVER/nagios/cgi-bin/trends.cgi?host=HOST&service=SVC&t1=T1&t2=T2&assumeinitialstates=yes&assumestatesduringnotrunning=yes&initialassumedhoststate=0&initialassumedservicestate=0&assumestateretention=yes&includesoftstates=no) ; |
|
11
|
|
|
|
|
21
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
use constant { |
66
|
11
|
|
|
|
|
1694
|
SEC => 0, |
67
|
|
|
|
|
|
|
MIN => 1, |
68
|
|
|
|
|
|
|
HOUR => 2, |
69
|
|
|
|
|
|
|
MDAY => 3, |
70
|
|
|
|
|
|
|
MON => 4, |
71
|
|
|
|
|
|
|
YEAR => 5, |
72
|
|
|
|
|
|
|
WDAY => 6, |
73
|
|
|
|
|
|
|
YDAY => 7, |
74
|
|
|
|
|
|
|
ISDST => 8, |
75
|
11
|
|
|
11
|
|
53
|
}; |
|
11
|
|
|
|
|
17
|
|
76
|
|
|
|
|
|
|
|
77
|
11
|
|
|
|
|
1022
|
use constant MONTH => { |
78
|
|
|
|
|
|
|
Jan => 0, |
79
|
|
|
|
|
|
|
Feb => 1, |
80
|
|
|
|
|
|
|
Mar => 2, |
81
|
|
|
|
|
|
|
Apr => 3, |
82
|
|
|
|
|
|
|
May => 4, |
83
|
|
|
|
|
|
|
Jun => 5, |
84
|
|
|
|
|
|
|
Jul => 6, |
85
|
|
|
|
|
|
|
Aug => 7, |
86
|
|
|
|
|
|
|
Sep => 8, |
87
|
|
|
|
|
|
|
Oct => 9, |
88
|
|
|
|
|
|
|
Nov => 10, |
89
|
|
|
|
|
|
|
Dec => 11, |
90
|
11
|
|
|
11
|
|
58
|
} ; |
|
11
|
|
|
|
|
54
|
|
91
|
|
|
|
|
|
|
|
92
|
11
|
|
|
11
|
|
53
|
use constant T => { w => 7*86_400, d => 86_400, h => 60*60, m => 60, s => 1 } ; |
|
11
|
|
|
|
|
19
|
|
|
11
|
|
|
|
|
26391
|
|
93
|
|
|
|
|
|
|
|
94
|
0
|
|
|
0
|
0
|
0
|
sub Iterator (&) { $_[0] } ; |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
my %default_sort = ( |
97
|
|
|
|
|
|
|
alpha => 1, # 0 implies numeric |
98
|
|
|
|
|
|
|
ascend => 1, |
99
|
|
|
|
|
|
|
fields => [ qw(HOST_NAME) ], |
100
|
|
|
|
|
|
|
) ; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
%stime_etime = ( |
103
|
|
|
|
|
|
|
last12hours => sub { my $t = defined($_[1]) ? timelocal(@{$_[1]}) : time(); ( $t - 12 * 3_600, $t) }, |
104
|
|
|
|
|
|
|
last24hours => sub { my $t = defined($_[1]) ? timelocal(@{$_[1]}) : time(); ( $t - 1 * 86_400, $t) }, |
105
|
|
|
|
|
|
|
last7days => sub { my $t = defined($_[1]) ? timelocal(@{$_[1]}) : time(); ( $t - 7 * 86_400, $t) }, |
106
|
|
|
|
|
|
|
last31days => sub { my $t = defined($_[1]) ? timelocal(@{$_[1]}) : time(); ( $t - 31 * 86_400, $t) }, |
107
|
|
|
|
|
|
|
today => sub { |
108
|
|
|
|
|
|
|
$_[1] ||= [localtime]; |
109
|
|
|
|
|
|
|
my $t = timelocal( @{$_[1]} ); |
110
|
|
|
|
|
|
|
#( mktime(0, 0, 0, $_[1]->[MDAY], $_[1]->[MON], $_[1]->[YEAR]), |
111
|
|
|
|
|
|
|
( |
112
|
|
|
|
|
|
|
$t - ( $_[1]->[SEC] + 60 *( $_[1]->[MIN] + 60*$_[1]->[HOUR] ) ), |
113
|
|
|
|
|
|
|
$t |
114
|
|
|
|
|
|
|
) |
115
|
|
|
|
|
|
|
}, |
116
|
|
|
|
|
|
|
yesterday => sub { |
117
|
|
|
|
|
|
|
$_[1] ||= [localtime] ; |
118
|
|
|
|
|
|
|
my $midnight = timelocal( @{$_[1]} ) - ( $_[1]->[SEC] + 60 *( $_[1]->[MIN] + 60*$_[1]->[HOUR] ) ) ; |
119
|
|
|
|
|
|
|
( |
120
|
|
|
|
|
|
|
$midnight - 86_400, |
121
|
|
|
|
|
|
|
$midnight |
122
|
|
|
|
|
|
|
) |
123
|
|
|
|
|
|
|
}, |
124
|
|
|
|
|
|
|
last_n_mins => sub { |
125
|
|
|
|
|
|
|
$_[1] ||= [localtime] ; |
126
|
|
|
|
|
|
|
my ($mins, $t_ar) = @_ ; |
127
|
|
|
|
|
|
|
my $t = timelocal( @$t_ar ) ; |
128
|
|
|
|
|
|
|
( |
129
|
|
|
|
|
|
|
$t - $mins * 60, |
130
|
|
|
|
|
|
|
$t |
131
|
|
|
|
|
|
|
) |
132
|
|
|
|
|
|
|
}, |
133
|
|
|
|
|
|
|
last_n_hours => sub { |
134
|
|
|
|
|
|
|
$_[1] ||= [localtime] ; |
135
|
|
|
|
|
|
|
my ($hours, $t_ar) = @_ ; |
136
|
|
|
|
|
|
|
my $t = timelocal(@$t_ar) ; |
137
|
|
|
|
|
|
|
( |
138
|
|
|
|
|
|
|
$t - $hours * 3_600, |
139
|
|
|
|
|
|
|
$t |
140
|
|
|
|
|
|
|
) |
141
|
|
|
|
|
|
|
}, |
142
|
|
|
|
|
|
|
last_n_days => sub { |
143
|
|
|
|
|
|
|
$_[1] ||= [localtime] ; |
144
|
|
|
|
|
|
|
my ($days, $t_ar) = @_ ; |
145
|
|
|
|
|
|
|
my $t = timelocal(@$t_ar ) ; |
146
|
|
|
|
|
|
|
# XXX Fails for days > 120. |
147
|
|
|
|
|
|
|
( |
148
|
|
|
|
|
|
|
$t - $days * 86_400, |
149
|
|
|
|
|
|
|
$t, |
150
|
|
|
|
|
|
|
) |
151
|
|
|
|
|
|
|
}, |
152
|
|
|
|
|
|
|
thisweek => sub { |
153
|
|
|
|
|
|
|
# thisweek is wrt to MONDAY. |
154
|
|
|
|
|
|
|
$_[1] ||= [localtime] ; |
155
|
|
|
|
|
|
|
my $t = timelocal( @{$_[1]} ) ; |
156
|
|
|
|
|
|
|
( |
157
|
|
|
|
|
|
|
$t - ( $_[1]->[SEC] + 60*($_[1]->[MIN] + 60*$_[1]->[HOUR]) + ($_[1]->[WDAY] - 1)*86_400 ), |
158
|
|
|
|
|
|
|
$t |
159
|
|
|
|
|
|
|
) |
160
|
|
|
|
|
|
|
}, |
161
|
|
|
|
|
|
|
lastweek => sub { |
162
|
|
|
|
|
|
|
$_[1] ||= [localtime] ; |
163
|
|
|
|
|
|
|
my $sweek = |
164
|
|
|
|
|
|
|
timelocal( @{$_[1]} ) - ( $_[1]->[SEC] + 60*($_[1]->[MIN] + 60*$_[1]->[HOUR]) + ($_[1]->[WDAY]-1)*86_400 ) ; |
165
|
|
|
|
|
|
|
( |
166
|
|
|
|
|
|
|
$sweek - 7 * 86_400, |
167
|
|
|
|
|
|
|
$sweek - 1 |
168
|
|
|
|
|
|
|
) |
169
|
|
|
|
|
|
|
}, |
170
|
|
|
|
|
|
|
thismonth => sub { |
171
|
|
|
|
|
|
|
$_[1] ||= [localtime] ; |
172
|
|
|
|
|
|
|
( |
173
|
|
|
|
|
|
|
timelocal( 0, 0, 0, 1, $_[1]->[MON], $_[1]->[YEAR] ), |
174
|
|
|
|
|
|
|
timelocal( @{$_[1]} ) |
175
|
|
|
|
|
|
|
) |
176
|
|
|
|
|
|
|
}, |
177
|
|
|
|
|
|
|
lastmonth => sub { |
178
|
|
|
|
|
|
|
$_[1] ||= [localtime] ; |
179
|
|
|
|
|
|
|
my ($m, $y) = @{$_[1]}[MON, YEAR] ; |
180
|
|
|
|
|
|
|
( |
181
|
|
|
|
|
|
|
timelocal( 0, 0, 0, 1, ($m - 1) % 12, $y - ($m == 0), ), |
182
|
|
|
|
|
|
|
timelocal( 0, 0, 0, 1, $m , $y ) - 1 |
183
|
|
|
|
|
|
|
) |
184
|
|
|
|
|
|
|
}, |
185
|
|
|
|
|
|
|
thisyear => sub { |
186
|
|
|
|
|
|
|
$_[1] ||= [localtime] ; |
187
|
|
|
|
|
|
|
( |
188
|
|
|
|
|
|
|
timelocal( 0, 0, 0, 1, 0, $_[1]->[YEAR]), |
189
|
|
|
|
|
|
|
timelocal( @{$_[1]} ) |
190
|
|
|
|
|
|
|
) |
191
|
|
|
|
|
|
|
}, |
192
|
|
|
|
|
|
|
lastyear => sub { |
193
|
|
|
|
|
|
|
$_[1] ||= [localtime] ; |
194
|
|
|
|
|
|
|
( timelocal( 0, 0, 0, 1, 0, $_[1]->[YEAR] - 1 ), |
195
|
|
|
|
|
|
|
timelocal( 0, 0, 0, 1, 0, $_[1]->[YEAR] ) -1 |
196
|
|
|
|
|
|
|
) |
197
|
|
|
|
|
|
|
}, |
198
|
|
|
|
|
|
|
__DEFAULT__ => sub { |
199
|
|
|
|
|
|
|
# The 'tag' or the name of the interval supplied to the constructor |
200
|
|
|
|
|
|
|
# The tag describes the interval either absolutely (eg DD.MM.YY) or |
201
|
|
|
|
|
|
|
# wrt to the second arg (the right edge of the interval). |
202
|
|
|
|
|
|
|
local $_= shift @_ ; |
203
|
|
|
|
|
|
|
# Usually this arg is the upper bound of the interval. |
204
|
|
|
|
|
|
|
# Most often it is [localtime]. |
205
|
|
|
|
|
|
|
my $t = @_ ? shift @_ : [localtime] ; |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
my @t = @$t ; |
208
|
|
|
|
|
|
|
my ($t1, $t2) = |
209
|
|
|
|
|
|
|
/^ last(\d+)day /x ? $stime_etime{last_n_days}->( $1, $t ) : |
210
|
|
|
|
|
|
|
/^ last(\d+)hour /x ? $stime_etime{last_n_hours}->( $1, $t ) : |
211
|
|
|
|
|
|
|
/^ last(\d+)min /x ? $stime_etime{last_n_mins}->( $1, $t ) : |
212
|
|
|
|
|
|
|
# Define a time period with a string like so |
213
|
|
|
|
|
|
|
# time: HHMM | HH:MM => from that time today to now |
214
|
|
|
|
|
|
|
# date: DD.MM.YY | DD.MM.YYYY | MM/DD/YYYY | MM/DD/YY |
215
|
|
|
|
|
|
|
# => midnight on that day to now |
216
|
|
|
|
|
|
|
# time date => that time on that day to now |
217
|
|
|
|
|
|
|
# The time and date formats are inspired by the at command. |
218
|
|
|
|
|
|
|
/^ (\d\d) :? (\d\d) $/x |
219
|
|
|
|
|
|
|
? do { # HHMM | HH:MM |
220
|
|
|
|
|
|
|
@t[SEC, MIN, HOUR] = |
221
|
|
|
|
|
|
|
(0, $2, $1 ) ; |
222
|
|
|
|
|
|
|
( timelocal(@t), timelocal(@$t) ) ; |
223
|
|
|
|
|
|
|
} : |
224
|
|
|
|
|
|
|
m{^ (\d\d?) [\./] (\d\d?) [\./] ( \d\d (?:\d\d)? ) $}x |
225
|
|
|
|
|
|
|
? do { # DD.MM.YY(YY)? | MM/DD/YY(YY)? |
226
|
|
|
|
|
|
|
my ($dd, $mm, $yy) = ($1, $2, $3) ; |
227
|
|
|
|
|
|
|
($mm, $dd) = ($dd, $mm) |
228
|
|
|
|
|
|
|
if m{/} ; |
229
|
|
|
|
|
|
|
@t[SEC, MIN, HOUR, MDAY, MON, YEAR] = |
230
|
|
|
|
|
|
|
(0, 0, 0, $dd, $mm - 1, $yy ) ; |
231
|
|
|
|
|
|
|
( timelocal(@t), timelocal(@$t) ) ; |
232
|
|
|
|
|
|
|
} : |
233
|
|
|
|
|
|
|
m{^ (\d\d) :? (\d\d) \s+ (\d\d?) [\./] (\d\d?) [\./] ( \d\d (?:\d\d)? ) $ }x |
234
|
|
|
|
|
|
|
? do { # HHMM | HH:MM DD.MM.YY(YY)? | MM/DD/YY(YY)? |
235
|
|
|
|
|
|
|
my ($h, $m, $dd, $mm, $yy) = ($1, $2, $3, $4, $5) ; |
236
|
|
|
|
|
|
|
($mm, $dd) = ($dd, $mm) |
237
|
|
|
|
|
|
|
if m{/} ; |
238
|
|
|
|
|
|
|
@t[SEC, MIN, HOUR, MDAY, MON, YEAR] = |
239
|
|
|
|
|
|
|
(0, $m, $h, $dd, $mm - 1, $yy ) ; |
240
|
|
|
|
|
|
|
( timelocal(@t), timelocal(@$t) ) ; |
241
|
|
|
|
|
|
|
} : |
242
|
|
|
|
|
|
|
m{^ (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \s* (\d{4})? }ix |
243
|
|
|
|
|
|
|
? do { |
244
|
|
|
|
|
|
|
# I'd like to be able to use 'Mar-2006' here but I can't because |
245
|
|
|
|
|
|
|
# the constructor will recognise date ranges (intervals) as strings |
246
|
|
|
|
|
|
|
# containing '-'. |
247
|
|
|
|
|
|
|
my ($mm, $yy, @t1, @t2) ; |
248
|
|
|
|
|
|
|
$mm = MONTH->{"\u$1"} ; |
249
|
|
|
|
|
|
|
$yy = $2 || $t[YEAR] ; |
250
|
|
|
|
|
|
|
@t1[SEC, MIN, HOUR, MDAY, MON, YEAR] = |
251
|
|
|
|
|
|
|
(0, 0, 0, 1, $mm, $yy ) ; |
252
|
|
|
|
|
|
|
@t2[SEC, MIN, HOUR, MDAY, MON, YEAR] = |
253
|
|
|
|
|
|
|
(0, 0, 0, 1, ($mm + 1) % 12, $yy + ($mm == 11) ) ; |
254
|
|
|
|
|
|
|
( timelocal(@t1), timelocal(@t2) - 1 ) ; |
255
|
|
|
|
|
|
|
} : |
256
|
|
|
|
|
|
|
(999_999, 999_999) ; |
257
|
|
|
|
|
|
|
die "\%stime_etime: non existent tag '$_' - no handler defined for this tag. Outahere." |
258
|
|
|
|
|
|
|
if $t1 == 999_999 && $t2 == 999_999 ; |
259
|
|
|
|
|
|
|
return ($t1, $t2) ; |
260
|
|
|
|
|
|
|
}, |
261
|
|
|
|
|
|
|
) ; |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
my %data_source = ( |
264
|
|
|
|
|
|
|
# All these subroutines return a code reference |
265
|
|
|
|
|
|
|
# (a closure encapsulating auth data) that actually gets the data. |
266
|
|
|
|
|
|
|
web_page => WEB_PAGE ? \&gen_web_page : |
267
|
|
|
|
|
|
|
sub { die 'No CLI web browser (lynx or wget) found. Use local_cgi or report bug' }, |
268
|
|
|
|
|
|
|
local_cgi => LOCAL_CGI ? \&gen_local_cgi : |
269
|
|
|
|
|
|
|
sub { die 'Nagios availability CGI not found on this host. Use web_page or report bug' }, |
270
|
|
|
|
|
|
|
# Return a ref to the subroutine in main:: (the client code) |
271
|
|
|
|
|
|
|
# that will return the CSV data. |
272
|
|
|
|
|
|
|
dev_debug => sub { |
273
|
|
|
|
|
|
|
die "dev_debug source tag must be followed by the name of a callback in main::." |
274
|
|
|
|
|
|
|
unless $_[0] ; |
275
|
11
|
|
|
11
|
|
89
|
no strict 'refs' ; |
|
11
|
|
|
|
|
25
|
|
|
11
|
|
|
|
|
17476
|
|
276
|
|
|
|
|
|
|
my $cb = 'main::' . $_[0] ; |
277
|
|
|
|
|
|
|
return \&$cb ; |
278
|
|
|
|
|
|
|
}, |
279
|
|
|
|
|
|
|
__DEFAULT__ => sub { die "Outahere: bad source tag '$_[0]'" }, |
280
|
|
|
|
|
|
|
) ; |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
sub new { |
283
|
|
|
|
|
|
|
|
284
|
5
|
|
|
5
|
1
|
8867
|
my ($class, $source_tag, $rpt_period, $tme_period, $rep_type, $pre_filter) = @_ ; |
285
|
|
|
|
|
|
|
|
286
|
5
|
50
|
|
|
|
29
|
my @report_period = $rpt_period ? @$rpt_period : qw(24x7) ; |
287
|
5
|
50
|
|
|
|
21
|
my $time_period = $tme_period ? $tme_period : q(thismonth) ; |
288
|
5
|
50
|
|
|
|
17
|
my $report_type = $rep_type ? q(service) : q(host) ; |
289
|
|
|
|
|
|
|
|
290
|
5
|
50
|
33
|
|
|
34
|
die 'new() called with a pre_filter parm that is _not_ a code ref. Caller ' . join(' ', caller) |
291
|
|
|
|
|
|
|
if $pre_filter and ref($pre_filter) ne 'CODE' ; |
292
|
|
|
|
|
|
|
|
293
|
5
|
|
50
|
20
|
|
114
|
$pre_filter ||= sub { 1 } ; |
|
20
|
|
|
|
|
55
|
|
294
|
|
|
|
|
|
|
|
295
|
5
|
|
|
|
|
12
|
my $me = {} ; |
296
|
5
|
|
|
|
|
12
|
my $schema = q{} ; |
297
|
5
|
|
|
|
|
12
|
my @fieldnames= () ; |
298
|
5
|
|
|
|
|
12
|
my @fieldnums = () ; |
299
|
5
|
|
|
|
|
13
|
my %fields = () ; |
300
|
|
|
|
|
|
|
|
301
|
5
|
|
|
|
|
19
|
$me->{REPORTS}= {} ; |
302
|
5
|
|
|
|
|
16
|
$me->{REPORT_PERIODS} = [ @report_period ] ; |
303
|
|
|
|
|
|
|
# Date ranges: $time_period =~ start_at_date / \s* - \s*/x end_at_date |
304
|
|
|
|
|
|
|
# start_at_date and end_at_dates look like time stamps. |
305
|
5
|
|
|
|
|
11
|
my ($t1, $t2) ; |
306
|
5
|
50
|
|
|
|
27
|
if ( my ($s, $e) = $time_period =~ /^([^-]+)-([^-]+)$/ ) { |
307
|
|
|
|
|
|
|
# XXX |
308
|
0
|
|
|
|
|
0
|
$s =~ s/\s+$// ; |
309
|
0
|
|
|
|
|
0
|
$e =~ s/^\s+// ; |
310
|
0
|
|
|
|
|
0
|
($t1, undef) = $stime_etime{__DEFAULT__}->( $s, [ localtime ] ) ; |
311
|
0
|
|
|
|
|
0
|
($t2, undef) = $stime_etime{__DEFAULT__}->( $e, [ localtime ] ) |
312
|
|
|
|
|
|
|
} else { |
313
|
5
|
50
|
|
|
|
164
|
($t1, $t2) = exists $stime_etime{$time_period} ? $stime_etime{$time_period}->( $time_period, [localtime] ) |
314
|
|
|
|
|
|
|
: $stime_etime{__DEFAULT__}->( $time_period, [localtime] ) |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
5
|
|
|
|
|
214
|
my $data ; |
318
|
5
|
50
|
|
|
|
42
|
$source_tag =~ s/dev_debug/dev_debug BOGON_SERVER/ |
319
|
|
|
|
|
|
|
if $source_tag =~ /^dev_debug/ ; |
320
|
5
|
|
|
|
|
26
|
($source_tag, $data) = split /\s+/, $source_tag, 2 ; |
321
|
|
|
|
|
|
|
|
322
|
5
|
50
|
33
|
|
|
43
|
die "new() called with either null source_tag or null parms: \$source_tag: '$source_tag' \$data: '$data'. Caller " . |
323
|
|
|
|
|
|
|
join(' ', caller) |
324
|
|
|
|
|
|
|
unless $source_tag && $data ; |
325
|
|
|
|
|
|
|
|
326
|
5
|
|
|
|
|
19
|
my ($server, $auth) = split /\s+/, $data, 2 ; |
327
|
|
|
|
|
|
|
|
328
|
5
|
50
|
|
|
|
22
|
die "new() called with a source_tag that failed to contain a non null server name. Caller " . join(' ', caller) |
329
|
|
|
|
|
|
|
unless $server ; |
330
|
|
|
|
|
|
|
|
331
|
5
|
|
|
|
|
31
|
$me->{DATA_SOURCE} = $data_source{$source_tag}->(split /\s+/, $auth) ; |
332
|
5
|
|
|
|
|
14
|
$me->{SERVER} = $server ; |
333
|
5
|
|
|
|
|
16
|
$me->{SOURCE_TAG} = $source_tag ; |
334
|
5
|
|
|
|
|
11
|
$me->{REPORT_TYPE} = $report_type ; |
335
|
5
|
|
|
|
|
15
|
$me->{T1} = $t1 ; |
336
|
5
|
|
|
|
|
15
|
$me->{T2} = $t2 ; |
337
|
|
|
|
|
|
|
|
338
|
5
|
|
|
|
|
12
|
foreach my $rep_period ( @report_period ) { |
339
|
|
|
|
|
|
|
|
340
|
5
|
|
|
|
|
10
|
my $user_data ; |
341
|
5
|
50
|
|
|
|
22
|
$user_data = $report_type eq 'host' ? QS_TEMP_HOSTREP : QS_TEMP_SVCREP ; |
342
|
5
|
|
|
|
|
75
|
$user_data =~ s/t1=T1&t2=T2/t1=$t1&t2=$t2/ ; |
343
|
5
|
|
|
|
|
40
|
$user_data =~ s/REPORT_PERIOD/$rep_period/ ; |
344
|
5
|
0
|
|
|
|
37
|
$user_data = |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
345
|
|
|
|
|
|
|
$me->{SOURCE_TAG} eq 'web_page' ? "http://$me->{SERVER}/nagios/cgi-bin/avail.cgi?$user_data" : |
346
|
|
|
|
|
|
|
$me->{SOURCE_TAG} eq 'dev_debug' ? $rep_period : |
347
|
|
|
|
|
|
|
$me->{SOURCE_TAG} eq 'local_cgi' ? $user_data : |
348
|
|
|
|
|
|
|
'__DEFAULT__' ; |
349
|
|
|
|
|
|
|
|
350
|
5
|
|
|
|
|
24
|
my @avail_rep = $me->{DATA_SOURCE}->($user_data) ; |
351
|
|
|
|
|
|
|
|
352
|
5
|
|
|
|
|
856
|
$schema = shift @avail_rep ; |
353
|
5
|
|
|
|
|
27
|
$schema .= ', AVAIL_URL, TREND_URL' ; |
354
|
5
|
|
50
|
|
|
230
|
$me->{FIELDNAMES} ||= [ @fieldnames = split /,\s+/, $schema ] ; |
355
|
5
|
|
|
|
|
241
|
@fields{@fieldnames}= (0 .. $#fieldnames) ; |
356
|
5
|
|
50
|
|
|
146
|
$me->{FIELDS} ||= { %fields } ; |
357
|
|
|
|
|
|
|
|
358
|
5
|
|
|
|
|
20
|
my @avail_report = () ; |
359
|
|
|
|
|
|
|
|
360
|
5
|
|
|
|
|
12
|
local $_ ; |
361
|
|
|
|
|
|
|
|
362
|
5
|
|
|
|
|
14
|
foreach (@avail_rep) { |
363
|
20
|
|
|
|
|
528
|
my @vals = split /,\s+/ ; |
364
|
|
|
|
|
|
|
|
365
|
20
|
|
|
|
|
63
|
my $host = $vals[$fields{HOST_NAME}] ; |
366
|
20
|
|
|
|
|
24
|
my $svc ; |
367
|
20
|
|
|
|
|
72
|
$host =~ s/"//g ; |
368
|
20
|
|
|
|
|
40
|
$vals[$fields{HOST_NAME}] = $host ; |
369
|
20
|
50
|
|
|
|
51
|
if ( $report_type eq 'service' ) { |
370
|
0
|
|
|
|
|
0
|
$svc = $vals[$fields{SERVICE_DESCRIPTION}] ; |
371
|
0
|
|
|
|
|
0
|
$svc =~ s/"//g ; |
372
|
0
|
|
|
|
|
0
|
$vals[$fields{SERVICE_DESCRIPTION}] = $svc ; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
20
|
50
|
|
|
|
50
|
my $avail_url = $report_type eq 'host' ? AVAIL_URL_TEMP_HOST : AVAIL_URL_TEMP_SVC ; |
376
|
20
|
|
|
|
|
86
|
$avail_url =~ s/HOST/$host/ ; |
377
|
20
|
50
|
|
|
|
54
|
$avail_url =~ s/SVC/$svc/ |
378
|
|
|
|
|
|
|
if $report_type eq 'service' ; |
379
|
20
|
|
|
|
|
222
|
$avail_url =~ s/t1=T1&t2=T2/t1=$t1&t2=$t2/ ; |
380
|
20
|
|
|
|
|
81
|
$avail_url =~ s/SERVER/$me->{SERVER}/ ; |
381
|
20
|
|
|
|
|
41
|
$vals[$fields{AVAIL_URL}] = $avail_url ; |
382
|
|
|
|
|
|
|
|
383
|
20
|
50
|
|
|
|
46
|
my $trend_url = $report_type eq 'host' ? TREND_URL_TEMP_HOST : TREND_URL_TEMP_SVC ; |
384
|
20
|
|
|
|
|
60
|
$trend_url =~ s/HOST/$host/ ; |
385
|
20
|
50
|
|
|
|
48
|
$trend_url =~ s/SVC/$svc/ |
386
|
|
|
|
|
|
|
if $report_type eq 'service' ; |
387
|
20
|
|
|
|
|
125
|
$trend_url =~ s/t1=T1&t2=T2/t1=$t1&t2=$t2/ ; |
388
|
20
|
|
|
|
|
79
|
$trend_url =~ s/SERVER/$me->{SERVER}/ ; |
389
|
20
|
|
|
|
|
39
|
$vals[$fields{TREND_URL}] = $trend_url ; |
390
|
|
|
|
|
|
|
|
391
|
20
|
|
|
|
|
21
|
my %F ; |
392
|
20
|
|
|
|
|
340
|
@F{@fieldnames} = @vals ; |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
next |
395
|
20
|
50
|
|
|
|
172
|
unless $pre_filter->(%F) ; |
396
|
|
|
|
|
|
|
|
397
|
20
|
|
|
|
|
328
|
push @avail_report, [ @vals ] ; |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
5
|
|
|
|
|
39
|
$me->{AVAIL_REPORTS}{$rep_period} = [ @avail_report ] ; |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
5
|
|
33
|
|
|
104
|
bless $me, ref($class) || $class ; |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
# Runs while object 'loads' |
409
|
|
|
|
|
|
|
# Creates accessors for the callers convenience. |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
# XXX |
412
|
|
|
|
|
|
|
# This class will _not_ use the accessors itself |
413
|
|
|
|
|
|
|
# since it doesn't believe it will be inherited from. |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
foreach my $acc (qw(FIELDS FIELDNAMES REPORT_PERIODS T1 T2 SERVER AVAIL_REPORTS REPORTS DATA_SOURCE SOURCE_TAG REPORT_TYPE)) { |
416
|
11
|
|
|
11
|
|
81
|
no strict 'refs' ; |
|
11
|
|
|
|
|
19
|
|
|
11
|
|
|
|
|
55599
|
|
417
|
|
|
|
|
|
|
*$acc = sub { |
418
|
0
|
|
|
0
|
|
0
|
my $me = shift @_ ; |
419
|
0
|
0
|
|
|
|
0
|
$me->{$acc} = @_ |
420
|
|
|
|
|
|
|
if @_ ; |
421
|
0
|
|
|
|
|
0
|
$me->{$acc} ; |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
sub mkreport { |
426
|
0
|
|
|
0
|
1
|
0
|
my ($me, $these_fields, $select_these, $this_order, $alter, $add_downs) = @_ ; |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
# $these_fields: fields which will appear in output |
429
|
|
|
|
|
|
|
# in the same order as specified (in |
430
|
|
|
|
|
|
|
# the array pointed to). |
431
|
|
|
|
|
|
|
# $select_these: callback specifying which records |
432
|
|
|
|
|
|
|
# to report on. |
433
|
|
|
|
|
|
|
# $this_order : callback for sort to order the |
434
|
|
|
|
|
|
|
# records. |
435
|
|
|
|
|
|
|
# $alter : callback to add fields to or other |
436
|
|
|
|
|
|
|
# wise mangle a record. Should return |
437
|
|
|
|
|
|
|
# the names of any added fields. |
438
|
|
|
|
|
|
|
# $add_downs : duplicate the rec by the |
439
|
|
|
|
|
|
|
# number of outage recs, appending |
440
|
|
|
|
|
|
|
# time down, up and outage duration. |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
# XXX |
443
|
|
|
|
|
|
|
# $these_fields should specify the names and orders |
444
|
|
|
|
|
|
|
# of any fields added by $alter->(). |
445
|
|
|
|
|
|
|
|
446
|
0
|
|
|
|
|
0
|
my $usage =<<'USAGE' ; |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
mkreport( $these_fields, $select_these, $this_order, $alter, $add_downs ) |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
$these_fields := optional array ref enumerating the fields, and there order to appear in the report. |
451
|
|
|
|
|
|
|
$select_these := optional callback returning true if the availability record is to appear in the report. Called |
452
|
|
|
|
|
|
|
with pairs of all fields and values for this record. |
453
|
|
|
|
|
|
|
$this_order := optional callback specifiying sort order. Called with pairs of all fieldnames and their offsets |
454
|
|
|
|
|
|
|
$alter := optional callback that munges fields (transforming field values or adding new fields). |
455
|
|
|
|
|
|
|
$add_downs := optional flag. If set, each availability record is duplicated by the number of outage records, |
456
|
|
|
|
|
|
|
and the time down, time up and duration of the outage is appended to each record. |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
USAGE |
459
|
|
|
|
|
|
|
|
460
|
0
|
0
|
0
|
|
|
0
|
die $usage |
461
|
|
|
|
|
|
|
if $these_fields and ref($these_fields) ne 'ARRAY' ; |
462
|
|
|
|
|
|
|
|
463
|
0
|
0
|
0
|
|
|
0
|
die $usage |
464
|
|
|
|
|
|
|
if $select_these and ref($select_these) ne 'CODE' ; |
465
|
|
|
|
|
|
|
|
466
|
0
|
0
|
0
|
|
|
0
|
die $usage |
467
|
|
|
|
|
|
|
if $this_order and ref($this_order) ne 'CODE' ; |
468
|
|
|
|
|
|
|
|
469
|
0
|
0
|
0
|
|
|
0
|
die $usage |
470
|
|
|
|
|
|
|
if $alter and ref($alter) ne 'CODE' ; |
471
|
|
|
|
|
|
|
|
472
|
0
|
|
0
|
|
|
0
|
$these_fields ||= [] ; |
473
|
0
|
|
0
|
0
|
|
0
|
$select_these ||= sub { 1 } ; |
|
0
|
|
|
|
|
0
|
|
474
|
0
|
|
0
|
0
|
|
0
|
$this_order ||= sub { my %f = @_ ; $a->[$f{HOST_NAME}] cmp $b->[$f{HOST_NAME}] } ; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
475
|
|
|
|
|
|
|
|
476
|
0
|
0
|
|
|
|
0
|
my @field_names = scalar(@$these_fields) ? @$these_fields : @{ $me->{FIELDNAMES} } ; |
|
0
|
|
|
|
|
0
|
|
477
|
0
|
|
|
|
|
0
|
my @fieldnames = @{ $me->{FIELDNAMES} } ; |
|
0
|
|
|
|
|
0
|
|
478
|
0
|
|
|
|
|
0
|
my %fields = %{ $me->{FIELDS} } ; |
|
0
|
|
|
|
|
0
|
|
479
|
|
|
|
|
|
|
|
480
|
0
|
|
|
|
|
0
|
$me->{REPORTS}{$_}{RECORDS} = [] |
481
|
0
|
|
|
|
|
0
|
foreach keys %{ $me->{AVAIL_REPORTS} } ; |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
# map |
484
|
|
|
|
|
|
|
# slice |
485
|
|
|
|
|
|
|
# sort |
486
|
|
|
|
|
|
|
# filter |
487
|
|
|
|
|
|
|
# alter |
488
|
|
|
|
|
|
|
# add_downs list |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
# Do the transforms - to add |
491
|
|
|
|
|
|
|
# fields - first, and then |
492
|
|
|
|
|
|
|
# update the fieldnames so |
493
|
|
|
|
|
|
|
# the new fields can be used |
494
|
|
|
|
|
|
|
# to select and sort. |
495
|
|
|
|
|
|
|
|
496
|
0
|
|
|
|
|
0
|
foreach my $rep ( keys %{ $me->{AVAIL_REPORTS} } ) { |
|
0
|
|
|
|
|
0
|
|
497
|
|
|
|
|
|
|
|
498
|
0
|
|
|
|
|
0
|
my (%F, @r, @avail_recs, $avail_url) ; |
499
|
|
|
|
|
|
|
|
500
|
0
|
|
|
|
|
0
|
@avail_recs = @{ $me->{AVAIL_REPORTS}{$rep} } ; |
|
0
|
|
|
|
|
0
|
|
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
next |
503
|
0
|
0
|
|
|
|
0
|
unless @avail_recs ; |
504
|
|
|
|
|
|
|
|
505
|
0
|
|
|
|
|
0
|
@r = shift @avail_recs ; |
506
|
|
|
|
|
|
|
|
507
|
0
|
0
|
|
|
|
0
|
$add_downs = 0 |
508
|
|
|
|
|
|
|
unless $me->{SOURCE_TAG} =~ /^(?:web_page|local_cgi)/ ; |
509
|
|
|
|
|
|
|
|
510
|
0
|
0
|
|
|
|
0
|
if ( $add_downs ) { |
511
|
0
|
|
|
|
|
0
|
my @ofn = qw(DOWN UP OUTAGE) ; |
512
|
0
|
|
|
|
|
0
|
push @fieldnames, @ofn ; |
513
|
|
|
|
|
|
|
# The new fields are added to the list |
514
|
|
|
|
|
|
|
# of those appearing in the report |
515
|
0
|
0
|
|
|
|
0
|
push @field_names, @ofn |
516
|
|
|
|
|
|
|
unless grep $_ eq $ofn[0], @field_names ; |
517
|
0
|
|
|
|
|
0
|
@r = |
518
|
0
|
|
|
|
|
0
|
map { get_downs($_, $me->{DATA_SOURCE}, $_->[$fields{AVAIL_URL}], $me->{T1}) } shift @r ; |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
|
521
|
0
|
0
|
|
|
|
0
|
if ( $alter ) { |
522
|
0
|
|
|
|
|
0
|
my @downs = @r ; |
523
|
0
|
|
|
|
|
0
|
@F{@fieldnames} = @{$r[0]} ; |
|
0
|
|
|
|
|
0
|
|
524
|
|
|
|
|
|
|
# XXX - don't modify the rec, only get the added fields. |
525
|
0
|
|
|
|
|
0
|
my @afn = $alter->(\%F) ; |
526
|
|
|
|
|
|
|
# my @afn = $alter->($r[0], \%F) ; |
527
|
|
|
|
|
|
|
# my @afn = $alter->($r[0], %F) ; |
528
|
0
|
|
|
|
|
0
|
push @fieldnames, @afn ; |
529
|
0
|
0
|
|
|
|
0
|
push @field_names, @afn |
530
|
|
|
|
|
|
|
unless grep $_ eq $afn[0], @field_names ; |
531
|
0
|
|
|
|
|
0
|
@r = |
532
|
0
|
|
|
|
|
0
|
map { @F{@fieldnames} = @$_; $alter->(\%F); [ @F{@fieldnames} ] } @downs ; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
|
535
|
0
|
|
|
|
|
0
|
$me->{FIELDNAMES} = [ @fieldnames ] ; |
536
|
0
|
|
|
|
|
0
|
@fields{@fieldnames}= 0 .. $#fieldnames ; |
537
|
0
|
|
|
|
|
0
|
$me->{FIELDS} = { %fields } ; |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
# Transform rec by adding or munging fields |
540
|
|
|
|
|
|
|
# NB, the one attempt I made to move the |
541
|
|
|
|
|
|
|
# tests outside map actually slowed the benchmark |
542
|
|
|
|
|
|
|
# 'make tests'. |
543
|
0
|
|
|
|
|
0
|
push @r, |
544
|
|
|
|
|
|
|
map { |
545
|
0
|
0
|
|
|
|
0
|
@F{@fieldnames} = @$_ ; |
546
|
0
|
0
|
|
|
|
0
|
$alter->(\%F) |
547
|
|
|
|
|
|
|
if $alter ; |
548
|
0
|
|
|
|
|
0
|
[ @F{@fieldnames} ] |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
map { |
551
|
0
|
|
|
|
|
0
|
$add_downs |
552
|
|
|
|
|
|
|
? get_downs($_, $me->{DATA_SOURCE}, $_->[$fields{AVAIL_URL}], $me->{T1}) |
553
|
|
|
|
|
|
|
: $_ |
554
|
|
|
|
|
|
|
} |
555
|
|
|
|
|
|
|
@avail_recs ; |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
# Slice |
558
|
0
|
|
|
|
|
0
|
my @rep = map [ @{$_}[@fields{@field_names}] ], |
|
0
|
|
|
|
|
0
|
|
559
|
|
|
|
|
|
|
# Sort |
560
|
0
|
|
|
|
|
0
|
sort { $this_order->(%fields) } |
561
|
|
|
|
|
|
|
# Filter |
562
|
0
|
|
|
|
|
0
|
grep { @F{@{$me->{FIELDNAMES}}} = @$_; $select_these->(%F) } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
563
|
|
|
|
|
|
|
@r ; |
564
|
|
|
|
|
|
|
|
565
|
0
|
|
|
|
|
0
|
$me->{REPORTS}{$rep}{RECORDS} = [ @rep ] ; |
566
|
0
|
|
|
|
|
0
|
$me->{REPORTS}{$rep}{FIELDNAMES} = [ @field_names ] ; |
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
sub excel_dump { |
573
|
0
|
|
|
0
|
1
|
0
|
my ($me, $excel_filename, $chart_details) = @_ ; |
574
|
|
|
|
|
|
|
|
575
|
0
|
|
|
|
|
0
|
eval { require Spreadsheet::WriteExcel } ; |
|
0
|
|
|
|
|
0
|
|
576
|
0
|
0
|
|
|
|
0
|
die "John McNamara's _excellent_ CPAN module, Spreadsheet::WriteExcel is needed by excel_dump(). Outahere. " |
577
|
|
|
|
|
|
|
if $@ ; |
578
|
|
|
|
|
|
|
|
579
|
0
|
|
0
|
|
|
0
|
my $workbook = Spreadsheet::WriteExcel->new($excel_filename || EXCEL_FILENAME) ; |
580
|
0
|
0
|
|
|
|
0
|
die "Spreadsheet::WriteExcel constructor failed, prob opening '$excel_filename': $!" |
581
|
|
|
|
|
|
|
unless $workbook ; |
582
|
|
|
|
|
|
|
|
583
|
0
|
|
|
|
|
0
|
my $format = $workbook->add_format() ; |
584
|
0
|
|
|
|
|
0
|
$format->set_bold() ; |
585
|
|
|
|
|
|
|
|
586
|
0
|
|
|
|
|
0
|
foreach my $rep (@{ $me->{REPORT_PERIODS} }) { |
|
0
|
|
|
|
|
0
|
|
587
|
|
|
|
|
|
|
|
588
|
0
|
|
|
|
|
0
|
my $down_times = $me->{REPORTS}{$rep}{RECORDS} ; |
589
|
|
|
|
|
|
|
|
590
|
0
|
|
|
|
|
0
|
my $worksheet = $workbook->addworksheet($rep) ; |
591
|
|
|
|
|
|
|
|
592
|
0
|
|
|
|
|
0
|
my @max_col_width = () ; |
593
|
|
|
|
|
|
|
# The general syntax is write($row, $column, $token). |
594
|
|
|
|
|
|
|
# Note that row and column are zero indexed |
595
|
0
|
|
|
|
|
0
|
my ($row, $col) = (0, 0) ; |
596
|
|
|
|
|
|
|
# XXX |
597
|
|
|
|
|
|
|
# Scan all data to determine widest column. |
598
|
|
|
|
|
|
|
# The column width needs to be set before any |
599
|
|
|
|
|
|
|
# cells are written. |
600
|
|
|
|
|
|
|
|
601
|
0
|
|
|
|
|
0
|
foreach my $c ( @{ $me->{REPORTS}{$rep}{FIELDNAMES} } ) { |
|
0
|
|
|
|
|
0
|
|
602
|
0
|
|
|
|
|
0
|
$max_col_width[$col++] = 1.5 * length($c) ; |
603
|
|
|
|
|
|
|
# Fieldnames are bold so are wider than usual. |
604
|
|
|
|
|
|
|
} |
605
|
|
|
|
|
|
|
|
606
|
0
|
|
|
|
|
0
|
foreach my $r (@$down_times) { |
607
|
0
|
|
|
|
|
0
|
$col = 0 ; |
608
|
0
|
|
|
|
|
0
|
foreach my $c (@$r) { |
609
|
0
|
|
|
|
|
0
|
my $h ; |
610
|
|
|
|
|
|
|
# XXX |
611
|
|
|
|
|
|
|
# Set col width to width of label _not_ the URL. |
612
|
|
|
|
|
|
|
|
613
|
0
|
0
|
|
|
|
0
|
my $len = (($h) = $c =~ m#^http://.+?host=([^&]+)) ? length($h) : length($c) ; |
614
|
0
|
0
|
|
|
|
0
|
$max_col_width[$col] = $len |
615
|
|
|
|
|
|
|
if $len >= $max_col_width[$col] ; |
616
|
0
|
|
|
|
|
0
|
$col++ ; |
617
|
|
|
|
|
|
|
} |
618
|
|
|
|
|
|
|
} |
619
|
|
|
|
|
|
|
|
620
|
0
|
|
|
|
|
0
|
$col = 0 ; |
621
|
|
|
|
|
|
|
|
622
|
0
|
|
|
|
|
0
|
foreach my $c ( @{ $me->{REPORTS}{$rep}{FIELDNAMES} } ) { |
|
0
|
|
|
|
|
0
|
|
623
|
0
|
|
|
|
|
0
|
$worksheet->set_column($col, $col, $max_col_width[$col]) ; |
624
|
0
|
|
|
|
|
0
|
$worksheet->write(0, $col, $c, $format) ; |
625
|
0
|
|
|
|
|
0
|
$col++ |
626
|
|
|
|
|
|
|
} |
627
|
|
|
|
|
|
|
|
628
|
0
|
|
|
|
|
0
|
$row = 1 ; |
629
|
|
|
|
|
|
|
|
630
|
0
|
|
|
|
|
0
|
foreach my $r (@$down_times) { |
631
|
0
|
|
|
|
|
0
|
$col = 0 ; |
632
|
0
|
|
|
|
|
0
|
foreach my $c ( @$r ) { |
633
|
0
|
0
|
|
|
|
0
|
if ( my ($h) = $c =~ m#^http://.+?host=([^&]+) ) { |
634
|
0
|
0
|
|
|
|
0
|
$worksheet->write_url($row, $col, $c, $h ? $h : "URL without hostname: $c") ; |
635
|
|
|
|
|
|
|
} else { |
636
|
0
|
|
|
|
|
0
|
$worksheet->write($row, $col, $c) |
637
|
|
|
|
|
|
|
} |
638
|
0
|
|
|
|
|
0
|
$col++ ; |
639
|
|
|
|
|
|
|
} |
640
|
0
|
|
|
|
|
0
|
$row++ ; |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
|
644
|
0
|
0
|
|
|
|
0
|
&add_chart($workbook, $chart_details) |
645
|
|
|
|
|
|
|
if $chart_details ; |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
} |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
sub csv_dump { |
651
|
0
|
|
|
0
|
1
|
0
|
my $me = shift @_ ; |
652
|
|
|
|
|
|
|
|
653
|
0
|
|
|
|
|
0
|
foreach my $rep (@{ $me->{REPORT_PERIODS} }) { |
|
0
|
|
|
|
|
0
|
|
654
|
|
|
|
|
|
|
|
655
|
0
|
|
|
|
|
0
|
print "==> $rep reporting period.\n" ; |
656
|
|
|
|
|
|
|
|
657
|
0
|
|
|
|
|
0
|
my $down_times = $me->{REPORTS}{$rep}{RECORDS} ; |
658
|
|
|
|
|
|
|
|
659
|
0
|
|
|
|
|
0
|
print |
660
|
0
|
|
|
|
|
0
|
join(',', @{ $me->{REPORTS}{$rep}{FIELDNAMES} }), "\n" ; |
661
|
|
|
|
|
|
|
|
662
|
0
|
|
|
|
|
0
|
foreach my $r ( @{$down_times} ) { |
|
0
|
|
|
|
|
0
|
|
663
|
0
|
|
|
|
|
0
|
print |
664
|
|
|
|
|
|
|
join(',', @$r), "\n" ; |
665
|
|
|
|
|
|
|
} |
666
|
|
|
|
|
|
|
|
667
|
0
|
|
|
|
|
0
|
print "\n\n" ; |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
} |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
sub debug_dump { |
673
|
0
|
|
|
0
|
0
|
0
|
my ($me, $field_width, $fields_per_line) = @_ ; |
674
|
|
|
|
|
|
|
|
675
|
0
|
|
0
|
|
|
0
|
$field_width ||= 15 ; |
676
|
0
|
|
0
|
|
|
0
|
$fields_per_line||= 7 ; |
677
|
|
|
|
|
|
|
|
678
|
0
|
|
|
|
|
0
|
my $format = 0 ; |
679
|
|
|
|
|
|
|
|
680
|
0
|
|
|
|
|
0
|
foreach my $rep (@{ $me->{REPORT_PERIODS} }) { |
|
0
|
|
|
|
|
0
|
|
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
format STDOUT_TOP = |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
685
|
|
|
|
|
|
|
$rep |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
. |
688
|
|
|
|
|
|
|
|
689
|
0
|
|
|
|
|
0
|
$- = 0 ; |
690
|
|
|
|
|
|
|
|
691
|
0
|
|
|
|
|
0
|
my @line ; |
692
|
0
|
|
|
|
|
0
|
@line = map { my $x = $_ ; $x =~ s/PERCENT/%/; $x } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
693
|
0
|
|
|
|
|
0
|
@{ $me->{REPORTS}{$rep}{FIELDNAMES} } ; |
694
|
|
|
|
|
|
|
|
695
|
0
|
0
|
|
|
|
0
|
&mkform($field_width, $fields_per_line, @line) |
696
|
|
|
|
|
|
|
unless $format++ ; |
697
|
0
|
|
|
|
|
0
|
&do_write(@line) ; |
698
|
|
|
|
|
|
|
|
699
|
0
|
|
|
|
|
0
|
foreach my $r ( @{ $me->{REPORTS}{$rep}{RECORDS} } ) { |
|
0
|
|
|
|
|
0
|
|
700
|
0
|
|
|
|
|
0
|
@line = @$r ; |
701
|
0
|
|
|
|
|
0
|
&do_write(@line) ; |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
} |
704
|
|
|
|
|
|
|
} |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
{ |
707
|
|
|
|
|
|
|
my @base = ( |
708
|
|
|
|
|
|
|
{ b => 60, u => 's' }, |
709
|
|
|
|
|
|
|
{ b => 60, u => 'm' }, |
710
|
|
|
|
|
|
|
{ b => 24, u => 'h' }, |
711
|
|
|
|
|
|
|
{ b => 7, u => 'd' }, |
712
|
|
|
|
|
|
|
{ b => 4, u => 'w' }, |
713
|
|
|
|
|
|
|
{ b => 12, u => 'm' }, |
714
|
|
|
|
|
|
|
) ; |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
sub time2ddhhmmss { |
717
|
|
|
|
|
|
|
# Rounds arg to nearest 5 minute interval |
718
|
|
|
|
|
|
|
# and returns hhmmss string. |
719
|
23
|
|
|
23
|
0
|
6349
|
my $d = shift @_ ; |
720
|
|
|
|
|
|
|
|
721
|
23
|
|
|
|
|
28
|
$d += 150 ; |
722
|
23
|
|
|
|
|
38
|
$d = int($d/300) * 300 ; |
723
|
|
|
|
|
|
|
|
724
|
23
|
100
|
|
|
|
60
|
return ' ' |
725
|
|
|
|
|
|
|
unless $d ; |
726
|
|
|
|
|
|
|
|
727
|
21
|
|
|
|
|
22
|
my ($s, $r, $i) ; |
728
|
21
|
|
|
|
|
21
|
$s = ' ' ; |
729
|
|
|
|
|
|
|
|
730
|
21
|
|
|
|
|
43
|
for ($i = 0; $d > 0; $i++) { |
731
|
80
|
|
|
|
|
97
|
$r = $d % $base[$i]{b} ; |
732
|
80
|
100
|
|
|
|
156
|
$s = "${r}$base[$i]{u} $s" |
733
|
|
|
|
|
|
|
if $r > 0 ; |
734
|
80
|
|
|
|
|
170
|
$d = ($d - $r) / $base[$i]{b} ; |
735
|
|
|
|
|
|
|
} |
736
|
|
|
|
|
|
|
|
737
|
21
|
|
|
|
|
220
|
$s ; |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
} |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
} |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
sub mkform { |
744
|
|
|
|
|
|
|
|
745
|
0
|
|
|
0
|
0
|
0
|
my ($field_width, $fields_per_line) = @_ ; |
746
|
|
|
|
|
|
|
|
747
|
0
|
|
|
|
|
0
|
my ($pics, $vals, $f1, $f, $form_body) ; |
748
|
|
|
|
|
|
|
|
749
|
0
|
|
|
|
|
0
|
$f1 = '@' . '<' x 24 ; |
750
|
0
|
|
|
|
|
0
|
$f = '@' . '<' x $field_width ; |
751
|
|
|
|
|
|
|
|
752
|
0
|
|
|
|
|
0
|
$pics = $f1 . " $f" x ($fields_per_line - 1) ; |
753
|
0
|
|
|
|
|
0
|
$vals = 'shift(@_), ' x $fields_per_line ; |
754
|
0
|
|
|
|
|
0
|
$form_body = "format STDOUT = \n" ; |
755
|
|
|
|
|
|
|
|
756
|
0
|
|
|
|
|
0
|
$form_body .= <
|
757
|
|
|
|
|
|
|
$pics |
758
|
|
|
|
|
|
|
$vals |
759
|
|
|
|
|
|
|
EOFORM |
760
|
|
|
|
|
|
|
|
761
|
0
|
|
|
|
|
0
|
my $fields_remaining = @_ - $fields_per_line ; |
762
|
|
|
|
|
|
|
|
763
|
0
|
0
|
|
|
|
0
|
if ( $fields_remaining <= 0 ) { |
764
|
0
|
|
|
|
|
0
|
$form_body .= <
|
765
|
|
|
|
|
|
|
. |
766
|
|
|
|
|
|
|
EOFORM |
767
|
|
|
|
|
|
|
|
768
|
0
|
|
|
|
|
0
|
eval $form_body ; |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
} else { |
771
|
0
|
|
|
|
|
0
|
my $lines_remaining = int($fields_remaining / ($fields_per_line - 1)) ; |
772
|
0
|
|
|
|
|
0
|
my $fields_on_last_line = $fields_remaining % ($fields_per_line - 1) ; |
773
|
0
|
|
|
|
|
0
|
my $spaces = ' ' x 25 ; |
774
|
|
|
|
|
|
|
|
775
|
0
|
|
|
|
|
0
|
$pics = $spaces . " $f" x ($fields_per_line - 1) ; |
776
|
0
|
|
|
|
|
0
|
$vals = $spaces . ' shift(@_), ' x ($fields_per_line - 1) ; |
777
|
|
|
|
|
|
|
|
778
|
0
|
|
|
|
|
0
|
$form_body .= <
|
779
|
|
|
|
|
|
|
$pics |
780
|
|
|
|
|
|
|
$vals |
781
|
|
|
|
|
|
|
EOFORM |
782
|
|
|
|
|
|
|
|
783
|
0
|
|
|
|
|
0
|
$pics = $spaces . " $f" x $fields_on_last_line ; |
784
|
0
|
|
|
|
|
0
|
$vals = $spaces . ' shift(@_), ' x $fields_on_last_line ; |
785
|
|
|
|
|
|
|
|
786
|
0
|
|
|
|
|
0
|
$form_body .= <
|
787
|
|
|
|
|
|
|
$pics |
788
|
|
|
|
|
|
|
$vals |
789
|
|
|
|
|
|
|
. |
790
|
|
|
|
|
|
|
EOFORM |
791
|
|
|
|
|
|
|
|
792
|
0
|
|
|
|
|
0
|
eval $form_body ; |
793
|
|
|
|
|
|
|
} |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
} |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
sub do_write { |
798
|
|
|
|
|
|
|
# Only exists to get vals into @_ ; |
799
|
0
|
|
|
0
|
0
|
0
|
write ; |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
sub max_l { |
803
|
|
|
|
|
|
|
# my $max = shift @_ or |
804
|
|
|
|
|
|
|
return undef |
805
|
7
|
100
|
|
7
|
1
|
2896
|
unless @_ ; |
806
|
|
|
|
|
|
|
|
807
|
6
|
|
|
|
|
8
|
my $max = shift @_ ; |
808
|
|
|
|
|
|
|
|
809
|
6
|
|
|
|
|
7
|
local $_ ; |
810
|
6
|
|
|
|
|
16
|
while ( defined($_ = shift @_) ) { |
811
|
30
|
100
|
|
|
|
66
|
$max = $_ |
812
|
|
|
|
|
|
|
if $_ >= $max |
813
|
|
|
|
|
|
|
} |
814
|
|
|
|
|
|
|
|
815
|
6
|
|
|
|
|
66
|
$max ; |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
} |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
sub comp { |
820
|
|
|
|
|
|
|
# Returns a comparator function to sort the avail records |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
# Call with (alpha => 0|1, ascend => 0|1, fields =. [ f1.. ]) |
823
|
|
|
|
|
|
|
|
824
|
0
|
|
|
0
|
1
|
0
|
my %sort_parms = (%default_sort, @_) ; |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
# eg |
827
|
|
|
|
|
|
|
# alpha => 0, $ascend => 1, fields = [TOTAL_TIME_DOWN, TOTAL_TIME_UNREACH] |
828
|
|
|
|
|
|
|
# TIME_DOWN and TIME_UNREACH are the same to the reader of the report; |
829
|
|
|
|
|
|
|
# they should be consolidated with some consolidation function (eg max |
830
|
|
|
|
|
|
|
# or sum of values). |
831
|
|
|
|
|
|
|
|
832
|
0
|
|
|
|
|
0
|
my $r ; |
833
|
|
|
|
|
|
|
|
834
|
0
|
0
|
|
|
|
0
|
if ( $sort_parms{alpha} ) { |
835
|
|
|
|
|
|
|
$r = $sort_parms{ascend} |
836
|
|
|
|
|
|
|
? sub { |
837
|
0
|
|
|
0
|
|
0
|
my %f = @_ ; |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
# package Nagios::Report ; |
840
|
0
|
|
|
|
|
0
|
$a->[$f{HOST_NAME}] cmp $b->[$f{HOST_NAME}] |
841
|
|
|
|
|
|
|
} |
842
|
|
|
|
|
|
|
: sub { |
843
|
0
|
|
|
0
|
|
0
|
my %f = @_ ; |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
# package Nagios::Report ; |
846
|
0
|
|
|
|
|
0
|
$b->[$f{HOST_NAME}] cmp $a->[$f{HOST_NAME}] |
847
|
0
|
0
|
|
|
|
0
|
} ; |
848
|
0
|
|
|
|
|
0
|
return $r ; |
849
|
|
|
|
|
|
|
} else { |
850
|
0
|
|
|
|
|
0
|
my $fields = $sort_parms{fields} ; |
851
|
|
|
|
|
|
|
$r = $sort_parms{ascend} |
852
|
|
|
|
|
|
|
? sub { |
853
|
0
|
|
|
0
|
|
0
|
my %f = @_ ; |
854
|
|
|
|
|
|
|
|
855
|
0
|
|
|
|
|
0
|
my @field_indices = @f{@$fields} ; |
856
|
|
|
|
|
|
|
|
857
|
0
|
|
|
|
|
0
|
my $a_max = &max_l( @{$a}[@field_indices] ) ; |
|
0
|
|
|
|
|
0
|
|
858
|
0
|
|
|
|
|
0
|
my $b_max = &max_l( @{$b}[@field_indices] ) ; |
|
0
|
|
|
|
|
0
|
|
859
|
0
|
|
|
|
|
0
|
$a_max <=> $b_max ; |
860
|
|
|
|
|
|
|
} |
861
|
|
|
|
|
|
|
: sub { |
862
|
0
|
|
|
0
|
|
0
|
my %f = @_ ; |
863
|
|
|
|
|
|
|
|
864
|
0
|
|
|
|
|
0
|
my @field_indices = @f{@$fields} ; |
865
|
|
|
|
|
|
|
|
866
|
0
|
|
|
|
|
0
|
my $a_max = &max_l( @{$a}[@field_indices] ) ; |
|
0
|
|
|
|
|
0
|
|
867
|
0
|
|
|
|
|
0
|
my $b_max = &max_l( @{$b}[@field_indices] ) ; |
|
0
|
|
|
|
|
0
|
|
868
|
0
|
|
|
|
|
0
|
$b_max <=> $a_max ; |
869
|
0
|
0
|
|
|
|
0
|
} ; |
870
|
0
|
|
|
|
|
0
|
return $r ; |
871
|
|
|
|
|
|
|
} |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
} |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
sub gen_local_cgi { |
876
|
0
|
|
|
0
|
0
|
0
|
my $user = shift @_ ; |
877
|
|
|
|
|
|
|
# Generate a closure that will get an |
878
|
|
|
|
|
|
|
# availability report by running the CGI |
879
|
|
|
|
|
|
|
# from the shell. |
880
|
0
|
0
|
|
|
|
0
|
die "gen_local_cgi() called without username for access to local availability CGI: \$user: '$user'. Caller " |
881
|
|
|
|
|
|
|
. join(' ', caller) |
882
|
|
|
|
|
|
|
unless $user ; |
883
|
|
|
|
|
|
|
|
884
|
0
|
|
|
|
|
0
|
$ENV{REMOTE_USER} = $user ; |
885
|
0
|
|
|
|
|
0
|
$ENV{REQUEST_METHOD} = REQUEST_METHOD ; |
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
return sub { |
888
|
0
|
|
|
0
|
|
0
|
my $url = shift @_ ; |
889
|
|
|
|
|
|
|
# Must convert URL to query_string |
890
|
0
|
|
|
|
|
0
|
my $qs ; |
891
|
0
|
|
|
|
|
0
|
($qs = $url) =~ s|http:.*?\?|| ; |
892
|
|
|
|
|
|
|
|
893
|
0
|
|
|
|
|
0
|
$ENV{QUERY_STRING} = $qs ; |
894
|
0
|
|
|
|
|
0
|
my @x = `${\NAG_AVAIL_CGI}` ; |
|
0
|
|
|
|
|
0
|
|
895
|
|
|
|
|
|
|
# Drop HTTP headers |
896
|
0
|
|
|
|
|
0
|
splice @x, 0, 6 ; |
897
|
0
|
|
|
|
|
0
|
chomp @x ; |
898
|
0
|
0
|
|
|
|
0
|
wantarray ? @x : join('', @x) ; |
899
|
0
|
|
|
|
|
0
|
} ; |
900
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
} |
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
sub gen_web_page { |
904
|
0
|
|
|
0
|
0
|
0
|
my ($user, $pass) = @_ ; |
905
|
|
|
|
|
|
|
|
906
|
0
|
0
|
0
|
|
|
0
|
die "gen_web_page() called without username or password for web page access: \$user: '$user', \$pass: '$pass'." |
907
|
|
|
|
|
|
|
. ' Caller ' . join(' ', caller) |
908
|
|
|
|
|
|
|
unless $user && $pass ; |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
return sub { |
911
|
|
|
|
|
|
|
# lynx -dump will render the page as text |
912
|
|
|
|
|
|
|
# regardless of its content. |
913
|
0
|
|
|
0
|
|
0
|
USE_LYNX ? `${\LYNX} -nolist -dump -width=1000 -auth=$user:$pass '$_[0]'` |
914
|
0
|
|
|
|
|
0
|
: `${\WGET} --output-document=- --http-user=$user --http-passwd=$pass '$_[0]' 2>/dev/null` ; |
915
|
0
|
|
|
|
|
0
|
} ; |
916
|
|
|
|
|
|
|
} |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
sub down_records { |
919
|
0
|
|
|
0
|
0
|
0
|
my ($data_source, $avail_url, $start_time) = @_ ; |
920
|
|
|
|
|
|
|
|
921
|
0
|
|
|
|
|
0
|
my $avail_rep = $data_source->($avail_url) ; |
922
|
|
|
|
|
|
|
|
923
|
0
|
|
|
|
|
0
|
my ($downs, @down_recs, @downs) ; |
924
|
|
|
|
|
|
|
|
925
|
0
|
0
|
|
|
|
0
|
if ( $avail_rep =~ //i ) { |
926
|
|
|
|
|
|
|
# XXX |
927
|
|
|
|
|
|
|
# Will fail if the availability CGI contains |
928
|
|
|
|
|
|
|
# different tags |
929
|
|
|
|
|
|
|
# |
930
|
|
|
|
|
|
|
# | 01-11-2005 00:00:00 |
931
|
|
|
|
|
|
|
# | 09-11-2005 15:09:59 |
932
|
|
|
|
|
|
|
# | 8d 15h 9m 59s |
933
|
|
|
|
|
|
|
# | HOST UP (HARD) |
934
|
|
|
|
|
|
|
|
935
|
0
|
|
|
|
|
0
|
($downs) = $avail_rep =~ /( |
.*)/s ;
936
|
0
|
|
|
|
|
0
|
my @rows = $downs =~ m|( |
)|g ;
937
|
0
|
|
|
|
|
0
|
@down_recs = map { s/<.*?>/ /g; $_ } @rows ; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
938
|
|
|
|
|
|
|
} else { |
939
|
|
|
|
|
|
|
# Parsed HTML (by lynx -dump) looks like |
940
|
|
|
|
|
|
|
# 01-11-2005 00:00:00 09-11-2005 15:09:59 8d 15h 9m 59s |
941
|
|
|
|
|
|
|
# HOST UP (HARD) |
942
|
0
|
|
|
|
|
0
|
($downs) = $avail_rep =~ m|( \d+-\d+-\d+ \s+ \d+:\d+:\d+ \s+ \d+-\d+-\d+ \s+ \d+:\d+:\d+ .* \Z) |msx ; |
943
|
0
|
|
|
|
|
0
|
@down_recs = split /\n/, $downs ; |
944
|
|
|
|
|
|
|
} |
945
|
|
|
|
|
|
|
|
946
|
0
|
|
|
|
|
0
|
local $_ ; |
947
|
|
|
|
|
|
|
|
948
|
0
|
|
|
|
|
0
|
foreach (@down_recs) { |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
=begin comment |
951
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
# Must also deal with scheduled downtime. |
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
01-02-2006 00:00:00 01-02-2006 14:27:54 0d 14h 27m 54s HOST UP (HARD) PING OK - Packet loss = 0%, RTA = 7.26 ms |
955
|
|
|
|
|
|
|
02-02-2006 20:24:42 02-02-2006 20:24:42 0d 0h 0m 0s HOST DOWN (HARD) CRITICAL - Plugin timed out after 10 seconds |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
VVVV This appears to be the correct entry |
958
|
|
|
|
|
|
|
02-02-2006 20:24:42 02-02-2006 20:47:54 0d 0h 23m 12s HOST DOWNTIME START Start of scheduled downtime |
959
|
|
|
|
|
|
|
^^^^ |
960
|
|
|
|
|
|
|
02-02-2006 20:47:54 02-02-2006 22:24:42 0d 1h 36m 48s HOST UP (HARD) PING OK - Packet loss = 0%, RTA = 0.66 ms |
961
|
|
|
|
|
|
|
02-02-2006 22:24:42 03-02-2006 12:54:29 0d 14h 29m 47s HOST DOWNTIME END End of scheduled downtime |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
=end comment |
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
=cut |
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
next |
968
|
0
|
0
|
|
|
|
0
|
if /HOST UP|SERVICE OK|HOST DOWNTIME END/ ; |
969
|
|
|
|
|
|
|
|
970
|
0
|
|
|
|
|
0
|
my ($down, $up, $outage) = / |
971
|
|
|
|
|
|
|
(\d+-\d+-\d+ \s+ \d+:\d+:\d+) \s+ |
972
|
|
|
|
|
|
|
(\d+-\d+-\d+ \s+ \d+:\d+:\d+) \s+ |
973
|
|
|
|
|
|
|
( (?:\d+[wdhms] \s*)+ ) |
974
|
|
|
|
|
|
|
/x ; |
975
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
next |
977
|
0
|
0
|
|
|
|
0
|
if &before_start($down, $start_time) ; |
978
|
|
|
|
|
|
|
|
979
|
0
|
|
|
|
|
0
|
$outage =~ s/^(?:0[wdh] )*//g ; |
980
|
|
|
|
|
|
|
|
981
|
0
|
|
|
|
|
0
|
push @downs, [$down, $up, $outage] ; |
982
|
|
|
|
|
|
|
} |
983
|
|
|
|
|
|
|
|
984
|
0
|
0
|
|
|
|
0
|
@downs = ( [ (' ') x 3 ] ) |
985
|
|
|
|
|
|
|
unless @downs ; |
986
|
|
|
|
|
|
|
@downs |
987
|
|
|
|
|
|
|
|
988
|
0
|
|
|
|
|
0
|
} |
989
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
sub before_start { |
991
|
3
|
|
|
3
|
0
|
1090
|
my ($t1_str, $t2) = @_ ; |
992
|
3
|
|
|
|
|
8
|
my $t1 = &date2time($t1_str) ; |
993
|
|
|
|
|
|
|
|
994
|
3
|
100
|
|
|
|
214
|
return $t1 < $t2 ? 1 : 0 ; |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
} |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
sub date2time { |
999
|
3
|
|
|
3
|
0
|
4
|
local $_ = shift @_ ; |
1000
|
|
|
|
|
|
|
|
1001
|
3
|
|
|
|
|
4
|
my ($dd, $mm, $mon, $yyyy, $h, $m, $s) ; |
1002
|
|
|
|
|
|
|
|
1003
|
3
|
50
|
|
|
|
28
|
if ( ($dd, $mm, $yyyy, $h, $m, $s) = m< (\d+)-(\d+)-(\d+) \s+ (\d+):(\d+):(\d+) >x ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
# 01-11-2005 00:00:00 |
1005
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
# DD-MM-YYYY HH:MM:SS Euro style dates with day first |
1007
|
3
|
|
|
|
|
15
|
return EURO_DATE ? timelocal($s, $m, $h, $dd, $mm - 1, $yyyy) |
1008
|
|
|
|
|
|
|
# MM-DD-YYYY HH:MM:SS US style dates with month first |
1009
|
|
|
|
|
|
|
: timelocal($s, $m, $h, $mm, $dd - 1, $yyyy) |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
} elsif ( ($mon, $dd, $h, $m, $s, $yyyy) = /\w{3} (\w{3})\s+(\d+) (\d+):(\d+):(\d+) \w{3} (\d{4})/ ) { |
1012
|
|
|
|
|
|
|
# Tue Nov 29 20:19:17 EST 2005 |
1013
|
0
|
|
|
|
|
|
$mon = "\u\L$mon" ; |
1014
|
0
|
|
|
|
|
|
$mm = MONTH->{$mon} ; |
1015
|
0
|
|
|
|
|
|
return timelocal($s, $m, $h, $dd, $mm - 1, $yyyy) ; |
1016
|
|
|
|
|
|
|
} elsif ( /now/ ) { |
1017
|
0
|
|
|
|
|
|
return time() + 0 ; |
1018
|
|
|
|
|
|
|
} else { |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
} |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
} |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
sub interval2time { |
1025
|
0
|
|
|
0
|
0
|
|
local $_ = shift @_ ; |
1026
|
0
|
|
|
|
|
|
my $t = 0 ; |
1027
|
0
|
|
|
|
|
|
foreach my $x ( /(\d+[wdhms])/g ) { |
1028
|
|
|
|
|
|
|
# XXX |
1029
|
|
|
|
|
|
|
# Would be nice to do this without two matches but |
1030
|
|
|
|
|
|
|
# /g only counts the first match not the pair. |
1031
|
0
|
|
|
|
|
|
my ($u, $b) = $x =~ /(\d+)([wdhms])/ ; |
1032
|
0
|
|
|
|
|
|
$t += T->{$b} * $u ; |
1033
|
|
|
|
|
|
|
} |
1034
|
|
|
|
|
|
|
|
1035
|
0
|
|
|
|
|
|
return $t ; |
1036
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
} |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
sub get_downs { |
1040
|
0
|
|
|
0
|
0
|
|
my $r = shift @_ ; |
1041
|
|
|
|
|
|
|
|
1042
|
0
|
|
|
|
|
|
my @downs = &down_records(@_) ; |
1043
|
0
|
|
|
|
|
|
my @r = map [ @$r, @$_ ], @downs ; |
1044
|
0
|
|
|
|
|
|
@r ; |
1045
|
|
|
|
|
|
|
} |
1046
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
sub avail { |
1048
|
0
|
|
|
0
|
1
|
|
my ($me, $rep_period) = @_ ; |
1049
|
0
|
|
0
|
|
|
|
$rep_period ||= '24x7' ; |
1050
|
0
|
0
|
|
|
|
|
die "Non existent report period '$rep_period': choose from " . join(' ', keys %{$me->{AVAIL_REPORTS}}) . '. Outahere.' |
|
0
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
unless exists $me->{AVAIL_REPORTS}{$rep_period} ; |
1052
|
|
|
|
|
|
|
|
1053
|
0
|
|
|
|
|
|
my @avail_recs = @{ $me->{AVAIL_REPORTS}{$rep_period} } ; |
|
0
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
return wantarray |
1055
|
|
|
|
|
|
|
? @avail_recs |
1056
|
0
|
0
|
|
0
|
|
|
: Iterator { shift @avail_recs ; } ; |
|
0
|
|
|
|
|
|
|
1057
|
|
|
|
|
|
|
} |
1058
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
sub report { |
1060
|
0
|
|
|
0
|
1
|
|
my ($me, $rep_period) = @_ ; |
1061
|
0
|
|
0
|
|
|
|
$rep_period ||= '24x7' ; |
1062
|
|
|
|
|
|
|
|
1063
|
0
|
0
|
|
|
|
|
die "Non existent report period '$rep_period': choose from " . join(' ', keys %{$me->{REPORTS}}) . '. Outahere.' |
|
0
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
unless exists $me->{REPORTS}{$rep_period} ; |
1065
|
|
|
|
|
|
|
|
1066
|
0
|
|
|
|
|
|
my @report_recs = @{ $me->{REPORTS}{$rep_period}{RECORDS} } ; |
|
0
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
return wantarray |
1068
|
|
|
|
|
|
|
? @report_recs |
1069
|
0
|
0
|
|
0
|
|
|
: Iterator { shift @report_recs ; } ; |
|
0
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
} |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
|
1073
|
|
|
|
|
|
|
sub to_dbh { |
1074
|
0
|
|
|
0
|
1
|
|
my $me = shift @_ ; |
1075
|
|
|
|
|
|
|
|
1076
|
0
|
|
|
|
|
|
eval { require DBI } ; |
|
0
|
|
|
|
|
|
|
1077
|
0
|
0
|
|
|
|
|
die "Jeff Zuckers's _excellent_ CPAN module, DBI is needed by to_dbh(). Outahere. " |
1078
|
|
|
|
|
|
|
if $@ ; |
1079
|
|
|
|
|
|
|
|
1080
|
0
|
|
|
|
|
|
my @dbh = () ; |
1081
|
|
|
|
|
|
|
# Fruitless attempts to silence DBI - |
1082
|
|
|
|
|
|
|
# this appears to be a known issue of DBD::AnyData |
1083
|
|
|
|
|
|
|
# as of Mar 2006. |
1084
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
# local $SIG{__WARN__} = sub {} ; |
1086
|
|
|
|
|
|
|
|
1087
|
0
|
|
|
|
|
|
foreach my $rep_period ( @{$me->REPORT_PERIODS} ) { |
|
0
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
|
1089
|
0
|
|
|
|
|
|
my $dbh = DBI->connect('dbi:AnyData:') ; |
1090
|
|
|
|
|
|
|
# my $dbh = DBI->connect('dbi:AnyData(Warn => 0, ... |
1091
|
|
|
|
|
|
|
# Also fails to check warnings. |
1092
|
0
|
|
|
|
|
|
$dbh->func( |
1093
|
|
|
|
|
|
|
"tab_${rep_period}", |
1094
|
|
|
|
|
|
|
'ARRAY', |
1095
|
|
|
|
|
|
|
$me->{AVAIL_REPORTS}{$rep_period}, |
1096
|
|
|
|
|
|
|
# [ $me->avail($rep_period) ], |
1097
|
0
|
|
|
|
|
|
{ col_names => join(',', @{$me->FIELDNAMES}) }, |
1098
|
|
|
|
|
|
|
'ad_import' |
1099
|
|
|
|
|
|
|
) ; |
1100
|
|
|
|
|
|
|
|
1101
|
0
|
|
|
|
|
|
push @dbh, $dbh ; |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
} |
1104
|
|
|
|
|
|
|
|
1105
|
0
|
|
|
|
|
|
@dbh ; |
1106
|
|
|
|
|
|
|
|
1107
|
|
|
|
|
|
|
} |
1108
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
sub add_chart { |
1110
|
0
|
|
|
0
|
0
|
|
my ($wkbook, $chart) = @_ ; |
1111
|
|
|
|
|
|
|
|
1112
|
0
|
0
|
|
|
|
|
die "add_chart() called without hash ref to chart details eg { template => '/path/to/chart/template', link => .. }. Outahere." |
1113
|
|
|
|
|
|
|
unless ref($chart) eq 'HASH' ; |
1114
|
|
|
|
|
|
|
|
1115
|
0
|
0
|
0
|
|
|
|
die "add_chart() called without a well formed 'template' value in \$chart_detail. Must be to a filename containing the Chart template. Outahere." |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1116
|
|
|
|
|
|
|
unless exists($chart->{template}) && $chart->{template} && -e $chart->{template} && -s $chart->{template} ; |
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
# Add some extra formats to cover formats used in the charts. |
1119
|
|
|
|
|
|
|
|
1120
|
0
|
|
|
|
|
|
$wkbook->add_format(color => 1, bold => 1); |
1121
|
0
|
|
|
|
|
|
$wkbook->add_format(color => 2); |
1122
|
0
|
|
|
|
|
|
$wkbook->add_format(color => 3); |
1123
|
|
|
|
|
|
|
|
1124
|
0
|
|
0
|
|
|
|
$chart->{title} ||= 'Chart 24x7' ; |
1125
|
0
|
|
0
|
|
|
|
$chart->{link} ||= '=24x7!A1' ; |
1126
|
|
|
|
|
|
|
|
1127
|
0
|
|
|
|
|
|
$wkbook->add_chart_ext($chart->{template}, $chart->{title}) ; |
1128
|
|
|
|
|
|
|
|
1129
|
0
|
|
|
|
|
|
$wkbook->sheets(0)->store_formula($chart->{link}) ; |
1130
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
} |
1132
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
1 ; |
1134
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
# ---> That's all folks <----- |
1136
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
=head1 NAME |
1138
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
Nagios::Report - Perl class to filter and munge Nagios availability data |
1140
|
|
|
|
|
|
|
|
1141
|
|
|
|
|
|
|
=head1 SYNOPSIS |
1142
|
|
|
|
|
|
|
|
1143
|
|
|
|
|
|
|
use Nagios::Report ; |
1144
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
my $x = Nagios::Report->new(q, [ '24x7' ], 'thismonth') |
1146
|
|
|
|
|
|
|
or die "Can't construct Nagios::Report object." ; |
1147
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
my @these_fields = qw( |
1149
|
|
|
|
|
|
|
HOST_NAME |
1150
|
|
|
|
|
|
|
PERCENT_TOTAL_TIME_UP |
1151
|
|
|
|
|
|
|
TOTAL_TIME_DOWN |
1152
|
|
|
|
|
|
|
TIME_DOWN_HHMMSS |
1153
|
|
|
|
|
|
|
TOTAL_TIME_UNREACHABLE |
1154
|
|
|
|
|
|
|
TIME_UNREACH_HHMMSS |
1155
|
|
|
|
|
|
|
AVAIL_URL |
1156
|
|
|
|
|
|
|
TREND_URL |
1157
|
|
|
|
|
|
|
) ; |
1158
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
$x->mkreport( |
1160
|
|
|
|
|
|
|
# Field selector; display these fields only (in the listed order) |
1161
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
# [] means display all the fields. |
1163
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
\@these_fields, |
1165
|
|
|
|
|
|
|
# Record selector |
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
# Called with @_ loaded # with a list of field names and |
1168
|
|
|
|
|
|
|
# their vals for this record. Usually copied to a hash |
1169
|
|
|
|
|
|
|
# so it can be used as one. |
1170
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
# All records |
1172
|
|
|
|
|
|
|
# sub { 1 }, |
1173
|
|
|
|
|
|
|
# All records whose HOST_NAME starts with 'Alb' |
1174
|
|
|
|
|
|
|
# sub { my %F = @_; my $h = $F{HOST_NAME}; $h =~ /^Alb/ }, |
1175
|
|
|
|
|
|
|
# Regrettably, this is _NOT_ the same since |
1176
|
|
|
|
|
|
|
# @_ can't be used as a hash. |
1177
|
|
|
|
|
|
|
# sub { $_{HOST_NAME} =~ /^Alb/ } |
1178
|
|
|
|
|
|
|
# All records with an up time percent < 98% |
1179
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
sub { my %F = @_; my $u = $F{PERCENT_TOTAL_TIME_UP}; $u =~ s/%//; $u < 98 }, |
1181
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
# Sort order |
1183
|
|
|
|
|
|
|
|
1184
|
|
|
|
|
|
|
&comp( alpha => 0, ascend => 0, fields => [ qw(TOTAL_TIME_DOWN TOTAL_TIME_UNREACHABLE) ]), |
1185
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
# Sorts descending by max of TOTAL_TIME_DOWN and TOTAL_TIME_UNREACHABLE |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
# DIY sorters remember that $a and $b _must_ be in Nagios::Report package. |
1189
|
|
|
|
|
|
|
# eg by TOTAL_DOWN_TIME descending. |
1190
|
|
|
|
|
|
|
# sub { my %f = @_ ; |
1191
|
|
|
|
|
|
|
# package Nagios::Report; |
1192
|
|
|
|
|
|
|
# $b->[$f{TOTAL_TIME_DOWN}] <=> $a->[$f{TOTAL_TIME_DOWN}] |
1193
|
|
|
|
|
|
|
# }, |
1194
|
|
|
|
|
|
|
# Same as |
1195
|
|
|
|
|
|
|
# &comp(alpha => 0, ascend => 0, fields => ['TOTAL_TIME_DOWN']) |
1196
|
|
|
|
|
|
|
# Same but harder, |
1197
|
|
|
|
|
|
|
# sub { package Nagios::Report; $b->[16] <=> $a->[16] }, |
1198
|
|
|
|
|
|
|
|
1199
|
|
|
|
|
|
|
# Optional callback to add or mangle fields. |
1200
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
# Add 2 fields for downtime vals in hours minutes and secs. |
1202
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
sub { $F = shift @_; |
1204
|
|
|
|
|
|
|
$F->{TIME_DOWN_HHMMSS} = t2hms( $F->{TOTAL_TIME_DOWN} ), |
1205
|
|
|
|
|
|
|
$F->{TIME_UNREACH_HHMMSS}= t2hms( $F->{TOTAL_TIME_UNREACHABLE} ) ; |
1206
|
|
|
|
|
|
|
qw(TIME_DOWN_HHMMSS TIME_UNREACH_HHMMSS) |
1207
|
|
|
|
|
|
|
} |
1208
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
) ; |
1210
|
|
|
|
|
|
|
|
1211
|
|
|
|
|
|
|
$x->debug_dump ; |
1212
|
|
|
|
|
|
|
# $x->csv_dump ; |
1213
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
=head1 DESCRIPTION |
1217
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
Gets the Nagios (http://wwww.Nagios.ORG/) B availability report (getting the results in CSV format) |
1219
|
|
|
|
|
|
|
and applies grep like filters, map like munging, and slice like field masks to produce a report which can be output in |
1220
|
|
|
|
|
|
|
various ways. |
1221
|
|
|
|
|
|
|
|
1222
|
|
|
|
|
|
|
This class provides extra control over the content and disposition of the data produced by the |
1223
|
|
|
|
|
|
|
Nagios availability CGI, by writing for example a spreadsheet containing the selected data. |
1224
|
|
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
Since the data originates from standard Nagios availability CGI, its results are no more accurate - and should be |
1226
|
|
|
|
|
|
|
exactly the same - as that CGI. |
1227
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
|
1229
|
|
|
|
|
|
|
=head1 METHODS |
1230
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
=over 4 |
1232
|
|
|
|
|
|
|
|
1233
|
|
|
|
|
|
|
=item * new (DATA_SOURCE, REPORT_PERIODS, TIME_PERIOD, HOST_OR_SERVICE, PRE_FILTER) |
1234
|
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
This is the constructor of the Nagios::Report object. |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
C is one of |
1239
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
1 local_cgi - get the data by running the availability report CGI on the local host. |
1241
|
|
|
|
|
|
|
Space separated values of the Nagios web server name/address and a Nagios user should follow. |
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
2 web_page - get the data with LYNX or WGET from the named web server with the credential. |
1244
|
|
|
|
|
|
|
Space separated values of the Nagios web server name/address, a Nagios user and that users password |
1245
|
|
|
|
|
|
|
should follow. |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
3 dev_debug - get __development__ data by running a client supplied callback. |
1248
|
|
|
|
|
|
|
The _name_ of the callback should follow the tag, separated by spaces. |
1249
|
|
|
|
|
|
|
NB the callback is assumed to be in the __main__ package. |
1250
|
|
|
|
|
|
|
The callback is expected to return a string consisting of a schema |
1251
|
|
|
|
|
|
|
(of CSV fieldnames) followed by lines of CSV data. |
1252
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
C is an optional reference to a list of names of Nagios time periods (conventionally defined in timeperiods.cfg) for which the availability data will be computed (by the CGI). |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
C is an optional specification of the interval containing eligible availability records. It is scalar whose value |
1256
|
|
|
|
|
|
|
is one of the Nagios interval names such as C, C, or B of the time forms used by the B command. |
1257
|
|
|
|
|
|
|
(These forms include HHMM, HH:MM, DD.MM.YYYY MM/DD/YYYY and 24hour-time date). It can also be a month abbreviation followed by |
1258
|
|
|
|
|
|
|
any amount of white space and an optional 4 digit year. This form, like Mar 2006, selects all the days in that month. If the year |
1259
|
|
|
|
|
|
|
is missing, the month refers to this year. |
1260
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
Usually the timeperiod specifies an interval from some time in the past to now from which availability data will be selected. |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
|
1265
|
|
|
|
|
|
|
However, if the argument is of the form B B<-> B, the availability data will be extracted from |
1266
|
|
|
|
|
|
|
the corresponding interval. |
1267
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
|
1269
|
|
|
|
|
|
|
If this argument is omitted, the report is compiled for the B time period (ie any host availability record from the first of the current |
1270
|
|
|
|
|
|
|
month to the current time). |
1271
|
|
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
C is an optional scalar specifying the service report instead of the host report. If not set, the host |
1273
|
|
|
|
|
|
|
report is produced. |
1274
|
|
|
|
|
|
|
|
1275
|
|
|
|
|
|
|
C is a callback that is called with the B<%F> hash (vi) set to the values of the field names for this availability |
1276
|
|
|
|
|
|
|
record. The constructor saves the availability report for B the hosts and therefore if mkreport() then |
1277
|
|
|
|
|
|
|
requests the down records (vi), the availability CGI will be run for every host, whether or not the |
1278
|
|
|
|
|
|
|
filter in mkreport() actually selects them. To eliminate this waste and speed up the report, supply a callback like |
1279
|
|
|
|
|
|
|
sub { my %F = @_; $u = $F{PERCENT_TOTAL_TIME_UP}; $u =~ s/%//; $u < 99 } or |
1280
|
|
|
|
|
|
|
sub { my %F = @_; $F{TOTAL_TIME_DOWN} >= 600 } |
1281
|
|
|
|
|
|
|
|
1282
|
|
|
|
|
|
|
The constructor gets the Nagios availability data by running the all hosts or all services report (in CSV format) |
1283
|
|
|
|
|
|
|
and storing it in the object. |
1284
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
=item * mkreport (FIELD_LIST, SELECTOR_CALLBACK, ORDER_CALLBACK, MUNGE_CALLBACK, DOWNS) |
1286
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
E<10> |
1288
|
|
|
|
|
|
|
C is a reference to an array containing the field names that will appear in the report (a logical slice of the reports fields). |
1289
|
|
|
|
|
|
|
The fields appear in the report in the same order they have in this list. Fields added by C B be specified |
1290
|
|
|
|
|
|
|
by C or they will not be shown in the report B this parameter is omitted. If the C is omitted, |
1291
|
|
|
|
|
|
|
B the fields appear in the report, no matter where they come from (ie if fields are added by the C, the |
1292
|
|
|
|
|
|
|
new fields will appear in the report). If a field in C does not exist in the schema, it will not |
1293
|
|
|
|
|
|
|
appear in the report; the caller B spell the field names correctly. |
1294
|
|
|
|
|
|
|
|
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
C is a reference to a user supplied subroutine that will return B if the record is to be included in the report. |
1297
|
|
|
|
|
|
|
The subroutine is called with an argument list of field names and their values for this record. This argument list |
1298
|
|
|
|
|
|
|
can be copied to a hash in the callback, conventionally named B<%F>, so that the field names can be used in expressions like |
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
$F{HOST_NAME} =~ /^foo/ |
1301
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
to select eligible records. |
1303
|
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
C is a reference to a user supplied sort subroutine that determines the order of the records in the report. The |
1305
|
|
|
|
|
|
|
subroutine is called with an argument list of field names and their offsets in the records (eg (HOST_NAME, 0)). This argument list |
1306
|
|
|
|
|
|
|
can be copied to a hash in the callback, conventionally named B<%f>, so that the field names can be used in expressions like |
1307
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
$a->[$f{TOTAL_TIME_DOWN}] <=> $b->[$f{TOTAL_TIME_DOWN}] |
1309
|
|
|
|
|
|
|
|
1310
|
|
|
|
|
|
|
to sort the records based on the field values. |
1311
|
|
|
|
|
|
|
|
1312
|
|
|
|
|
|
|
C is a reference to a user supplied subroutine that is used to munge (transform input to output) the records. The subroutine |
1313
|
|
|
|
|
|
|
is called with a pointer to a hash of field names and their values for this record. The callback is expected to modify the record |
1314
|
|
|
|
|
|
|
by setting the values of this hash, munging fields with expressions like |
1315
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
$F->{TOTAL_TIME_DOWN} = 0 |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
If the callback adds fields to the record, it should add the new field value in the same way (by setting a value for |
1319
|
|
|
|
|
|
|
a new key in the hash, like for example, |
1320
|
|
|
|
|
|
|
|
1321
|
|
|
|
|
|
|
$F->{TOTAL_TIME_DOWN_HMS} = t2hms($F->{TOTAL_TIME_DOWN}) |
1322
|
|
|
|
|
|
|
|
1323
|
|
|
|
|
|
|
). |
1324
|
|
|
|
|
|
|
|
1325
|
|
|
|
|
|
|
If the callback adds no fields (modifies values only), it B return an empty list. |
1326
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
A complete callback to set TOTAL_TIME_DOWN to zero is therefore |
1328
|
|
|
|
|
|
|
|
1329
|
|
|
|
|
|
|
sub { |
1330
|
|
|
|
|
|
|
my $F = shift @_; |
1331
|
|
|
|
|
|
|
$F->{TOTAL_TIME_DOWN} = 0; |
1332
|
|
|
|
|
|
|
() |
1333
|
|
|
|
|
|
|
} |
1334
|
|
|
|
|
|
|
|
1335
|
|
|
|
|
|
|
mkreport() takes the availability data for each time period, adds outage data (which involves duplicating the |
1336
|
|
|
|
|
|
|
C availability record as many times as there are outages), does any specified munging, applies the filter discarding |
1337
|
|
|
|
|
|
|
records not rated as C by the selector callback, before sorting and |
1338
|
|
|
|
|
|
|
slicing the results - dropping fields unwanted fields - and storing them as a C for each time period. |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
mkreport() must be run before any of the output methods. |
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
C is an optional scalar flag. If the flag is set the availability |
1343
|
|
|
|
|
|
|
report - the detailed report with the outage log - for B host is fetched and the outage records extracted. |
1344
|
|
|
|
|
|
|
|
1345
|
|
|
|
|
|
|
Then, for each of the outage records, the availability record is duplicated followed by the outage data: when the host went down, when |
1346
|
|
|
|
|
|
|
it came back up, and the hours minutes seconds formatted value of the outage. These fields are named DOWN, UP, and OUTAGE. |
1347
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
Since the availability data is repeated for each outage record, C can make the report look messy. It is best used |
1349
|
|
|
|
|
|
|
with a small number of report fields (eg HOST_NAME, PERCENT_TOTAL_UP_TIME). Also, since the outage records are added B |
1350
|
|
|
|
|
|
|
filtering by the selector callback, you B set a pre-filter in the constructor. |
1351
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
|
1353
|
|
|
|
|
|
|
The callbacks are run in this order |
1354
|
|
|
|
|
|
|
|
1355
|
|
|
|
|
|
|
=over 4 |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
=item 1 DOWNS (the availability report is retrieved for B hosts/services so that the selector |
1358
|
|
|
|
|
|
|
can filter on the added fields, by for example, discarding all records with small outages). |
1359
|
|
|
|
|
|
|
|
1360
|
|
|
|
|
|
|
=item 2 MUNGE_CALLBACK |
1361
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
=item 3 SELECTOR_CALLBACK |
1363
|
|
|
|
|
|
|
|
1364
|
|
|
|
|
|
|
=item 4 ORDER_CALLBACK |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
=item 5 the field slice (ie discard all but the FIELD_LIST fields) |
1367
|
|
|
|
|
|
|
|
1368
|
|
|
|
|
|
|
=back |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
=item * to_dbh |
1371
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
If the DBD::AnyData module is installed, returns an array of DBI data handles |
1373
|
|
|
|
|
|
|
connected to the pseudo-databases containing one table populated |
1374
|
|
|
|
|
|
|
with the availability data corresponding to each of the REPORT_PERIODS |
1375
|
|
|
|
|
|
|
specified in the constructor call. |
1376
|
|
|
|
|
|
|
|
1377
|
|
|
|
|
|
|
Each table is named C. For example, after constructing the |
1378
|
|
|
|
|
|
|
Nagios::Report object with the default report period, the table is named B. |
1379
|
|
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
This method allows the use of SQL statements as an alternative means of filtering |
1381
|
|
|
|
|
|
|
and modifying the data. For example, |
1382
|
|
|
|
|
|
|
|
1383
|
|
|
|
|
|
|
$SQL =<
|
1384
|
|
|
|
|
|
|
SELECT host_name, |
1385
|
|
|
|
|
|
|
total_time_down, |
1386
|
|
|
|
|
|
|
time_down_scheduled, |
1387
|
|
|
|
|
|
|
time_down_unscheduled, |
1388
|
|
|
|
|
|
|
FROM tab_24x7 |
1389
|
|
|
|
|
|
|
WHERE total_time_down >= 300 |
1390
|
|
|
|
|
|
|
SQL |
1391
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
$x = Nagios::Report->new(local_cgi Nagios-server Nagios-contact) ; |
1393
|
|
|
|
|
|
|
($d) = $x->to_dbh ; |
1394
|
|
|
|
|
|
|
$s = $d->prepare($SQL) ; |
1395
|
|
|
|
|
|
|
$s->execute ; |
1396
|
|
|
|
|
|
|
$s->dump_results ; |
1397
|
|
|
|
|
|
|
|
1398
|
|
|
|
|
|
|
Unfortunately, the use of DBD::AnyData does not invalidate this module because |
1399
|
|
|
|
|
|
|
the SQL grammar implemented by SQL::Statement (and used by DBD::AnyData) is not as |
1400
|
|
|
|
|
|
|
extensive as the SQL grammar provided by an RDBMS, or as useful as the record selector |
1401
|
|
|
|
|
|
|
mechanism provided by this. |
1402
|
|
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
If one is determined to process with SELECT, load the data into an RDBMS of choice ( |
1404
|
|
|
|
|
|
|
MySQL comes to mind) and use the corresponding Perl DBD module on that. There is an example of |
1405
|
|
|
|
|
|
|
a script to do so included in the distribution. |
1406
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
Also, as of version 0.002, there were noisy complaints from DBI when DBD::AnyData |
1408
|
|
|
|
|
|
|
processes SQL. |
1409
|
|
|
|
|
|
|
|
1410
|
|
|
|
|
|
|
=item * excel_dump (EXCEL_FILENAME, CHART_DETAIL) |
1411
|
|
|
|
|
|
|
|
1412
|
|
|
|
|
|
|
excel_dump writes a Workbook in the specified filename. The workbook contains a worksheet for each report (ie one for each time period |
1413
|
|
|
|
|
|
|
specified by the constructor). excel_dump() requires the John McNamara's B CPAN module, Spreadsheet::WriteExcel. |
1414
|
|
|
|
|
|
|
|
1415
|
|
|
|
|
|
|
E<10> |
1416
|
|
|
|
|
|
|
C is the path of the file in which the Excel workbook will be written. |
1417
|
|
|
|
|
|
|
|
1418
|
|
|
|
|
|
|
C is an optional reference to a hash that specifies the details of an Excel Chart that will be linked to the |
1419
|
|
|
|
|
|
|
data from the report. |
1420
|
|
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
The keys of his hash are |
1422
|
|
|
|
|
|
|
|
1423
|
|
|
|
|
|
|
E<10> |
1424
|
|
|
|
|
|
|
template - the path to a binary file, produced by the Spreadsheet::WriteExcel chartex utility, containing the |
1425
|
|
|
|
|
|
|
chart to be linked to the data. |
1426
|
|
|
|
|
|
|
|
1427
|
|
|
|
|
|
|
link - an optional scalar that specifies the data to be linked to the chart. Defaults to "q<'24x7'!A1>". |
1428
|
|
|
|
|
|
|
You almost certainly will need to change this. |
1429
|
|
|
|
|
|
|
|
1430
|
|
|
|
|
|
|
title - an optional scalar that specifies the name of the chart to be added to the workbook. Defaults to '24x7 Chart'. |
1431
|
|
|
|
|
|
|
|
1432
|
|
|
|
|
|
|
Note that only one chart can be added to a workbook (by this module). |
1433
|
|
|
|
|
|
|
|
1434
|
|
|
|
|
|
|
=item * csv_dump |
1435
|
|
|
|
|
|
|
|
1436
|
|
|
|
|
|
|
CSV formatted output on STDOUT. Note that this mainly useful for debugging since the |
1437
|
|
|
|
|
|
|
cell data is not formatted should it be imported by Excel |
1438
|
|
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
=item * dev_debug (FIELD_WIDTH, FIELDS_PER_LINE) |
1440
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
report formatted output on STDOUT. |
1442
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
=head1 ACCESSORS/MUTATORS |
1444
|
|
|
|
|
|
|
|
1445
|
|
|
|
|
|
|
Acessors and mutators are provided for most of the attributes in the object. The module makes B |
1446
|
|
|
|
|
|
|
use of them and, except for those below, are probably of little interest. Unless noted, the caller is |
1447
|
|
|
|
|
|
|
responsible for processing the attribute type correctly; the acessor does nothing more |
1448
|
|
|
|
|
|
|
than hand back a ref. |
1449
|
|
|
|
|
|
|
|
1450
|
|
|
|
|
|
|
=over 4 |
1451
|
|
|
|
|
|
|
|
1452
|
|
|
|
|
|
|
=item * report (REPORT_PERIOD) |
1453
|
|
|
|
|
|
|
|
1454
|
|
|
|
|
|
|
Accessor that returns, in scalar context, an iterator that when kicked returns each of the |
1455
|
|
|
|
|
|
|
records produced by mkreport() for that report period; in array context, returns the list of those records. |
1456
|
|
|
|
|
|
|
|
1457
|
|
|
|
|
|
|
Note that the 'records' are refs to anonymous lists containing only those fields specified by the field list parameter of |
1458
|
|
|
|
|
|
|
mkreport(). |
1459
|
|
|
|
|
|
|
|
1460
|
|
|
|
|
|
|
=item * avail (REPORT_PERIOD) |
1461
|
|
|
|
|
|
|
|
1462
|
|
|
|
|
|
|
Accessor that returns, in scalar context, an iterator that when kicked returns each of the |
1463
|
|
|
|
|
|
|
records returned by the constructor; in array context, returns the list of those records. |
1464
|
|
|
|
|
|
|
Note that the 'records' are refs to anonymous lists containing all of the Nagios availability report fields |
1465
|
|
|
|
|
|
|
augmented by the two extra fields AVAIL_URL and TREND_URL (vi). |
1466
|
|
|
|
|
|
|
|
1467
|
|
|
|
|
|
|
The iterator is a code ref that, when called, will return a ref to the next |
1468
|
|
|
|
|
|
|
availability record. Without a REPORT_PERIOD, |
1469
|
|
|
|
|
|
|
returns an iterator to the B<24x7> data, otherwise the availability data corresponding |
1470
|
|
|
|
|
|
|
to that report period (if it exists). If the methods of this class are not |
1471
|
|
|
|
|
|
|
useful, then the iterator allows the caller transform the availability data with |
1472
|
|
|
|
|
|
|
B and filter it with B. |
1473
|
|
|
|
|
|
|
|
1474
|
|
|
|
|
|
|
=item * FIELDNAMES |
1475
|
|
|
|
|
|
|
|
1476
|
|
|
|
|
|
|
Ref to a list of field names eg @fields = @{$me->FIELDNAMES} |
1477
|
|
|
|
|
|
|
|
1478
|
|
|
|
|
|
|
=item * FIELDS |
1479
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
Ref to a hash of field indices keyed by field name eg %f = %{$me->FIELDS}} |
1481
|
|
|
|
|
|
|
|
1482
|
|
|
|
|
|
|
=item * SERVER |
1483
|
|
|
|
|
|
|
|
1484
|
|
|
|
|
|
|
Hostname of the server on which the Nagios CGIs can be found. |
1485
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
=item * SOURCE_TAG |
1487
|
|
|
|
|
|
|
|
1488
|
|
|
|
|
|
|
How the availability data will be fetched. |
1489
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
=item * REPORT_TYPE |
1491
|
|
|
|
|
|
|
|
1492
|
|
|
|
|
|
|
host | service report |
1493
|
|
|
|
|
|
|
|
1494
|
|
|
|
|
|
|
=item * DATA_SOURCE |
1495
|
|
|
|
|
|
|
|
1496
|
|
|
|
|
|
|
Reference to a subroutine that will fetch the availability data. |
1497
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
=item * REPORTS |
1499
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
Ref to a hash keyed by report period containing a hash keyed by FIELDNAMES and RECORDS. |
1501
|
|
|
|
|
|
|
The latter key refers to a list containing the records selected and munged by mkreport(). |
1502
|
|
|
|
|
|
|
Note that each record contains only those fields specified by the field list parm of |
1503
|
|
|
|
|
|
|
mkreport(). |
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
See report (REPORT_PERIOD). |
1506
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
=item * AVAIL_REPORTS |
1508
|
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
Ref to a hash keyed by report period containing a ref to a list containing all |
1510
|
|
|
|
|
|
|
those records returned by the Nagios availability report that are accepted by the |
1511
|
|
|
|
|
|
|
pre-filter. |
1512
|
|
|
|
|
|
|
|
1513
|
|
|
|
|
|
|
Unlike REPORTS, each record contains all the Nagios reporting fields including |
1514
|
|
|
|
|
|
|
the fields AVAIL_URL and TREND_URL whose values are hyperlinks to the Nagios |
1515
|
|
|
|
|
|
|
trend and availability reports for the host named HOST_NAME. |
1516
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
|
1518
|
|
|
|
|
|
|
See avail (REPORT_PERIOD). |
1519
|
|
|
|
|
|
|
|
1520
|
|
|
|
|
|
|
=back |
1521
|
|
|
|
|
|
|
|
1522
|
|
|
|
|
|
|
=head1 SUBROUTINES |
1523
|
|
|
|
|
|
|
|
1524
|
|
|
|
|
|
|
=over 4 |
1525
|
|
|
|
|
|
|
|
1526
|
|
|
|
|
|
|
=item * max_l ( LIST_OF_NUMERIC_VALS) |
1527
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
Returns the maximum value in the list. Does not handle non-numeric values. |
1529
|
|
|
|
|
|
|
|
1530
|
|
|
|
|
|
|
=item * comp ( OPTION_HASH ) |
1531
|
|
|
|
|
|
|
|
1532
|
|
|
|
|
|
|
Returns a ref to a comparator function that determines the order of the records and can be used |
1533
|
|
|
|
|
|
|
as the B argument of B. |
1534
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
C is an B hash with keys |
1536
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
C Sort by the HOST_NAME field if set, otherwise by the maximum of the fields value. |
1538
|
|
|
|
|
|
|
|
1539
|
|
|
|
|
|
|
C Sort in ascending order if set. |
1540
|
|
|
|
|
|
|
|
1541
|
|
|
|
|
|
|
C The comparator function orders the records based on the B of the B field values. Only applies if alpha |
1542
|
|
|
|
|
|
|
is not set. C is a reference to an array of numeric field names. |
1543
|
|
|
|
|
|
|
|
1544
|
|
|
|
|
|
|
eg &comp( alpha => 1, ascend => 1 ) |
1545
|
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
Returns a ref to function that orders the records by the HOST_NAME field. |
1547
|
|
|
|
|
|
|
|
1548
|
|
|
|
|
|
|
eg &comp() |
1549
|
|
|
|
|
|
|
|
1550
|
|
|
|
|
|
|
Same as calling comp with ( alpha => 1, ascend => 1 ) |
1551
|
|
|
|
|
|
|
|
1552
|
|
|
|
|
|
|
eg &comp( alpha => 0, ascend => 1, fields => [TOTAL_TIME_DOWN, TOTAL_TIME_UNREACHABLE] ) |
1553
|
|
|
|
|
|
|
|
1554
|
|
|
|
|
|
|
Returns a ref to a function that orders the records by the maximum of the values of the |
1555
|
|
|
|
|
|
|
TOTAL_TIME_DOWN and TOTAL_TIME_UNREACHABLE fields. |
1556
|
|
|
|
|
|
|
|
1557
|
|
|
|
|
|
|
|
1558
|
|
|
|
|
|
|
=item * t2hms (TIME_T) |
1559
|
|
|
|
|
|
|
|
1560
|
|
|
|
|
|
|
Returns the argument formatted by weeks, days, hours, minutes and seconds eg &t2hms(300) -> 5m. |
1561
|
|
|
|
|
|
|
|
1562
|
|
|
|
|
|
|
=item * d2t (time_string) |
1563
|
|
|
|
|
|
|
|
1564
|
|
|
|
|
|
|
Returns the time_t value of the string formatted as either a localtime, US (MM-DD-YYYY) or EURO date (DD-MM-YYY). |
1565
|
|
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
=item * i2t (interval) |
1567
|
|
|
|
|
|
|
|
1568
|
|
|
|
|
|
|
Returns the time_t value of the string formatted as an interval of time ie one that matches (?:\d+[wdhms]\s*)+ |
1569
|
|
|
|
|
|
|
eg 3h 5m 30s (3 hours 5 minutes and 30 seconds). |
1570
|
|
|
|
|
|
|
|
1571
|
|
|
|
|
|
|
=item * $st_et{TAG}->(TAG, [ STRUCT TM ] ) |
1572
|
|
|
|
|
|
|
|
1573
|
|
|
|
|
|
|
A hash of code refs indexed by an interval selecting tag. The second optinal argument is a ref to |
1574
|
|
|
|
|
|
|
a STRUCT TM. If this arg is missing, [localtime] is used. |
1575
|
|
|
|
|
|
|
|
1576
|
|
|
|
|
|
|
Returns the pair of time_ts bounding the interval named by the tag. The |
1577
|
|
|
|
|
|
|
upper boundary of the interval is usually the time_t value corresponding to the second argument. The lower boundary is this less |
1578
|
|
|
|
|
|
|
the tags value. |
1579
|
|
|
|
|
|
|
|
1580
|
|
|
|
|
|
|
Tags include last_n_days, last_n_hours, last_n_mins, thisweek, lastweek, thismonth, lastmonth, thisyear, lastyear and variable strings like the 'at' style time stamps such as 'MMM YYYY' (eg Mar 2006) or HHMM DD.MM.YYYY. When the tag represents a fixed date or time, the interval |
1581
|
|
|
|
|
|
|
returned is from 'then' to 'now'. |
1582
|
|
|
|
|
|
|
|
1583
|
|
|
|
|
|
|
When called by this module, the second argument is always 'now' (ie [localtime]). |
1584
|
|
|
|
|
|
|
eg join('-', map { scalar(localtime($_)) } $st_et{today}->('today') eq 'Fri Aug 18 00:00:00 2006-Fri Aug 18 10:13:00 2006' |
1585
|
|
|
|
|
|
|
eg join('-', map { scalar(localtime($_)) } $st_et{today}->('today', [ 0, 0, 0, 18, 7, 106])) eq 'Fri Aug 18 00:00:00 2006-Fri Aug 18 10:13:00 2006' |
1586
|
|
|
|
|
|
|
|
1587
|
|
|
|
|
|
|
|
1588
|
|
|
|
|
|
|
|
1589
|
|
|
|
|
|
|
=back |
1590
|
|
|
|
|
|
|
|
1591
|
|
|
|
|
|
|
=head1 BUGS |
1592
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
=over 4 |
1594
|
|
|
|
|
|
|
|
1595
|
|
|
|
|
|
|
=item * Does not do much more than the standard availability CGI. The reports |
1596
|
|
|
|
|
|
|
has the same bugs as those produced by the CGI. |
1597
|
|
|
|
|
|
|
|
1598
|
|
|
|
|
|
|
=item * The B subroutine does not behave well if called with fields whose values are non numeric. |
1599
|
|
|
|
|
|
|
|
1600
|
|
|
|
|
|
|
=item * The hand done date and time functions are poor. |
1601
|
|
|
|
|
|
|
|
1602
|
|
|
|
|
|
|
=item * Anything good in this module comes from B; the rest comes from the author. |
1603
|
|
|
|
|
|
|
|
1604
|
|
|
|
|
|
|
=item * The module does not buy much more than rolling ones own with DBD::AnyData. Had I been more |
1605
|
|
|
|
|
|
|
aware of the fundamental utility and importance of RDBMS data, this module would probably |
1606
|
|
|
|
|
|
|
not exist. OTOH, this module now provides some sort of programmatic access to Nagios availability |
1607
|
|
|
|
|
|
|
data that Nagios has not had (AFAIK) hitherto. |
1608
|
|
|
|
|
|
|
|
1609
|
|
|
|
|
|
|
=back |
1610
|
|
|
|
|
|
|
|
1611
|
|
|
|
|
|
|
|
1612
|
|
|
|
|
|
|
=head1 SEE ALSO |
1613
|
|
|
|
|
|
|
|
1614
|
|
|
|
|
|
|
perl(1). |
1615
|
|
|
|
|
|
|
|
1616
|
|
|
|
|
|
|
Nagios (http://www.Nagios.ORG/) |
1617
|
|
|
|
|
|
|
|
1618
|
|
|
|
|
|
|
|
1619
|
|
|
|
|
|
|
=head1 AUTHOR |
1620
|
|
|
|
|
|
|
|
1621
|
|
|
|
|
|
|
Stanley Hopcroft |
1622
|
|
|
|
|
|
|
|
1623
|
|
|
|
|
|
|
=head1 COPYRIGHT |
1624
|
|
|
|
|
|
|
|
1625
|
|
|
|
|
|
|
Copyright (c) 2006 Stanley Hopcroft. All rights reserved. |
1626
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify |
1627
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
1628
|
|
|
|
|
|
|
|
1629
|
|
|
|
|
|
|
=cut |
1630
|
|
|
|
|
|
|
|
1631
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
|