#!/usr/bin/perl
#----------------------------------------------------------------------
# Description: get disc capacity form SNMP with bacula
# Author: Maxim Odinintsev <gwynn.pin@gmail.com>
# Created at: Thu Sep  6 08:57:45 EEST 2007
# Computer: i-am.org.ua
# System: Linux 2.6.20-1.2952.fc6 on i686
#
# Copyright (c) 2007 Maxim Odinintsev  All rights reserved.
#
#----------------------------------------------------------------------
#
use Getopt::Std;
use SNMP::Simple;
use Data::Dumper;

$ENV{MIBS} = 'ALL';
## common variables
my $TIMEOUT = 15;
my %ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
#
my $configs_dir="/etc/bacula";
my $clinets_conf=$configs_dir."/our-clients";
my $director_conf=$configs_dir."/bacula-dir.conf";
#
my $c_in_dir = 0;
my $parse = 0;
#
###
# -c - Critical space
# -g - percent|capacity|both
# -C - Critical percent
# -o - SNMP Community
# -j - Job name
my %opts =(
        g => 'capacity',   ### get percent or capacity of HD, or check both
        o => 'public',     ### set SNMP community
        c => 10248,        ### Min capacity size
        C => 85,           ### Min percentage
);

getopts('c:C:g:j:o:',\%opts);
#
my $client_name = $opts{'c'};
my $job_name    = lc($opts{'j'});
my $snmpcomm    = $opts{'o'};
my $crit_perc   = $opts{'C'};
my $crit_capa   = $opts{'c'};
my $get_type    = lc($opts{'g'});
my $timeout     = 6000000;

if (!$job_name) {
        print "Error: Missing parmetr: -j\n";
        print "Usage: -j job_name [-c critical space] [-C critical percent] [-o SNMP Community]\n\n";
        exit($ERRORS{'CRITICAL'});
}
print "Try to look in clients config: $clinets_conf ...\n";
open(CFG, "<$clinets_conf") || ($c_in_dir = 1);
if ($c_in_dir) {
        print "Client config file $clinets_conf not found, trying in director config...\n";
        open(CFG, "<$director_conf") || die("Error: Can't open config file $director_conf: $!");
}
while (<CFG>) {
        if (/job\s*{/i) {$parse = 1;}
        if (/\}/ && $parse != 0) {$parse=0; } # $client{$tmp_client{'name'}} = \%tmp_client; }
        if ($parse) {
                next unless (/=/);
                chomp;
                $_ = lc;
                s/(.+)#.*/$1/;
                ($name,$value) = split(/=/);
                $name =~ s/\s+//g;
                $value =~ s/^\s+//g;
                $value =~ s/\s+$//g;
                $value =~ s/"//g;
                chomp($name); chomp($value);
                if ($name =~ /name/i) { $j_name = $value };
                if ($name =~ /storage/i) { $j_storage = $value };
                if (($j_name && $j_storage) && ($j_name eq $job_name)) { $job{$j_name} = $j_storage; last }
        } else {$j_storage = undef; }
}
close CFG;
if ($c_in_dir == 0) {
        print "Try to look in director config: $director_conf ...\n";
        open(CFG, "<$director_conf") || die("Error: Can't open config file $director_conf: $!");
        while (<CFG>) {
                if (/job\s*{/i) {$parse = 1;}
                if (/\}/ && $parse != 0) {$parse=0; } # $client{$tmp_client{'name'}} = \%tmp_client; }
                if ($parse) {
                        next unless (/=/);
                        chomp;
                        $_ = lc;
                        s/(.+)#.*/$1/;
                        ($name,$value) = split(/=/);
                        $name =~ s/\s+//g;
                        $value =~ s/^\s+//g;
                        $value =~ s/\s+$//g;
                        $value =~ s/"//g;
                        chomp($name); chomp($value);
                        if ($name =~ /name/i) { $j_name = $value };
                        if ($name =~ /storage/i) { $j_storage = $value };
                        if (($j_name && $j_storage) && ($j_name eq $job_name)) { $job{$j_name} = $j_storage; last }
                } else {$j_storage = undef; }
        }
        close CFG;
}
if (defined $job{$job_name}) { print "Found necessary Job...\n"; }
else { print "Can't find a Job named $job_name...\nExiting\n\n"; exit($ERRORS{'CRITICAL'}); }
# print (Dumper(%job));

$parse=0;
print "Try to find storage address...\n";
open(CFG, "<$director_conf") || die("Error: Can't open config file $director_conf: $!");
while (<CFG>) {
        if (/storage\s*{/i) {$parse = 1;}
        if (/\}/ && $parse != 0) {$parse=0; } # $client{$tmp_client{'name'}} = \%tmp_client; }
        if ($parse) {
                next unless (/=/);
                chomp;
                $_ = lc;
                s/(.+)#.*/$1/;
                ($name,$value) = split(/=/);
                $name =~ s/\s+//g;
                $value =~ s/^\s+//g;
                $value =~ s/\s+$//g;
                $value =~ s/"//g;
                chomp($name); chomp($value);
                if ($name =~ /name/i) { $s_name = $value };
                if ($name =~ /address/i) { $s_addr = $value };
                if (($s_name && $s_addr) && ($s_name eq $job{$job_name})) { $storage{$s_name} = $s_addr; last }
        } else {$s_addr = undef; }
}
close CFG;
if (defined $storage{$job{$job_name}}) { print "Found needed storage address $storage{$job{$job_name}} for a Job $job_name...\nTrying to get free disc space...\n"; }
else { print "Can't find a needed storage address for Job named $job_name...\nExiting\n\n"; exit($ERRORS{'CRITICAL'}); }
# print (Dumper(%storage));
#
#
print "Start with params:\n";
print " get type of data: $get_type\n";
print " storage $job{$job_name} IP: $storage{$job{$job_name}}\n";
$get_type eq 'capacity' ? print " critical capacity: $crit_capa Mb\n" : print " critical percentage: $crit_perc\n";
ChkDiskSNMP($get_type,$storage{$job{$job_name}},$timeout,$snmpcomm,$crit_perc,$crit_capa);

sub ChkDiskSNMP {

# use Getopt::Std;
# getopts('i:g:c:t:C:w',\%opts);
 $get_by    = shift; # percent|capacity|both
 $ip        = shift; # IP
 $timeout   = shift; # Timeout
 $community = shift; # SNMP Community
# critical values
 $crit_precents = shift; # 85;
 $crit_space = shift; # 2048; # 2048 Mb or 2Gb
#  $warn_precents = 75;
#  $warn_space = 3072;


 # snmp objects
 $disks_oid = '.1.3.6.1.4.1.2021.9.1.3';
 #$disks_oid = 'dskAvail';
 $disk_freespace_oid = '.1.3.6.1.4.1.2021.9.1.7';
 $disk_percents_oid = '.1.3.6.1.4.1.2021.9.1.9';
 $disk_total_oid = '.1.3.6.1.4.1.2021.9.1.6';

 # max disks amount
 $disks = 6;

 # critical values
# $crit_precents = 85;
# $crit_space = 2048; # 2048 Mb or 2Gb
 $warn_precents = $crit_precents;
 $warn_space = $crit_space;

 # set default message
 $message = 'OK';
 $disks_string = '';

 if (!$ip) {
    return($ERRORS{'CRITICAL'});
 }

 # create SNMP object
 $snmp = SNMP::Simple->new(DestHost => $ip, Community => $community, Version => 1, Timeout => $timeout);
 disk2_die('Can\'t create SNMP object') && next unless $snmp;

 my $i;
 # iterate by HD number (set by $disks)
 for ($i = 1; $i <= $disks; $i++) {
        eval {
                # check does the disk exists
                $result = $snmp->get("$disks_oid.$i");
        };
        # detect timeout error
        disk2_die('SNMP session timeout!') if (!defined($result) and $@ =~ /Timeout/i);

        # do next on success
        next if ($result eq '');

        eval {
        # if exists try to get and store data
        $disk{$i}{name} = $result;
        $disk{$i}{freespace} = $snmp->get("$disk_freespace_oid.$i");
        $disk{$i}{percents} = $snmp->get("$disk_percents_oid.$i");
        $disk{$i}{total} = $snmp->get("$disk_total_oid.$i");

        #convert to Mb
        $disk{$i}{total} = $disk{$i}{total}/1024;
        $disk{$i}{freespace} = $disk{$i}{freespace}/1024;
        };
        disk2_die('Can\'t get disk SNMP oid.'." Disk number $i") if ($@);
        ### do the checks

        # if disk total capacity smallest for space limit
        # and check by capacity - swith check to percent
        if ((($get_by eq 'capacity') or ($get_by eq 'both'))
                and ($disk{$i}{total} <= $warn_space))
        { $check = 'percent'; }
        else
        { $check = $get_by; }

        # if check both percent and free space value
        if ($check eq 'both') {
                if     (($disk{$i}{percents} >= $crit_precents) or
                        ($disk{$i}{freespace} <= $crit_space))
                { $message = 'CRITICAL'; }
                elsif ((($disk{$i}{percents} >= $warn_precents) or
                        ($disk{$i}{freespace} <= $warn_space)) and
                        ($message ne 'CRITICAL'))
                { $message = 'WARNING'; }
        }

        # if check percent value
        elsif ($check eq 'percent') {
                if     ($disk{$i}{percents} >= $crit_precents)
                { $message = 'CRITICAL'; }
                elsif (($disk{$i}{percents} >= $warn_precents) and
                        ($message ne 'CRITICAL'))
                { $message = 'WARNING'; }
        }

        # if check free space value
        elsif ($check eq 'capacity') {
                if    ($disk{$i}{freespace} <= $crit_space)
                { $message = 'CRITICAL'; }
                elsif (($disk{$i}{freespace} <= $warn_space) and
                        ($message ne 'CRITICAL'))
                { $message = 'WARNING'; }
        }

        # build script response string
        $disks_string .= sprintf(" [%.1f Mb (%i%%) free on %s, total %.1f Mb]",
                $disk{$i}{freespace}, 100-$disk{$i}{percents}, $disk{$i}{name}, $disk{$i}{total});

        #debug
        #print "$disk{$i}{name} => $disk{$i}{freespace} ($disk{$i}{percents}\%)\n";
 }

 disk2_die('No SNMP data') if (!keys(%disk));

 print "$message DISK";
 print $disks_string."\n";

 exit($ERRORS{$message});

}
sub disk2_die($) {
     print 'ERROR ' . $_[0] . "\n";
     exit($ERRORS{'CRITICAL'});
}
