retire da-backup checks
[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 = 40*60*60;
34 my $TOO_FRESH = 5*60;
35 my $MAX_LOCK_AGE = 24*60*60;
36 my $LOCKFILE = '/var/lock/da-backup.lock';
37
38 my %CODE = (
39         'UNDEF'         => -1,
40         'OK'            => 0,
41         'WARNING'       => 1,
42         'CRITICAL'      => 2,
43         'UNKNOWN'       => 3
44 );
45 $SIG{__DIE__ } = sub() {
46         print shift;
47         exit $CODE{'UNKNOWN'};
48 };
49
50
51 my $EXITCODE = 'UNDEF';
52 my %MESSAGE = ();
53
54 sub problem($$$) {
55         my ($code, $msg, $resource) = @_;
56         $MESSAGE{$msg} = [] unless defined $MESSAGE{$msg};
57         push @{$MESSAGE{$msg}}, $resource;
58         $EXITCODE = ($CODE{$code} > $CODE{$EXITCODE}) ? $code : $EXITCODE;
59 };
60
61
62 sub help($$) {
63         my ($exitcode, $fd) = @_;
64         version ($fd, 0);
65         print $fd "Usage: $PROGRAM_NAME --help\n";
66         print $fd "Usage: $PROGRAM_NAME [--fresh <minseconds>] [--maxage <seconds>]";
67         exit $exitcode
68 };
69
70 my $params = {};
71
72 Getopt::Long::config('bundling');
73 if (!GetOptions (
74         'h|help'         =>  \$params->{'help'},
75         'f|fresh=i'      =>  \$TOO_FRESH,
76         'm|maxage=i'     =>  \$MAX_AGE,
77         'M|maxlockage=i' =>  \$MAX_LOCK_AGE,
78         )) {
79         die ("$PROGRAM_NAME: Usage: $PROGRAM_NAME [-fwhv]\n");
80 };
81
82 help(0, *STDOUT) if $params->{'help'};
83 help(1, *STDERR) if scalar @ARGV > 0;
84
85
86 unless (-e $DABACKUP_CONF) {
87         if (-e '/etc/da-backup') {
88                 print "WARNING: No $DABACKUP_CONF, but we have /etc/da-backup/\n";
89                 exit $CODE{'WARNING'};
90         };
91         if (-e '/var/log/da-backup') {
92                 print "WARNING: No $DABACKUP_CONF, but we have /var/log/da-backup/\n";
93                 exit $CODE{'WARNING'};
94         };
95         print "OK: da-backup not installed\n";
96         exit $CODE{'OK'};
97 };
98
99 my $confdir;
100 my $logdir;
101
102 open (FH, "< $DABACKUP_CONF") or die ("Cannot open $DABACKUP_CONF: $!\n");
103 while (<FH>) {
104         if (/confdir=(.*)/) {
105                 $confdir = $1;
106         } elsif (/logdir=(.*)/) {
107                 $logdir = $1;
108         };
109 };
110
111 die ("No confdir found in $DABACKUP_CONF") unless defined $confdir;
112 die ("No logdir found in $DABACKUP_CONF") unless defined $logdir;
113
114 opendir(DIR, $confdir) or die ("Cannot opendir $confdir: $!\n");
115 my %conffiles = map {$_ => 1} grep { !/^\./ && !/\.bak$/} readdir(DIR);
116 closedir(DIR);
117
118 opendir(DIR, $logdir) or die ("Cannot opendir $logdir: $!\n");
119 my %logfiles = map {$_ => 1} grep { !/^\./ && !/\.[0-9]+(\.gz)?$/} readdir(DIR);
120 closedir(DIR);
121
122 if (scalar keys %conffiles == 0) {
123         print "WARNING: da-backup installed but no backups configured\n";
124         exit $CODE{'WARNING'};
125 };
126
127 for my $f (keys %conffiles) {
128         unless (exists $logfiles{$f}) {
129                 problem('WARNING', 'no log', $f);
130         }
131 }
132
133 FILE:
134 for my $f (sort {$a cmp $b} keys %logfiles) {
135         unless (exists $conffiles{$f}) {
136                 problem('WARNING', 'no config', $f);
137                 next;
138         }
139
140         my @stat = stat("$logdir/$f") or die ("Cannot stat $logdir/$f: $!\n");
141         my $age = time - $stat[10];
142
143         my $lockage = undef;
144         if (my @lockstat = stat($LOCKFILE)) {
145                 $lockage = time - $lockstat[10];
146         }
147
148         if ($age < $TOO_FRESH || (defined $lockage && $lockage < $MAX_LOCK_AGE)) { # File is too new, let's use the old one
149                 if (-e "$logdir/$f.0") {
150                         $f .= ".0";
151                         my @stat = stat("$logdir/$f") or die ("Cannot stat $logdir/$f: $!\n");
152                         $age = time - $stat[10];
153                 };
154         };
155
156         if ($age < 0) {
157                 problem('WARNING', 'future timestamp', $f);
158                 next;
159         } elsif ($age > $MAX_AGE) {
160                 my $hage;
161
162                 if ($age > 48 * 3600) {
163                         $hage = sprintf("%d days", $age / 24 / 3600);
164                 } else {
165                         $hage = sprintf("%d hours", $age /  3600);
166                 };
167                 problem('WARNING', 'old', "$f ($hage)");
168                 next;
169         };
170
171         open(FH, "< $logdir/$f") or die ("Cannot open $logdir/$f: $!\n");
172         sysseek(FH, -1024, SEEK_END); # just try it - doesn't matter if it fails
173         my $last2 = '';
174         my $last = '';
175         while (<FH>) {
176                 chomp;
177                 if (/^sent\s+[\d,]+\s+bytes\s+received\s+[\d,]+\s+bytes\s+[\d,\.]+\s+bytes\/sec$/) {
178                         problem('OK', 'probably ok', $f);
179                         close(FH);
180                         next FILE;
181                 };
182                 $last2 = $last;
183                 $last = $_;
184         };
185         problem('CRITICAL', 'FAILED', "$f ($last2 $last)");
186 };
187
188 my $msg = join("; ", map {"$_: ".join(', ', @{$MESSAGE{$_}}) } (sort {$a cmp $b} keys %MESSAGE));
189 print $EXITCODE, ": ", $msg, "\n";
190 exit $CODE{$EXITCODE};