620d3162081ddc0d593265f7d69a9ee85df5b8ae
[mirror/dsa-nagios.git] / dsa-nagios-checks / checks / dsa-check-dabackup
1 #!/usr/bin/perl -w
2
3 # Check the status of da-backup backups
4 # Copyright 2007 Stephen Gran <sgran@debian.org>
5 # Copyright 2008 Peter Palfrader
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining
8 # a copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish,
11 # distribute, sublicense, and/or sell copies of the Software, and to
12 # permit persons to whom the Software is furnished to do so, subject to
13 # the following conditions:
14 #
15 # The above copyright notice and this permission notice shall be
16 # included in all copies or substantial portions of the Software.
17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 use strict;
27 use warnings;
28 use English;
29 use Getopt::Long;
30 use Fcntl qw(:seek);
31
32 my $DABACKUP_CONF = '/etc/da-backup.conf';
33 my $MAX_AGE = 30*60*60;
34 my $TOO_FRESH = 5*60;
35 my %CODE = (
36         'UNDEF'         => -1,
37         'OK'            => 0,
38         'WARNING'       => 1,
39         'CRITICAL'      => 2,
40         'UNKNOWN'       => 3
41 );
42 $SIG{__DIE__ } = sub() {
43         print shift;
44         exit $CODE{'UNKNOWN'};
45 };
46
47
48 my $EXITCODE = 'UNDEF';
49 my %MESSAGE = ();
50
51 sub problem($$$) {
52         my ($code, $msg, $resource) = @_;
53         $MESSAGE{$msg} = [] unless defined $MESSAGE{$msg};
54         push @{$MESSAGE{$msg}}, $resource;
55         $EXITCODE = ($CODE{$code} > $CODE{$EXITCODE}) ? $code : $EXITCODE;
56 };
57
58
59 sub help($$) {
60         my ($exitcode, $fd) = @_;
61         version ($fd, 0);
62         print $fd "Usage: $PROGRAM_NAME --help\n";
63         print $fd "Usage: $PROGRAM_NAME [--fresh <minseconds>] [--maxage <seconds>]";
64         exit $exitcode
65 };
66
67 my $params = {};
68
69 Getopt::Long::config('bundling');
70 if (!GetOptions (
71         'h|help'        =>  \$params->{'help'},
72         'f|fresh=i'     =>  \$TOO_FRESH,
73         'm|maxage=i'    =>  \$MAX_AGE,
74         )) {
75         die ("$PROGRAM_NAME: Usage: $PROGRAM_NAME [-fwhv]\n");
76 };
77
78 help(0, *STDOUT) if $params->{'help'};
79 help(1, *STDERR) if scalar @ARGV > 0;
80
81
82 unless (-e $DABACKUP_CONF) {
83         if (-e '/etc/da-backup') {
84                 print "WARNING: No $DABACKUP_CONF, but we have /etc/da-backup/\n";
85                 exit $CODE{'WARNING'};
86         };
87         if (-e '/var/log/da-backup') {
88                 print "WARNING: No $DABACKUP_CONF, but we have /var/log/da-backup/\n";
89                 exit $CODE{'WARNING'};
90         };
91         print "OK: da-backup not installed\n";
92         exit $CODE{'OK'};
93 };
94
95 my $confdir;
96 my $logdir;
97
98 open (FH, "< $DABACKUP_CONF") or die ("Cannot open $DABACKUP_CONF: $!\n");
99 while (<FH>) {
100         if (/confdir=(.*)/) {
101                 $confdir = $1;
102         } elsif (/logdir=(.*)/) {
103                 $logdir = $1;
104         };
105 };
106
107 die ("No confdir found in $DABACKUP_CONF") unless defined $confdir;
108 die ("No logdir found in $DABACKUP_CONF") unless defined $logdir;
109
110 opendir(DIR, $confdir) or die ("Cannot opendir $confdir: $!\n");
111 my %conffiles = map {$_ => 1} grep { !/^\./ && !/\.bak$/} readdir(DIR);
112 closedir(DIR);
113
114 opendir(DIR, $logdir) or die ("Cannot opendir $logdir: $!\n");
115 my %logfiles = map {$_ => 1} grep { !/^\./ && !/\.[0-9]+(\.gz)?$/} readdir(DIR);
116 closedir(DIR);
117
118 if (scalar keys %conffiles == 0) {
119         print "WARNING: da-backup installed but no backups configured\n";
120         exit $CODE{'WARNING'};
121 };
122
123 for my $f (keys %conffiles) {
124         unless (exists $logfiles{$f}) {
125                 problem('WARNING', 'no log', $f);
126         }
127 }
128
129 FILE:
130 for my $f (sort {$a cmp $b} keys %logfiles) {
131         unless (exists $conffiles{$f}) {
132                 problem('WARNING', 'no config', $f);
133                 next;
134         }
135
136         my @stat = stat("$logdir/$f") or die ("Cannot stat $logdir/$f: $!\n");
137         my $age = time - $stat[10];
138
139         if ($age < $TOO_FRESH) { # File is too new, let's use the old one
140                 if (-e "$logdir/$f.0") {
141                         $f .= ".0";
142                         my @stat = stat("$logdir/$f") or die ("Cannot stat $logdir/$f: $!\n");
143                         $age = time - $stat[10];
144                 };
145         };
146
147         if ($age < 0) {
148                 problem('WARNING', 'future timestamp', $f);
149                 next;
150         } elsif ($age > $MAX_AGE) {
151                 my $hage;
152
153                 if ($age > 48 * 3600) {
154                         $hage = sprintf("%d days", $age / 24 / 3600);
155                 } else {
156                         $hage = sprintf("%d hours", $age /  3600);
157                 };
158                 problem('WARNING', 'old', "$f ($hage)");
159                 next;
160         };
161
162         open(FH, "< $logdir/$f") or die ("Cannot open $logdir/$f: $!\n");
163         sysseek(FH, -1024, SEEK_END); # just try it - doesn't matter if it fails
164         my $last2 = '';
165         my $last = '';
166         while (<FH>) {
167                 chomp;
168                 if (/^sent\s+\d+\s+bytes\s+received\s+\d+\s+bytes\s+[\d\.]+\s+bytes\/sec$/) {
169                         problem('OK', 'probably ok', $f);
170                         close(FH);
171                         next FILE;
172                 };
173                 $last2 = $last;
174                 $last = $_;
175         };
176         problem('CRITICAL', 'FAILED', "$f ($last2 $last)");
177 };
178
179 my $msg = join("; ", map {"$_: ".join(', ', @{$MESSAGE{$_}}) } (sort {$a cmp $b} keys %MESSAGE));
180 print $EXITCODE, ": ", $msg, "\n";
181 exit $CODE{$EXITCODE};