diff -r b30cade45ad7 -r 1ea5da2535d7 check --- a/check Thu Jan 09 20:58:30 2014 +0100 +++ b/check Thu Jan 09 22:55:25 2014 +0100 @@ -3,51 +3,72 @@ use 5.010; use strict; use warnings; +use Getopt::Long; use POSIX; use File::Spec::Functions; use Data::Dumper; use File::Find; use Carp; +use Pod::Usage; sub su; sub find_tool; sub check_perms; sub config_names; sub get_devices; -sub amcheck; -sub amlist; +sub amchecks; +sub amlists; +sub main; -# test needs to be run as root:* or as backup:backup -my $USER = 'backup'; -my $CFDIR = '/etc/amanda'; +my $NAME = 'AMANDA-CLIENT'; + +sub ok; +sub warning; +sub critical; +sub unknown; -# change to backup if still root -su $USER if $> == 0; +$SIG{__DIE__} = sub { unknown @_ unless $^S }; + +exit main @ARGV; + +#---- -# amservice needs to be suid root, but executable -# by the backup user/group -check_perms find_tool('amservice'), 04750, 'root', $); +sub main { + + GetOptions( + 'h|help' => sub { pod2usage(-verbose => 1, -exit => 0) }, + 'm|man' => sub { pod2usage(-verbose => 2, -exit => 0) }, + ) or pod2usage; + -# find the backup sets we know about -# here we suppose that it's possible to find strings like -# 'conf "foo"' in files named 'amanda-client.conf' below /etc/amanda + # test needs to be run as root:* or as backup:backup + my $USER = 'backup'; + my $CFDIR = '/etc/amanda'; -my @confs = config_names $CFDIR - or die "no amanda backup sets found (did: find $CFDIR -name amanda-client.conf)\n"; + # change to backup if still root + su $USER if $> == 0; -#eval { amcheck $_ } or die $@ -# foreach @confs; + # amservice needs to be suid root, but executable + # by the backup user/group + eval { check_perms find_tool('amservice'), 04750, 'root', $) } + or unknown $@; -my @devs = get_devices; -foreach (@confs) { - my @dles = amlist $_; - warn Dumper \@dles; - warn Dumper \@devs; + # find the backup sets we know about + # here we suppose that it's possible to find strings like + # 'conf "foo"' in files named 'amanda-client.conf' below /etc/amanda + + my @confs = eval { config_names $CFDIR } + or unknown $@; + + eval { amchecks @confs } or critical $@; + + my @dles = eval { amlists @confs } or critical $@; + ok @dles; + + # never reached + return 0; } -exit; -#--- - # compare the file systems # get a list of file system sub get_devices { @@ -68,7 +89,7 @@ setgrent; my @rc; while (my @g = getgrent) { - push @groups, $g[2] if $USER ~~ [split ' ', $g[3]]; + push @groups, $g[2] if $user ~~ [split ' ', $g[3]]; } endgrent; $) = "@groups"; @@ -79,7 +100,7 @@ sub find_tool { my $name = shift; my @rc = grep { -f -x } map { catfile $_, $name } split /:/, $ENV{PATH} - or croak "Can't find `$name' in $ENV{PATH}\n"; + or die "Can't find `$name' in $ENV{PATH}\n"; $rc[0]; }; @@ -105,7 +126,8 @@ die $msg unless $f_group eq $group; die $msg unless $f_mode == $mode; }; - croak "wrong permissions for `$file', $@" if $@; + die "wrong permissions for `$file', $@" if $@; + 1; } @@ -117,21 +139,95 @@ open(my $fh, '<', $_) or die "Can't open $File::Find::name: $!\n"; push @configs, map { /^conf\s+"(.+?)"/ ? $1 : () } <$fh>; }, $dir); + + die "no configs found below $dir (amanda-client.conf needs need `conf \"foo\"' line)\n" + if not @configs; return @configs; }; -sub amcheck { - my $conf = shift; - my @errors = map { "$conf: $_" } grep { /^error/i } qx(amdump_client --config '$conf' check 2>&1); - die @errors if @errors; +sub amchecks { + my @errors; + foreach my $conf (@_) { + push @errors, map { "$conf: $_" } grep { /^error/i } qx(amdump_client --config '$conf' check 2>&1); + } + die join "\n", @errors if @errors; return 1; } sub amlist { + # return a list of [ name, dev ] tupels. + # name: the name of the disk/device + # dev: the local device id (stat)[0] + # iff the inum of $name != 2, it's not the top directory + # and we set the device id to -1, since $name does not stand for a whole + # device my $conf = shift; chomp((undef, my @dles) = qx(amdump_client --config '$conf' list)); - return map { [$_, (stat $_)[0] ] } @dles; + return map { [$_, (stat $_)[1] == 2 ? (stat $_)[0] : -1 ] } @dles; +} + +sub amlists { + my @confs = @_; + my @candidates = get_devices; + + my %missing; + + foreach my $conf (@confs) { + my @dles = amlist $conf; + foreach my $candidate (@candidates) { + # we're satisfied if either the name of the device is in + # the disklist, or the device id is found + $candidate->[0] ~~ [ map { $_->[0] } @dles ] and next; + $candidate->[1] ~~ [ map { $_->[1] } @dles ] and next; + push @{$missing{$conf}}, $candidate->[0]; + } + } + die map { "$_ missing: " . join(', ' => @{$missing{$_}}) . "\n" } keys %missing + if %missing; + return map { $_->[0] } @candidates; } +sub ok { say "$NAME OK\n", join "\n" => @_; exit 0 } +sub warning { print "$NAME WARNING\n", join "\n" => @_; exit 1 } +sub critical { print "$NAME CRITICAL\n", join "\n" => @_; exit 2 } +sub unknown { print "$NAME UNKNOWN\n", join "\n" => @_; exit 3 } + __END__ -system amdump_client => '--config', 'daily', 'list'; + +=head1 NAME + + check_amanda-client - check the amanda backup from the client side + +=head1 SYNOPSIS + + check_amanda-client [-h|--help] [-m|--man] + +=head1 DESCRIPTION + +This nagios check plugin checks the Amanda setup from the client side. + +=head1 OPTIONS + +=over + +=item B<-h>|B<--help> + +Show a short description and help text. + +=item B<-m>|B<--man> + +Show the man page of this tool. + +=back + +=head1 AUTHOR + +Heiko Schlittermann L + +=head1 SOURCE + +Source can be found at L + +=cut + +