done
authorHeiko Schlittermann (NIDRA) <hs@schlittermann.de>
Thu, 09 Jan 2014 22:55:25 +0100
changeset 1 1ea5da2535d7
parent 0 b30cade45ad7
child 2 7b9bad9c85e6
done
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<hs@schlittermann.de>
+
+=head1 SOURCE
+
+Source can be found at L<https://ssl.schlittermann.de/hg/nagios/nagios-plugin-amanda-client>
+
+=cut
+
+