summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins-scripts/Makefile.am2
-rwxr-xr-xplugins-scripts/check_uptime.pl315
-rw-r--r--plugins-scripts/t/check_uptime.t129
3 files changed, 446 insertions, 0 deletions
diff --git a/plugins-scripts/Makefile.am b/plugins-scripts/Makefile.am
index ea65aed..088a445 100644
--- a/plugins-scripts/Makefile.am
+++ b/plugins-scripts/Makefile.am
@@ -16,11 +16,13 @@ VPATH=$(top_srcdir) $(top_srcdir)/plugins-scripts $(top_srcdir)/plugins-scripts/
16libexec_SCRIPTS = check_breeze check_disk_smb check_flexlm check_ircd \ 16libexec_SCRIPTS = check_breeze check_disk_smb check_flexlm check_ircd \
17 check_log check_oracle check_rpc check_sensors check_wave \ 17 check_log check_oracle check_rpc check_sensors check_wave \
18 check_ifstatus check_ifoperstatus check_mailq check_file_age \ 18 check_ifstatus check_ifoperstatus check_mailq check_file_age \
19 check_uptime \
19 utils.sh utils.pm 20 utils.sh utils.pm
20 21
21EXTRA_DIST=check_breeze.pl check_disk_smb.pl check_flexlm.pl check_ircd.pl \ 22EXTRA_DIST=check_breeze.pl check_disk_smb.pl check_flexlm.pl check_ircd.pl \
22 check_log.sh check_oracle.sh check_rpc.pl check_sensors.sh \ 23 check_log.sh check_oracle.sh check_rpc.pl check_sensors.sh \
23 check_ifstatus.pl check_ifoperstatus.pl check_wave.pl check_mailq.pl check_file_age.pl \ 24 check_ifstatus.pl check_ifoperstatus.pl check_wave.pl check_mailq.pl check_file_age.pl \
25 check_uptime.pl \
24 utils.sh.in utils.pm.in t 26 utils.sh.in utils.pm.in t
25 27
26EDIT = sed \ 28EDIT = sed \
diff --git a/plugins-scripts/check_uptime.pl b/plugins-scripts/check_uptime.pl
new file mode 100755
index 0000000..4c9f22d
--- /dev/null
+++ b/plugins-scripts/check_uptime.pl
@@ -0,0 +1,315 @@
1#!@PERL@ -w
2
3# check_uptime - check uptime to see how long the system is running.
4#
5
6# License Information:
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
20# USA
21#
22############################################################################
23
24use POSIX;
25use strict;
26use Getopt::Long;
27use vars qw($opt_V $opt_h $opt_v $verbose $PROGNAME $opt_w $opt_c
28 $opt_f $opt_s
29 $lower_warn_threshold $upper_warn_threshold
30 $lower_crit_threshold $upper_crit_threshold
31 $status $state $msg);
32use FindBin;
33use lib "$FindBin::Bin";
34use utils qw(%ERRORS &print_revision &support &usage );
35
36sub print_help ();
37sub print_usage ();
38sub process_arguments ();
39
40$ENV{'PATH'}='@TRUSTED_PATH@';
41$ENV{'BASH_ENV'}='';
42$ENV{'ENV'}='';
43$PROGNAME = "check_uptime";
44$state = $ERRORS{'UNKNOWN'};
45
46my $uptime_file = "/proc/uptime";
47
48
49# Process arguments
50
51Getopt::Long::Configure('bundling');
52$status = process_arguments();
53if ($status){
54 print "ERROR: processing arguments\n";
55 exit $ERRORS{"UNKNOWN"};
56}
57
58
59# Get uptime info from file
60
61if ( ! -r $uptime_file ) {
62 print "ERROR: file '$uptime_file' is not readable\n";
63 exit $ERRORS{"UNKNOWN"};
64}
65
66if ( ! open FILE, "<", $uptime_file ) {
67 print "ERROR: cannot read from file '$uptime_file'\n";
68 exit $ERRORS{"UNKNOWN"};
69}
70
71chomp( my $file_content = <FILE> );
72close FILE;
73
74print "$uptime_file: $file_content\n" if $verbose;
75
76# Get first digit value (without fraction)
77my ( $uptime_seconds ) = $file_content =~ /^([\d]+)/;
78
79# Bail out if value is not numeric
80if ( $uptime_seconds !~ /^\d+$/ ) {
81 print "ERROR: no numeric value: $uptime_seconds\n";
82 exit $ERRORS{"UNKNOWN"};
83}
84
85
86# Do calculations for a "pretty" format (2 weeks, 5 days, ...)
87
88my ( $secs, $mins, $hours, $days, $weeks );
89$secs = $uptime_seconds;
90$mins = $hours = $days = $weeks = 0;
91if ( $secs > 100 ) {
92 $mins = int( $secs / 60 );
93 $secs -= $mins * 60;
94}
95if ( $mins > 100 ) {
96 $hours = int( $mins / 60 );
97 $mins -= $hours * 60;
98}
99if ( $hours > 48 ) {
100 $days = int( $hours / 24 );
101 $hours -= $days * 24;
102}
103if ( $days > 14 ) {
104 $weeks = int( $days / 7 );
105 $days -= $weeks * 7;
106}
107
108my $pretty_uptime = "";
109$pretty_uptime .= sprintf( "%d week%s, ", $weeks, $weeks == 1 ? "" : "s" ) if $weeks;
110$pretty_uptime .= sprintf( "%d day%s, ", $days, $days == 1 ? "" : "s" ) if $days;
111$pretty_uptime .= sprintf( "%d hour%s, ", $hours, $hours == 1 ? "" : "s" ) if $hours;
112$pretty_uptime .= sprintf( "%d minute%s, ", $mins, $mins == 1 ? "" : "s" ) if $mins;
113# Replace last occurence of comma with "and"
114$pretty_uptime =~ s/, $/ and /;
115# Always print the seconds (though it may be 0 seconds)
116$pretty_uptime .= sprintf( "%d second%s", $secs, $secs == 1 ? "" : "s" );
117
118
119# Default to catch errors in program
120my $state_str = "UNKNOWN";
121
122# Check values
123my $out_of_bounds_text = "";
124if ( $uptime_seconds > $upper_crit_threshold ) {
125 $state_str = "CRITICAL";
126 $out_of_bounds_text = "upper crit";
127} elsif ( $uptime_seconds < $lower_crit_threshold ) {
128 $state_str = "CRITICAL";
129 $out_of_bounds_text = "lower crit";
130} elsif ( $uptime_seconds > $upper_warn_threshold ) {
131 $state_str = "WARNING";
132 $out_of_bounds_text = "upper warn";
133} elsif ( $uptime_seconds < $lower_warn_threshold ) {
134 $state_str = "WARNING";
135 $out_of_bounds_text = "lower warn";
136} else {
137 $state_str = "OK";
138}
139
140$msg = "$state_str: ";
141
142$msg .= "uptime is $uptime_seconds seconds. ";
143$msg .= "Exceeds $out_of_bounds_text threshold. " if $out_of_bounds_text;
144$msg .= "Running for $pretty_uptime. " if $opt_f;
145if ( $opt_s ) {
146 my $up_since = strftime( "%Y-%m-%d %H:%M:%S", localtime( time - $uptime_seconds ) );
147 $msg .= "Running since $up_since. ";
148}
149
150$state = $ERRORS{$state_str};
151
152# Perfdata support
153print "$msg|uptime=${uptime_seconds}s;$upper_warn_threshold;$upper_crit_threshold;0\n";
154exit $state;
155
156
157#####################################
158#### subs
159
160
161sub process_arguments(){
162 GetOptions
163 ("V" => \$opt_V, "version" => \$opt_V,
164 "v" => \$opt_v, "verbose" => \$opt_v,
165 "h" => \$opt_h, "help" => \$opt_h,
166 "w=s" => \$opt_w, "warning=s" => \$opt_w, # warning if above this number
167 "c=s" => \$opt_c, "critical=s" => \$opt_c, # critical if above this number
168 "f" => \$opt_f, "for" => \$opt_f, # show "running for ..."
169 "s" => \$opt_s, "since" => \$opt_s, # show "running since ..."
170 );
171
172 if ($opt_V) {
173 print_revision($PROGNAME,'@NP_VERSION@');
174 exit $ERRORS{'UNKNOWN'};
175 }
176
177 if ($opt_h) {
178 print_help();
179 exit $ERRORS{'UNKNOWN'};
180 }
181
182 if (defined $opt_v) {
183 $verbose = $opt_v;
184 }
185
186 unless ( defined $opt_w && defined $opt_c ) {
187 print_usage();
188 exit $ERRORS{'UNKNOWN'};
189 }
190
191 # Check if a range was supplied ("lowvalue:highvalue") for warning and critical
192 # Otherwise, set 0 as the lower threshold and the parameter value as upper threshold
193 # (the uptime should always be positive, so there should be no issue)
194 if ( $opt_w =~ /^(.+):(.+)$/ ) {
195 $lower_warn_threshold = $1;
196 $upper_warn_threshold = $2;
197 } else {
198 $lower_warn_threshold = 0;
199 $upper_warn_threshold = $opt_w;
200 }
201 if ( $opt_c =~ /^(.+):(.+)$/ ) {
202 $lower_crit_threshold = $1;
203 $upper_crit_threshold = $2;
204 } else {
205 $lower_crit_threshold = 0;
206 $upper_crit_threshold = $opt_c;
207 }
208
209 # Set as seconds (calculate if suffix present)
210 $lower_warn_threshold = calc_as_seconds( $lower_warn_threshold );
211 $lower_crit_threshold = calc_as_seconds( $lower_crit_threshold );
212 $upper_warn_threshold = calc_as_seconds( $upper_warn_threshold );
213 $upper_crit_threshold = calc_as_seconds( $upper_crit_threshold );
214
215 # Check for numeric value of warning parameter
216 if ( $lower_warn_threshold !~ /^\d+$/ ) {
217 print "Lower warning (-w) is not numeric\n";
218 exit $ERRORS{'UNKNOWN'};
219 }
220 if ( $upper_warn_threshold !~ /^\d+$/ ) {
221 print "Upper warning (-w) is not numeric\n";
222 exit $ERRORS{'UNKNOWN'};
223 }
224 # Check for numeric value of critical parameter
225 if ( $lower_crit_threshold !~ /^\d+$/ ) {
226 print "Lower critical (-c) is not numeric\n";
227 exit $ERRORS{'UNKNOWN'};
228 }
229 if ( $upper_crit_threshold !~ /^\d+$/ ) {
230 print "Upper critical (-c) is not numeric\n";
231 exit $ERRORS{'UNKNOWN'};
232 }
233
234 # Check boundaries
235 if ( $upper_warn_threshold >= $upper_crit_threshold ) {
236 print "Upper Warning (-w) cannot be greater than Critical (-c)!\n";
237 exit $ERRORS{'UNKNOWN'};
238 }
239 # No "<=" since both values are zero if no range (only upper threshold values) is given
240 if ( $lower_warn_threshold < $lower_crit_threshold ) {
241 print "Lower Warning (-w) cannot be less than Critical (-c)!\n";
242 exit $ERRORS{'UNKNOWN'};
243 }
244
245 return $ERRORS{'OK'};
246}
247
248sub print_usage () {
249 print "Usage: $PROGNAME -w <warn> -c <crit> [-v]\n";
250}
251
252sub print_help () {
253 print_revision($PROGNAME,'@NP_VERSION@');
254 print "Copyright (c) 2002 Subhendu Ghosh/Carlos Canau/Benjamin Schmid\n";
255 print "Copyright (c) 2018 Bernd Arnold\n";
256 print "\n";
257 print_usage();
258 print "\n";
259 print " Checks the uptime of the system using $uptime_file\n";
260 print "\n";
261 print "-w (--warning) = Min. number of uptime to generate warning\n";
262 print "-c (--critical) = Min. number of uptime to generate critical alert ( w < c )\n";
263 print "-f (--for) = Show uptime in a pretty format (Running for x weeks, x days, ...)\n";
264 print "-s (--since) = Show last boot in yyyy-mm-dd HH:MM:SS format (output from 'uptime -s')\n";
265 print "-h (--help)\n";
266 print "-V (--version)\n";
267 print "-v (--verbose) = debugging output\n";
268 print "\n\n";
269 print "Note: -w and -c are required arguments.\n";
270 print " You can suffix both values with s for seconds (default), m (minutes), h (hours), d (days) or w (weeks).\n";
271 print "\n";
272 print "Range support: You may specify a range for both warning and critical thresholds.\n";
273 print " This works without additional Perl modules.\n";
274 print "Example: ./check_uptime -w 10m:4w -c 1m:8w\n";
275 print " Results in a critical state when uptime is below 60 seconds or higher than 8 weeks,\n";
276 print " and in a warning state when uptime is below 10 minutes or above 4 weeks.\n";
277 print "\n\n";
278 support();
279}
280
281sub calc_as_seconds () {
282
283 my $parameter = shift;
284
285 # Check if suffix is present
286 # Calculate parameter to seconds (to get an integer value finally)
287 # If no suffix is present, just return the value
288
289 # Possible suffixes:
290 # s = seconds
291 # m = minutes
292 # h = hours
293 # d = days
294 # w = weeks
295 my %factor = ( "s" => 1,
296 "m" => 60,
297 "h" => 60 * 60,
298 "d" => 60 * 60 * 24,
299 "w" => 60 * 60 * 24 * 7,
300 );
301
302 if ( $parameter =~ /^(\d+)([a-z])$/ ) {
303 my $value = $1;
304 my $suffix = $2;
305 print "detected: value=$value, suffix=$suffix\n" if $verbose;
306 if ( ! defined $factor{$suffix} ) {
307 print "Error: wrong suffix ($suffix) for value '$parameter'";
308 exit $ERRORS{'UNKNOWN'};
309 }
310 $parameter = $value * $factor{$suffix};
311 }
312
313 return $parameter;
314
315}
diff --git a/plugins-scripts/t/check_uptime.t b/plugins-scripts/t/check_uptime.t
new file mode 100644
index 0000000..c395307
--- /dev/null
+++ b/plugins-scripts/t/check_uptime.t
@@ -0,0 +1,129 @@
1#!/usr/bin/perl -w -I ..
2#
3# check_uptime tests
4#
5#
6
7use strict;
8use Test::More tests => 40;
9use NPTest;
10
11my $result;
12
13$result = NPTest->testCmd(
14 "./check_uptime"
15 );
16cmp_ok( $result->return_code, '==', 3, "Missing parameters" );
17like ( $result->output, '/^Usage: check_uptime -w/', "Output for missing parameters correct" );
18
19$result = NPTest->testCmd(
20 "./check_uptime --help"
21 );
22cmp_ok( $result->return_code, '==', 3, "Help output requested" );
23like ( $result->output, '/ABSOLUTELY NO WARRANTY/', "Output for help correct" );
24
25$result = NPTest->testCmd(
26 "./check_uptime -w 5 -c 2"
27 );
28cmp_ok( $result->return_code, '==', 3, "Warning greater than critical" );
29like ( $result->output, '/^Upper Warning .*cannot be greater than Critical/', "Output for warning greater than critical correct" );
30
31$result = NPTest->testCmd(
32 "./check_uptime -c 1000 -W 100 2>&1"
33 );
34like ( $result->output, '/^Unknown option: W/', "Output with wrong parameter is correct" );
35
36$result = NPTest->testCmd(
37 "./check_uptime -f -w 1 -c 2"
38 );
39cmp_ok( $result->return_code, '==', 2, "Uptime higher than 2 seconds" );
40like ( $result->output, '/Running for \d+/', "Output for the f parameter correct" );
41
42$result = NPTest->testCmd(
43 "./check_uptime -s -w 1 -c 2"
44 );
45cmp_ok( $result->return_code, '==', 2, "Uptime higher than 2 seconds" );
46like ( $result->output, '/Running since \d+/', "Output for the s parameter correct" );
47
48$result = NPTest->testCmd(
49 "./check_uptime -w 1 -c 2"
50 );
51cmp_ok( $result->return_code, '==', 2, "Uptime higher than 2 seconds" );
52like ( $result->output, '/^CRITICAL: uptime is \d+ seconds/', "Output for uptime higher than 2 seconds correct" );
53
54$result = NPTest->testCmd(
55 "./check_uptime -w 1 -c 9999w"
56 );
57cmp_ok( $result->return_code, '==', 1, "Uptime lower than 9999 weeks" );
58like ( $result->output, '/^WARNING: uptime is \d+ seconds/', "Output for uptime lower than 9999 weeks correct" );
59
60$result = NPTest->testCmd(
61 "./check_uptime -w 9998w -c 9999w"
62 );
63cmp_ok( $result->return_code, '==', 0, "Uptime lower than 9998 weeks" );
64like ( $result->output, '/^OK: uptime is \d+ seconds/', "Output for uptime lower than 9998 weeks correct" );
65like ( $result->output, '/\|uptime=[0-9]+s;6046790400;6047395200;/', "Checking for performance output" );
66
67$result = NPTest->testCmd(
68 "./check_uptime -w 111222d -c 222333d"
69 );
70cmp_ok( $result->return_code, '==', 0, "Uptime lower than 111222 days" );
71like ( $result->output, '/^OK: uptime is \d+ seconds/', "Output for uptime lower than 111222 days correct" );
72like ( $result->output, '/\|uptime=[0-9]+s;9609580800;19209571200;/', "Checking for performance output" );
73
74# Same as before, hopefully uptime is higher than 2 seconds so no warning
75$result = NPTest->testCmd(
76 "./check_uptime -w 2:111222d -c 1:222333d"
77 );
78cmp_ok( $result->return_code, '==', 0, "Uptime lower than 111222 days, and higher 2 seconds" );
79like ( $result->output, '/^OK: uptime is \d+ seconds/', "Output for uptime lower than 111222 days, and higher 2 seconds correct" );
80like ( $result->output, '/\|uptime=[0-9]+s;9609580800;19209571200;/', "Checking for performance output" );
81
82# Same as before, now the low warning should trigger
83$result = NPTest->testCmd(
84 "./check_uptime -w 111221d:111222d -c 1:222333d"
85 );
86cmp_ok( $result->return_code, '==', 1, "Uptime lower than 111221 days raises warning" );
87like ( $result->output, '/^WARNING: uptime is \d+ seconds/', "Output for uptime lower than 111221 days correct" );
88like ( $result->output, '/Exceeds lower warn threshold/', "Exceeds text correct" );
89like ( $result->output, '/\|uptime=[0-9]+s;9609580800;19209571200;/', "Checking for performance output" );
90
91# Same as before, now the low critical should trigger
92$result = NPTest->testCmd(
93 "./check_uptime -w 111221d:111222d -c 111220d:222333d"
94 );
95cmp_ok( $result->return_code, '==', 2, "Uptime lower than 111220 days raises critical" );
96like ( $result->output, '/^CRITICAL: uptime is \d+ seconds/', "Output for uptime lower than 111220 days correct" );
97like ( $result->output, '/Exceeds lower crit threshold/', "Exceeds text correct" );
98like ( $result->output, '/\|uptime=[0-9]+s;9609580800;19209571200;/', "Checking for performance output" );
99
100
101#
102# Range values using ":" without two parts ("a:b") is invalid
103# Strings without two parts are always considered as upper threshold
104#
105
106$result = NPTest->testCmd(
107 "./check_uptime -w 2: -c 1:4"
108 );
109cmp_ok( $result->return_code, '==', 3, "Wrong parameter format raises unknown" );
110like ( $result->output, '/^Upper warning .* is not numeric/', "Output for wrong parameter format correct" );
111
112$result = NPTest->testCmd(
113 "./check_uptime -w 2:3 -c 1:"
114 );
115cmp_ok( $result->return_code, '==', 3, "Wrong parameter format raises unknown" );
116like ( $result->output, '/^Upper critical .* is not numeric/', "Output for wrong parameter format correct" );
117
118$result = NPTest->testCmd(
119 "./check_uptime -w :3 -c 1:4"
120 );
121cmp_ok( $result->return_code, '==', 3, "Wrong parameter format raises unknown" );
122like ( $result->output, '/^Upper warning .* is not numeric/', "Output for wrong parameter format correct" );
123
124$result = NPTest->testCmd(
125 "./check_uptime -w 2:3 -c :4"
126 );
127cmp_ok( $result->return_code, '==', 3, "Wrong parameter format raises unknown" );
128like ( $result->output, '/^Upper critical .* is not numeric/', "Output for wrong parameter format correct" );
129