plugins/check_amanda-client
changeset 74 7d87261e4396
parent 73 112c0d86f3d4
--- a/plugins/check_amanda-client	Fri Jun 30 12:27:35 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,374 +0,0 @@
-#! /usr/bin/perl
-# source: https://ssl.schlittermann.de/hg/ius/nagios/nagios-plugin-amanda-client
-
-use 5.014;
-use strict;
-use warnings;
-use Getopt::Long;
-use POSIX;
-use File::Spec::Functions;
-use Data::Dumper;
-use File::Find;
-use Carp;
-use Pod::Usage;
-use Const::Fast;
-use if $ENV{DEBUG} => 'Smart::Comments';
-use if $^V >= v5.18 => (experimental => qw/smartmatch/);
-
-const my $NAME  => 'AMANDA-CLIENT';
-const my $USER  => 'backup';
-const my $CFDIR => '/etc/amanda';
-
-sub su;
-sub find_tool;
-sub check_perms;
-sub config_names;
-sub get_devices;
-
-sub amchecks;
-sub compare_lists;
-
-sub main;
-
-sub OK;
-sub WARNING;
-sub CRITICAL;
-sub UNKNOWN;
-sub verbose;
-sub unique { my %h; @h{@_} = (); return keys %h }
-
-local $SIG{__DIE__} = sub { UNKNOWN @_ unless $^S };
-
-# this we need for testing only, if this file gets
-# included as a module
-sub import {
-    no strict 'refs';
-    *{"$_[0]::verbose"} = sub { };
-}
-
-
-exit main @ARGV if not caller;
-
-#----
-
-sub main {
-    my @opt_exclude;
-    my $opt_verbose = 0;
-
-    GetOptions(
-        'e|x|exclude=s@' => \@opt_exclude,
-        'h|help'         => sub { pod2usage(-verbose => 1, -exit => 0) },
-        'm|man'          => sub { pod2usage(-verbose => 2, -exit => 0) },
-        'v|verbose'      => \$opt_verbose,
-    ) or pod2usage;
-
-    *::verbose = $opt_verbose ? sub { say '# ', @_ } : sub { };
-
-	verbose('setting working directory to /, this avoids permission problems');
-	chdir '/';
-
-    # test needs to be run as root:* or as backup:backup
-    # change to backup if still root
-    su $USER if $> == 0;
-
-    # amservice needs to be suid root, but executable
-    # by the backup user/group
-    verbose q{checking permissions for `amservice'};
-    eval { check_perms find_tool('amservice'), 04750, 'root', $) }
-      or UNKNOWN $@;
-
-    # 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
-
-    verbose qq{find config names from $CFDIR};
-    my @confs = sort +unique eval { config_names $CFDIR }
-      or UNKNOWN $@;
-
-    eval { amchecks @confs } or CRITICAL $@;
-
-    my @dles =
-      eval { compare_lists confs => \@confs, exclude => \@opt_exclude, }
-      or CRITICAL $@;
-    OK 'config: ' . join(', ', @confs), @dles;
-
-    # never reached
-    return 0;
-}
-
-# compare the file systems
-# get a list of file system
-sub get_devices {
-    open(my $fh, '/proc/filesystems');
-    my @types = map { /^\s+(\S+)/ ? $1 : () } <$fh>;
-    my @df = (df => '-P', map { -t => $_ } @types);
-    map { [$_, (stat)[0]] } map { (split ' ', $_)[5] } grep { /^\// } `@df`;
-}
-
-sub su {
-    my $user  = shift;
-    my $group = (getgrnam $user)[0];
-    my $uid   = getpwnam $user;
-    my $gid   = getgrnam $group;
-
-    my @groups;
-
-    setgrent;
-    my @rc;
-    while (my @g = getgrent) {
-        push @groups, $g[2] if $user ~~ [split ' ', $g[3]];
-    }
-    endgrent;
-    $) = "@groups";
-
-    verbose "su to $uid:$gid";
-
-    # during testing
-    return ($uid, $gid) if $ENV{HARNESS_ACTIVE};
-
-    setgid $gid;
-    setuid $uid;
-}
-
-sub find_tool {
-    my $name = shift;
-    my @rc = grep { -f -x } map { catfile $_, $name } split /:/, $ENV{PATH}
-      or die "Can't find executable `$name' in $ENV{PATH}\n";
-    $rc[0];
-}
-
-sub check_perms {
-    my ($file, $mode, $owner, $group) = @_;
-
-    $owner = getpwuid $owner if $owner ~~ /^\d+$/;
-
-    $group = getgrgid +(split ' ', $group)[0]
-      if $group ~~ /^[\d\s]+$/;
-
-    stat $file or croak "Can't stat `$file': $!\n";
-
-    eval {
-        my $f_owner = getpwuid +(stat _)[4] or die $!;
-        my $f_group = getgrgid +(stat _)[5] or die $!;
-        my $f_mode  = (stat _)[2] & 07777   or die $!;
-
-        my $msg =
-          sprintf "need: 0%04o root:%s, got: 0%04o %s:%s\n",
-				$mode, $group, $f_mode, $f_owner, $f_group;
-
-		if (-f '/etc/debian_version') {
-			$msg .= sprintf  "try dpkg-statoverride --update --add root %s 0%04o %s\n",
-			  $group, $mode, $file;
-		}
-
-        die $msg unless $f_owner eq $owner;
-        die $msg unless $f_group eq $group;
-        die $msg unless $f_mode == $mode;
-    };
-    die "wrong permissions for `$file', $@" if $@;
-    1;
-}
-
-sub config_names {
-    my $dir     = shift;
-    my @configs = ();
-    find(
-        sub {
-            -f and /^amanda-client\.conf$/ or return;
-            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 {
-
-    #config: daily
-    #CHECKING
-    #
-    #Amanda Backup Client Hosts Check
-    #--------------------------------
-    #Client check: 1 host checked in 2.242 seconds.  0 problems found.
-    #
-    #(brought to you by Amanda 3.3.1)
-    #The check is finished
-
-    my $conf = shift;
-    my $o    = qx(amdump_client --config '$conf' check 2>&1);
-
-    $o =~ /^config:\s+
-      (BUSY Amanda is busy, retry later)/smx
-      and WARNING "$1\n";
-
-    $o =~ /^config:\s+$conf\n
-		 CHECKING\n
-		 .*\n
-		 Client.check:.1.host.checked.in.\d+\.\d+.seconds\.\s+0.problems.found\.\n
-		 .*\n
-		 The.check.is.finished$
-	/smx or UNKNOWN "unexpected output from check:\n$o";
-}
-
-sub amchecks {
-    my @errors = ();
-    foreach my $conf (@_) {
-        eval { _amcheck $conf } or push @errors, $@;
-    }
-    die @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 $_)[1] == 2 ? (stat $_)[0] : -1] } @dles;
-}
-
-sub compare_lists {
-    my %arg     = @_;
-    my @confs   = @{ $arg{confs} } or croak 'missing list of confs';
-
-    # magic: if there is no config with the exclude, generate a list of config:exclude
-    my @exclude = map { /^[^\/]+?:/ ? $_ : do { my $x = $_; map { "$_:$x" } @confs } }  
-		  @{ $arg{exclude} };
-    ### exclude:@exclude
-
-    WARNING
-      "excluded filesystem(s) @$_ does not exist, update the config please!\n"
-      if @exclude
-          and @$_ = grep { not -e } unique map { /^.*?:(.*)/ } @exclude;
-
-    my @candidates = get_devices;
-    my %missing;
-
-    ### Candidates: @candidates
-    foreach my $conf (@confs) {
-        my @dles = _amlist $conf;
-	### DLEs: @dles
-
-        foreach my $candidate (@candidates) {
-            ### $candidate
-            #next if not $candidate =~ m{^/|\Q$conf\E:};
-
-            # 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]
-              if not "$conf:$candidate->[0]" ~~ @exclude;
-        }
-    }
-    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 }
-
-1;
-
-__END__
-
-=pod
-
-=head1 NAME
-
- check_amanda-client - check the amanda backup from the client side
-
-=head1 SYNOPSIS
-
-  check_amanda-client [-h|--help] [-m|--man]
-  check_amanda-client [options]
-
-=head1 DESCRIPTION
-
-This nagios check plugin checks the Amanda setup from the client side.
-
-=head1 OPTIONS
-
-=over
-
-=item B<-x>|B<--exclude> [I<config:>]I<filesystem>
-
-The name of a filesystem to be excluded. 
-No config means all configs.
-
-    check_amanda-client --exclude weekly:/var/spool/squid --exclude /boot
-
-
-=item B<-h>|B<--help>
-
-Show a short description and help text.
-
-=item B<-m>|B<--man>
-
-Show the man page of this tool.
-
-=item B<-v>|B<--verbose>
-
-Show what's going only. Many for debugging purpose. (default: off)
-
-=back
-
-=head1 PREPARATIONS
-
-In order to make the check working, some preparations needs to be done.
-
-=head1 Client
-
-For each backup set you want to check: Create an
-F</etc/amanda/$set/amanda-client.conf>. 
-
-    config "foo"
-    index-server    "amanda.example.com"    # used by restore
-    tape-server	    "amanda.example.com"    # used by restore
-    amdump-server   "amanda.example.com"    # used by amdump_client
-
-In addition, the F<amservice> binary has to be suid root and executable
-by the backup user. This requirement is checked automatically by the
-plugin.
-
-=head1 Server
-
-The server need to know about the amdumpd service. In the F<inetd.conf> 
-you need to add "amdumpd" to the list of allowed services. And
-additionally in F<.amandahosts> the "backup" user of the client needs
-the permissions to run the "amdumpd" service.
-
-    # inetd.conf
-    amanda stream tcp nowait backup /usr/lib/amanda/amandad amandad -auth=bsdtcp amindexd amidxtaped amdumpd
-
-    # .amandahosts
-    client.example.com backup amdumpd
-    client.example.com root amindexd amidxtaped 
-
-=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
-
-# vim:et ts=4 sw=4 aw ai: