check
changeset 1 1ea5da2535d7
parent 0 b30cade45ad7
child 2 7b9bad9c85e6
equal deleted inserted replaced
0:b30cade45ad7 1:1ea5da2535d7
     1 #! /usr/bin/perl
     1 #! /usr/bin/perl
     2 
     2 
     3 use 5.010;
     3 use 5.010;
     4 use strict;
     4 use strict;
     5 use warnings;
     5 use warnings;
       
     6 use Getopt::Long;
     6 use POSIX;
     7 use POSIX;
     7 use File::Spec::Functions;
     8 use File::Spec::Functions;
     8 use Data::Dumper;
     9 use Data::Dumper;
     9 use File::Find;
    10 use File::Find;
    10 use Carp;
    11 use Carp;
       
    12 use Pod::Usage;
    11 
    13 
    12 sub su;
    14 sub su;
    13 sub find_tool;
    15 sub find_tool;
    14 sub check_perms;
    16 sub check_perms;
    15 sub config_names;
    17 sub config_names;
    16 sub get_devices;
    18 sub get_devices;
    17 sub amcheck;
    19 sub amchecks;
    18 sub amlist;
    20 sub amlists;
    19 
    21 sub main;
    20 # test needs to be run as root:* or as backup:backup
    22 
    21 my $USER = 'backup';
    23 my $NAME = 'AMANDA-CLIENT';
    22 my $CFDIR = '/etc/amanda';
    24 
    23 
    25 sub ok;
    24 # change to backup if still root
    26 sub warning;
    25 su $USER if $> == 0;
    27 sub critical;
    26 
    28 sub unknown;
    27 # amservice needs to be suid root, but executable
    29 
    28 # by the backup user/group
    30 $SIG{__DIE__} = sub { unknown @_ unless $^S };
    29 check_perms find_tool('amservice'), 04750, 'root', $);
    31 
    30 
    32 exit main @ARGV;
    31 # find the backup sets we know about
    33 
    32 # here we suppose that it's possible to find strings like
    34 #----
    33 # 'conf "foo"' in files named 'amanda-client.conf' below /etc/amanda
    35 
    34 
    36 sub main {
    35 my @confs = config_names $CFDIR
    37 
    36 	or die "no amanda backup sets found (did: find $CFDIR -name amanda-client.conf)\n";
    38 	GetOptions(
    37 
    39 		'h|help' => sub { pod2usage(-verbose => 1, -exit => 0) },
    38 #eval { amcheck $_ } or die $@
    40 		'm|man'  => sub { pod2usage(-verbose => 2, -exit => 0) },
    39 #		foreach @confs;
    41 	) or pod2usage;
    40 
    42 
    41 my @devs = get_devices;
    43 
    42 foreach (@confs) {
    44 	# test needs to be run as root:* or as backup:backup
    43 	my @dles = amlist $_;
    45 	my $USER = 'backup';
    44 	warn Dumper \@dles;
    46 	my $CFDIR = '/etc/amanda';
    45 	warn Dumper \@devs;
    47 
    46 }
    48 	# change to backup if still root
    47 
    49 	su $USER if $> == 0;
    48 exit;
    50 
    49 #---
    51 	# amservice needs to be suid root, but executable
       
    52 	# by the backup user/group
       
    53 	eval { check_perms find_tool('amservice'), 04750, 'root', $) }
       
    54 		or unknown $@;
       
    55 
       
    56 	# find the backup sets we know about
       
    57 	# here we suppose that it's possible to find strings like
       
    58 	# 'conf "foo"' in files named 'amanda-client.conf' below /etc/amanda
       
    59 
       
    60 	my @confs = eval { config_names $CFDIR }
       
    61 		or unknown $@;
       
    62 
       
    63 	eval { amchecks @confs } or critical $@;
       
    64 
       
    65 	my @dles = eval { amlists @confs } or critical $@;
       
    66 	ok @dles;
       
    67 
       
    68 	# never reached
       
    69 	return 0;
       
    70 }
    50 
    71 
    51 # compare the file systems
    72 # compare the file systems
    52 # get a list of file system
    73 # get a list of file system
    53 sub get_devices {
    74 sub get_devices {
    54 	open(my $fh, '/proc/filesystems');
    75 	open(my $fh, '/proc/filesystems');
    66 	my @groups;
    87 	my @groups;
    67 	
    88 	
    68 	setgrent;
    89 	setgrent;
    69 	my @rc;
    90 	my @rc;
    70 	while (my @g = getgrent) {
    91 	while (my @g = getgrent) {
    71 		 push @groups, $g[2] if $USER ~~ [split ' ', $g[3]];
    92 		 push @groups, $g[2] if $user ~~ [split ' ', $g[3]];
    72 	}
    93 	}
    73 	endgrent;
    94 	endgrent;
    74 	$) = "@groups";
    95 	$) = "@groups";
    75 	setgid $gid;
    96 	setgid $gid;
    76 	setuid $uid;
    97 	setuid $uid;
    77 }
    98 }
    78 
    99 
    79 sub find_tool {
   100 sub find_tool {
    80 	my $name = shift;
   101 	my $name = shift;
    81 	my @rc = grep { -f -x } map { catfile $_, $name } split /:/, $ENV{PATH}
   102 	my @rc = grep { -f -x } map { catfile $_, $name } split /:/, $ENV{PATH}
    82 		or croak "Can't find `$name' in $ENV{PATH}\n";
   103 		or die "Can't find `$name' in $ENV{PATH}\n";
    83 	$rc[0];
   104 	$rc[0];
    84 };
   105 };
    85 
   106 
    86 sub check_perms {
   107 sub check_perms {
    87 	my ($file, $mode, $owner, $group) = @_;
   108 	my ($file, $mode, $owner, $group) = @_;
   103 
   124 
   104 		die $msg unless $f_owner eq $owner;
   125 		die $msg unless $f_owner eq $owner;
   105 		die $msg unless $f_group eq $group;
   126 		die $msg unless $f_group eq $group;
   106 		die $msg unless $f_mode == $mode;
   127 		die $msg unless $f_mode == $mode;
   107 	};
   128 	};
   108 	croak "wrong permissions for `$file', $@" if $@;
   129 	die "wrong permissions for `$file', $@" if $@;
       
   130 	1;
   109 }
   131 }
   110 
   132 
   111 
   133 
   112 sub config_names {
   134 sub config_names {
   113 	my $dir = shift;
   135 	my $dir = shift;
   115 	find(sub {
   137 	find(sub {
   116 		-f and /^amanda-client\.conf$/ or return;
   138 		-f and /^amanda-client\.conf$/ or return;
   117 		open(my $fh, '<', $_) or die "Can't open  $File::Find::name: $!\n";
   139 		open(my $fh, '<', $_) or die "Can't open  $File::Find::name: $!\n";
   118 		push @configs, map { /^conf\s+"(.+?)"/ ? $1 : () } <$fh>;
   140 		push @configs, map { /^conf\s+"(.+?)"/ ? $1 : () } <$fh>;
   119 	}, $dir);
   141 	}, $dir);
       
   142 
       
   143 	die "no configs found below $dir (amanda-client.conf needs need `conf \"foo\"' line)\n"
       
   144 		if not @configs;
   120 	return @configs;
   145 	return @configs;
   121 };
   146 };
   122 
   147 
   123 sub amcheck {
   148 sub amchecks {
   124 	my $conf = shift;
   149 	my @errors;
   125 	my @errors = map { "$conf: $_" } grep { /^error/i } qx(amdump_client --config '$conf' check 2>&1);
   150 	foreach my $conf (@_) {
   126 	die @errors if @errors;
   151 		push @errors, map { "$conf: $_" } grep { /^error/i } qx(amdump_client --config '$conf' check 2>&1);
       
   152 	}
       
   153 	die join "\n", @errors if @errors;
   127 	return 1;
   154 	return 1;
   128 }
   155 }
   129 
   156 
   130 sub amlist {
   157 sub amlist {
       
   158 	# return a list of [ name, dev ] tupels.
       
   159 	# name: the name of the disk/device
       
   160 	# dev:  the local device id (stat)[0]
       
   161 	# iff the inum of $name != 2, it's not the top directory
       
   162 	# and we set the device id to -1, since $name does not stand for a whole
       
   163 	# device
   131 	my $conf = shift;
   164 	my $conf = shift;
   132 	chomp((undef, my @dles) = qx(amdump_client --config '$conf' list));
   165 	chomp((undef, my @dles) = qx(amdump_client --config '$conf' list));
   133 	return map { [$_, (stat $_)[0] ] } @dles;
   166 	return map { [$_, (stat $_)[1] == 2 ? (stat $_)[0] : -1 ] } @dles;
   134 }
   167 }
       
   168 
       
   169 sub amlists {
       
   170 	my @confs = @_;
       
   171 	my @candidates = get_devices;
       
   172 
       
   173 	my %missing;
       
   174 
       
   175 	foreach my $conf (@confs) {
       
   176 		my @dles = amlist $conf;
       
   177 		foreach my $candidate (@candidates) {
       
   178 			# we're satisfied if either the name of the device is in
       
   179 			# the disklist, or the device id is found
       
   180 			$candidate->[0] ~~ [ map { $_->[0] } @dles ] and next;
       
   181 			$candidate->[1] ~~ [ map { $_->[1] } @dles ] and next;
       
   182 			push @{$missing{$conf}}, $candidate->[0];
       
   183 		}
       
   184 	}
       
   185 	die map { "$_ missing: " . join(', ' => @{$missing{$_}}) . "\n" } keys %missing
       
   186 		if %missing;
       
   187 	return map { $_->[0] } @candidates;
       
   188 }
       
   189 
       
   190 sub ok { say "$NAME OK\n", join "\n" => @_; exit 0 }
       
   191 sub warning { print "$NAME WARNING\n", join "\n" => @_; exit 1 }
       
   192 sub critical { print "$NAME CRITICAL\n", join "\n" => @_; exit 2 }
       
   193 sub unknown { print "$NAME UNKNOWN\n", join "\n" => @_; exit 3 }
   135 
   194 
   136 __END__
   195 __END__
   137 system amdump_client => '--config', 'daily', 'list';
   196 
       
   197 =head1 NAME
       
   198 
       
   199  check_amanda-client - check the amanda backup from the client side
       
   200 
       
   201 =head1 SYNOPSIS
       
   202 
       
   203   check_amanda-client [-h|--help] [-m|--man]
       
   204 
       
   205 =head1 DESCRIPTION
       
   206 
       
   207 This nagios check plugin checks the Amanda setup from the client side.
       
   208 
       
   209 =head1 OPTIONS
       
   210 
       
   211 =over
       
   212 
       
   213 =item B<-h>|B<--help>
       
   214 
       
   215 Show a short description and help text.
       
   216 
       
   217 =item B<-m>|B<--man>
       
   218 
       
   219 Show the man page of this tool.
       
   220 
       
   221 =back
       
   222 
       
   223 =head1 AUTHOR
       
   224 
       
   225 Heiko Schlittermann L<hs@schlittermann.de>
       
   226 
       
   227 =head1 SOURCE
       
   228 
       
   229 Source can be found at L<https://ssl.schlittermann.de/hg/nagios/nagios-plugin-amanda-client>
       
   230 
       
   231 =cut
       
   232 
       
   233