#!/usr/bin/perl -w
#
# check_qnap_volumes  v1.0, 24.11.2013
# (c) Michael Geiger, info@mgeiger.de
# updates on http://www.mgeiger.de/downloads.html
#
# nagios plugin that verifies the volumes (state, free space)
# of a QNAP NAS (tested on a TS-259 Pro+, firmware 3.7.2)
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


use strict;
use Nagios::Plugin;
use Nagios::Plugin::Getopt;
use SNMP;

use constant VERSION => "1.0";
use constant QTREE =>".1.3.6.1.4.1.24681.1.2.";

my ($np,$sess,$anz,@tab,$statc,$statw,$txt,$a,$x,$warn,$crit,$free,$size);


# check SNMP error code
sub chk_err {
	my $txt = shift;

	if ($sess->{ErrorNum} != 0) {
		$np->nagios_die ("$txt: " . $sess->{ErrorStr});
	}
}


# convert into bytes
sub to_bytes {
	my $n = shift;
	my $b = lc(shift);

	if ($b eq "kb") {
		return ($n * 1024);
	} elsif ($b eq "mb") {
		return ($n * 1024 * 1024);
	} elsif ($b eq "gb") {
		return ($n * 1024 * 1024 * 1024);
	} elsif ($b eq "tb") {
		return ($n * 1024 * 1024 * 1024 * 1024);
	} else {
		return (0);
	}
}



### MAIN ###
$np = Nagios::Plugin->new(
	usage		=> "Usage: %s -H <host> -w <warning free space%%> -c <critical free space%%> [-t <timeout>]",
	shortname	=> "QNAP Volumes",
	version		=> VERSION,
	timeout		=> 5,
	url		=> "http://www.mgeiger.de/downloads.html",
	blurb		=> "This plugin sends SNMP queries to a QNAP NAS and verifies the state\n" .
			   "of all volumes (status, space free).",
);

# plugin arguments
$np->add_arg(
	spec		=> "host|H=s",
	help		=> "ip address or hostname of the qnap device",
	required	=> 1,
);

$np->add_arg(
	spec		=> "warning|w=s",
	label		=> "PERCENT%",
	help		=> "free space in percent, when a WARNING is returned",
	required	=> 1,
);

$np->add_arg(
	spec		=> "critical|c=s",
	label		=> "PERCENT%",
	help		=> "free space in percent, when a CRITICAL is returned",
	required	=> 1,
);

$np->getopts;

if ($np->opts->warning =~ /^(\d+)%/) {
	$warn = $1;
} else {
	$np->nagios_die ("warning value not a percentage (e.g. 15%)");
}

if ($np->opts->critical =~ /^(\d+)%/) {
	$crit = $1;
} else {
	$np->nagios_die ("critical value not a percentage (e.g. 15%)");
}


# setup SNMP session
$sess = new SNMP::Session(
	DestHost	=> $np->opts->host,
	Community	=> "public",
	Version		=> 2,
	Timeout		=> $np->opts->timeout * 1000000,
	Retries		=> 2,
);
if (! defined($sess)) {
	$np->nagios_die ("SNMP Session Setup");
}
chk_err("Session Setup");


# query number of volumes
$anz = $sess->get(QTREE . "16.0");
chk_err("Get SysVolumeNumber");
if (($anz !~ /^\d+$/) || ($anz <= 0) || ($anz > 20)) {
	$np->nagios_die ("SysVolumeNumber: " . $anz);
}

# bulk query on SystemVolumeTable
@tab = $sess->getbulk(0,$anz * 6,QTREE . "17.1");
chk_err("Get SystemVolumeTable");


# loop all volumes
$statw = 0;
$statc = 0;
$txt = "";
for ($a = 1; $a <= $anz; $a++) {

	# Status Text
	if ($a > 1) {
		$txt .= ", ";
	}
	$x = $tab[$anz * 1 + $a - 1];
	$txt .= $x . ": ";

	# SysVolumeFreeSize
	$x = $tab[$anz * 4 + $a - 1];
	$txt .= $x . " / ";
	if ($x =~ /^([0-9\.]+) ([kmgt]b)/i) {
		$free = to_bytes($1,$2);
	} else {
		$np->nagios_die ("SysVolumeFreeSize: $x");
	}

	# SysVolumeTotalSize
	$x = $tab[$anz * 3 + $a - 1];
	$txt .= $x;
	if ($x =~ /^([0-9\.]+) ([kmgt]b)/i) {
		$size = to_bytes($1,$2);
	} else {
		$np->nagios_die ("SysVolumeTotalSize: $x");
	}

	# check free space
	if (($free / $size) <= ($crit / 100)) {
		$statc = 1;
	} elsif (($free / $size) <= ($warn / 100)) {
		$statw = 1;
	}

	# performance data
	$np->add_perfdata(
		label		=> "Volume " . $a,
		value		=> $free,
		uom		=> "B",
		warning		=> int($warn / 100 * $size),
		critical	=> int($crit / 100 * $size),
	);


	# SysVolumeStatus
	$x = $tab[$anz * 5 + $a - 1];
	if ($x !~ /^ready/i) {
		$statc = 1;
		$txt .= ", Volume " . $a . " Status: " . $x;
	}
}


# Exit
if ($statc) {
	$np->nagios_exit (CRITICAL, $txt);
} elsif ($statw) {
	$np->nagios_exit (WARNING, $txt);
} else {
	$np->nagios_exit (OK, $txt);
}

