--- 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<hs@schlittermann.de>
+
+=head1 SOURCE
+
+Source can be found at L<https://ssl.schlittermann.de/hg/nagios/nagios-plugin-amanda-client>
+
+=cut
+
+