#!/usr/bin/perl
#Author:
#        Otavio Honorio (otavio.honorio@opservices.com.br)
use strict;
use Getopt::Long;
use POSIX;
use File::Basename;
# Setting environment
$ENV{"USER"}="opuser";
$ENV{"HOME"}="/home/opuser";
# Global variables
our $name = basename($0, ".pl");
our $path = "/usr/local/opmon/libexec";
our ($oHelp, $oVerbose, $oWarn, $oCrit, $oDev, $oMode);
#--------------------------------------------------------------------------------------
sub main {
	getoption();
	my $io = check_io();

	my ($first, $code);
	if (!$oDev) {
		for my $k ( sort keys %$io ) {
			$first = $k;
			last;
		}
	}else{
		$first = $oDev;
	}

	if ($oMode eq "all") {
		my $perf;
		while ( my ($k, $value) = each( %$io) ) {
			if ($k eq $first) {
		                while ( my ($key, $value) = each(%$value) ) {
					if ($key eq '%util') {
						$perf .= " '$key'=$value;$oWarn;$oCrit;0;";
					}else{
						$perf .= " '$key'=$value;;;0;";
					}
	                	}
			}
        	}
		my $code = metric($$io{$first}{'%util'},$oWarn,$oCrit);
		quit("I/O Utilization: ".$$io{$first}{'%util'}."%|$perf",$code);
	} elsif ($oMode eq "tps") {
		my ($rWarn, $wWarn) = split(/,/,$oWarn);
		my ($rCrit, $wCrit) = split(/,/,$oCrit);
		my $rCode = metric($$io{$first}{"r/s"},$rWarn,$rCrit);
		my $wCode = metric($$io{$first}{"w/s"},$wWarn,$wCrit);
		$code = 0 if ($rCode == 0 || $wCode == 0);
		$code = 1 if ($rCode == 1 || $wCode == 1);
		$code = 2 if ($rCode == 2 || $wCode == 2);
		my $perf = "'read/s'=".$$io{$first}{"r/s"}.";$rWarn;$rCrit;0; 'write/s'=".$$io{$first}{"w/s"}.";$wWarn;$wCrit;0;";
		my $mgs = "I/O Request Issued - Read/sec: ".$$io{$first}{"r/s"}." / Write/sec: ".$$io{$first}{"w/s"};
		quit("$mgs | $perf",$code);
	} elsif ($oMode eq "rqm") {
		my ($rWarn, $wWarn) = split(/,/,$oWarn);
		my ($rCrit, $wCrit) = split(/,/,$oCrit);
		my $rCode = metric($$io{$first}{"rrqm/s"},$rWarn,$rCrit);
		my $wCode = metric($$io{$first}{"wrqm/s"},$wWarn,$wCrit);
		$code = 0 if ($rCode == 0 || $wCode == 0);
		$code = 1 if ($rCode == 1 || $wCode == 1);
		$code = 2 if ($rCode == 2 || $wCode == 2);
		my $perf = "'read merged/s'=".$$io{$first}{"rrqm/s"}.";$rWarn;$rCrit;0; 'write merged/s'=".$$io{$first}{"wrqm/s"}.";$wWarn;$wCrit;0;";
		my $mgs = "I/O Queue Merged - Read merged/sec: ".$$io{$first}{"rrqm/s"}." / Write merged/sec: ".$$io{$first}{"wrqm/s"};
		quit("$mgs | $perf",$code);
	} elsif ($oMode eq "sec") {
		my ($rWarn, $wWarn) = split(/,/,$oWarn);
		my ($rCrit, $wCrit) = split(/,/,$oCrit);
		my $rCode = metric($$io{$first}{"rsec/s"},$rWarn,$rCrit);
		my $wCode = metric($$io{$first}{"wsec/s"},$wWarn,$wCrit);
		$code = 0 if ($rCode == 0 || $wCode == 0);
		$code = 1 if ($rCode == 1 || $wCode == 1);
		$code = 2 if ($rCode == 2 || $wCode == 2);
		my $perf = "'sectors read/s'=".$$io{$first}{"rsec/s"}.";$rWarn;$rCrit;0; 'sectors write/s'=".$$io{$first}{"wsec/s"}.";$wWarn;$wCrit;0;";
		my $mgs = "I/O Sectors - Read sectors/sec: ".$$io{$first}{"rsec/s"}." / Write sectors/sec: ".$$io{$first}{"wsec/s"};
		quit("$mgs | $perf",$code);
	} else {
		my $code = metric($$io{$first}{"$oMode"},$oWarn,$oCrit);
		my $perf = "'$oMode'=".$$io{$first}{"$oMode"}.";$oWarn;$oCrit;0;";
		my $mgs = "I/O - $oMode: ".$$io{$first}{"$oMode"};
		quit("$mgs | $perf",$code);
	}
}
#--------------------------------------------------------------------------------------
sub check_io {
	my $iostat = "/usr/bin/iostat";
	quit("Not found $iostat") if (!-e $iostat);
	my %inc = ("cmd" => 0, "com" => 0);
	my (@arr, @com, $hash);
	my @cmd = `$iostat -xd $oDev`;
	shift(@cmd);
	chomp(@cmd); foreach (@cmd) {
		print $_."\n" if ($oVerbose);
		if ($cmd[$inc{"cmd"}]) {
			$cmd[$inc{"cmd"}] =~ /(\w+)/;
			if ($cmd[$inc{"cmd"}] =~ /^Device.+/) {
				@com = split(/\s+/,$cmd[$inc{"cmd"}]);
				shift(@com);
			} else {
				@arr = split(/\s+/,$cmd[$inc{"cmd"}]);
				shift(@arr);
				$inc{"com"} = 0;
				foreach (@arr) {
					$hash->{$1}->{$com[$inc{"com"}]} = $arr[$inc{"com"}];
					$inc{"com"}++;
				}
			}
		}
		$inc{"cmd"}++;
	}
	return $hash;
}
#--------------------------------------------------------------------------------------
sub metric {
	my $value = shift;
	my $warn = shift;
	my $crit = shift;
	quit("Unable to check.",3) if (!$value);
	if ($value >= $crit) { return 2
	}elsif ($value >= $warn) { return 1
	}elsif ($value < $warn) { return 0
	}else{ quit("Unable to check.",3) }
}
#--------------------------------------------------------------------------------------
sub quit {
	my $mgs = shift;
	my $code = shift;
	print $mgs,"\n";
	exit($code);
}
#--------------------------------------------------------------------------------------
sub getoption  {
	Getopt::Long::Configure('bundling');
	GetOptions(
		'c|critical=s' => \$oCrit,
		'h|help' => \$oHelp,
		'v|verbose' => \$oVerbose,
		'w|warning=s' => \$oWarn,
		'm|mode=s' => \$oMode,
		'd|device=s' => \$oDev,
        );
	if($oHelp){
		printUsage();
		exit(1);
	}

	if ((!$oWarn) or (!$oCrit) or (!$oMode)){
		printUsage();
		exit(1);
	}
}
#--------------------------------------------------------------------------------------
sub logger {
        my $msg = shift (@_);
        my $log = "$path/$name.log";
        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
        $wday++;
        $yday++;
        $mon++;
        $year+=1900;
        $isdst++;
        open(LOG, ">>$log");
        printf LOG ("%02i/%02i/%i - %02i:%02i:%02i => %s\n",$mday,$mon,$year,$hour,$min,$sec,$msg);
        close(LOG);
}
#--------------------------------------------------------------------------------------
sub printUsage {
       print <<EOB
Usage: $name.pl [OPTION]...
	
	Need version iostat 7.x.x

-h, --help
-w, --warning
-c, --critical
-v, --verbose
-d, --device
	Default: First device.
-m, --mode

	tps:	Request Issued	- two metrics, ex.: -w 30,40 -c 40,50
        	r/s - The number of read requests that were issued to the device per second.
        	w/s - The number of write requests that were issued to the device per second.

	rqm:	Queue Merged - two metrics, ex.: -w 30,40 -c 40,50
		rrqm/s - The number of read requests merged per second that were queued to the device.
		wrqm/s - The number of write requests merged per second that were queued to the device.

	sec:	Sectors - two metrics, ex.: -w 30,40 -c 40,50
		rsec/s - The number of sectors read from the device per second.
		wsec/s - The number of sectors written to the device per second.

	others:
	avgrq-sz - The average size (in sectors) of the requests that were issued to the device.
	avgqu-sz - The average queue length of the requests that were issued to the device.
	await - The average time (in milliseconds) for I/O requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them.
	svctm - The average service time (in milliseconds) for I/O requests that were issued to the device.
	\%util - Percentage of CPU time during which I/O requests were issued to the device (bandwidth utilization for the device). Device saturation occurs when this value is close to 100%.

	all:	print all infomations, using metric \%util.
	
EOB
}
#--------------------------------------------------------------------------------------
&main;
