#!/usr/bin/perl 
############################################################################
# NAGIOS Adaptation of :
#
#	 bb-drbd.pl: checks the health of DRBD
# 	Version   0.6.0
# 	Created   2005-03-01 by Michael Nagel
# 	Modified  2005-07-13
#
# By Emmanuel Doguet
#
# v0.1:		first release. Must do some clean & optimize.
############################################################################


use strict;
use Getopt::Long;
use File::Copy;

use lib "/app/scripts/nagios";
use nagios_libs;





my ($BBcmd,$host,$test,$suffix,$pageColor,$date);
my ($oldFileIsOK,$oldLogFile,$newLogFile);
my ($lastTime,$newTime,@oldLog,@newLog,$maxFileDateDiff);
my (%LContent,%defs);
my ($output);
my ($GREEN_PIC, $RED_PIC, $YELLOW_PIC, $CLEAR_PIC);
my ($colwidthALARM, $colwidthDESC, $colwidthDATA, $colwidthDELTA);
my $ret;


# Set parameter to 0, if you don't want to display the descripion of the parameters
my $SHOWDESC = 1;

# max valid time between two cycles for calculating differences
$maxFileDateDiff=600;


$newLogFile="/proc/drbd"; # the status output of drbd
$oldLogFile="/tmp/drbdout";

my @hide_data_item= ( 'nr', 'ns', 'dr', 'dw');
my %perf_data_item= ( "nr", "ns");

$host = $ENV{'HOSTNAME'};

########
# Aide #
########
sub Usage {
        my ( $s ) = @_;

        if( defined( $s ) )
        {
                print "$s\n";
        }

        print "check_drbd.pl\n";
        print "  --help                Help\n";
        print "  --role                Primary/Primary,Primary/Secondary ...\n";
	exit(-1);
}

#################
# Check Options #
#################
my $o_role;
my $o_help;

sub check_options {
    Getopt::Long::Configure ("bundling");
    GetOptions(
        '--role:s'	=> \$o_role,
        '--help'   => \$o_help,
        );
}

	# Check Options
	check_options();

	Usage() if defined( $o_help );

	Usage("--role is mandatory") if not defined( $o_role );
		


setParameters();

# load the logfile content of the last cylce
$lastTime=readFileContent(\@oldLog,$oldLogFile);

	if( ! copy( $newLogFile, $oldLogFile ) )
	{
	print "exit";
		NAGIOS_SetStatus( $STATES{'CRITICAL'}, "cp $newLogFile $oldLogFile failed" );
		NAGIOS_Send();
		exit $NAGIOS_STATUS;
	}




# loads the current logfile content
$newTime=readFileContent(\@newLog,$oldLogFile);


# display the status output of drbd
#foreach (@newLog){
#	$output .= $_;
#}


# make the old logfile analyzeable
if ($lastTime && $newTime) {
	if ($newTime - $lastTime < $maxFileDateDiff){
		splitContent(\%LContent,\@oldLog,"old");
	}
}

# make the new logfile analyzeable
splitContent(\%LContent,\@newLog,"new");

# generate a table with the actual and the status of the last run
OutputDiffTable(\%LContent,$lastTime,$newTime);

# Formating output
$output =~ s/\&green/$N_COLOR_GREEN/g;
$output =~ s/&yellow/$N_COLOR_YELLOW/g;
$output =~ s/&red/$N_COLOR_RED/g;
$output =~ s/\&clear/$N_COLOR_CLEAR/g;


NAGIOS_Add( "$output\n" );
NAGIOS_Send( );

exit( $NAGIOS_STATUS );


###################################################


sub readFileContent($\@)
{
	use vars qw(@fContent);
	local(*fContent)= shift;
	my ($filename) = @_;
	my ($fileDate,$line);
	$fileDate=0;
	if (-e $filename) {

		$fileDate = (stat($filename))[9];
		open(LOG,"< $filename");
			

		foreach $line (<LOG>) {
		
			if( ! ($line =~ m/version|GIT/) )
			{
				@fContent=(@fContent,$line);	
			}

		}
		close(LOG);	
	}
	else
	{
		NAGIOS_SetStatus( $STATES{CRITICAL}, "Can't open $filename" );
                NAGIOS_Send();
                exit $NAGIOS_STATUS;

	}
	return $fileDate;
}


# extract the pairs of variates
sub splitContent(\%\@$)
{
	use vars qw(%Lcontent @fContent);
	my (@vals,$line,$p,$devId,$k,$v);
	local(*Lcontent)= shift;
	local(*fContent)= shift;
	my($oldNew) = @_;
	foreach $line(@fContent){

		$line =~ s/^\s*//g;
		if ($line =~ /cs:|ns:/){
			@vals = split /\s+/, $line;
			FIELDS: foreach $p(@vals){
				if ($line =~ /cs:/){
					if ($p =~ /^ *[0-9]+:/){
						$devId = $p;

						$devId =~ s/\D//g;	
						next FIELDS;
					}
				}	
				($k,$v) = split /:/,$p;

				$Lcontent{$devId}{$k}{$oldNew} = $v;
			}
		}
	}
}

# generate the table output
sub OutputDiffTable(\%$$)
{

	use vars qw(%Lcontent);
	local(*Lcontent) = shift;
	my($oldDate,$newDate) = @_;
	my($k,$d,$i,$maxKey,$ok,$strDummy,$strLine,$r,$head,$body, $stateOK, $NOTstateOK);
	my ($devColor, $color);
	
	
	#expand the row definions with those key which are not predefined
	$maxKey = 0;
	foreach $d(keys %defs) {
		$maxKey ++;
	}
	
	$output .= "\n";	
	foreach $d(keys %Lcontent) {
		foreach $k(keys %{ $Lcontent{$d} } ) {
			$ok = 0;
			PRESX: foreach $i( keys %defs) { 
				if ($defs{$i}{sh} eq $k) {
					$ok = 1;
					last PRESX;
				}
			}
			if ($ok == 0) {
				$maxKey++;
				$defs{$maxKey}{sh} = $k;
			}
		}
	}
	
	# devices loop
	foreach $d(keys %Lcontent) {
		$devColor = $CLEAR_PIC;
		$head = ""; # table header for the device
		$body = ""; # table body for the device
		# key loop
		for ($k=1;$k<=$maxKey;$k++) {
			$r = $defs{$k}{sh};

			$stateOK = $defs{$k}{stateOK};
			$NOTstateOK = $defs{$k}{NOTstateOK};


			if ( (defined $Lcontent{$d}{$r}{new} || defined $Lcontent{$d}{$r}{old}) && ! (grep { $_ eq $r } @hide_data_item))  {
			
				# generate the output line
				$strDummy = "$r";
				$strDummy = sprintf( '%3s', $r );
				if ($SHOWDESC) {
					$strDummy .= ': ' . $defs{$k}{tx} . ' =';
				} 

				$strLine = "$strDummy ";

				$ok = 0;
				if(defined $Lcontent{$d}{$r}{new} ) {
					if ($Lcontent{$d}{$r}{new} =~/[0-9]/g) {
						$strDummy = $Lcontent{$d}{$r}{new};
						$ok ++;
					}
					else {
						$strDummy = $Lcontent{$d}{$r}{new};
					}
				}
				else {
					$strDummy = '';
				}
				$strLine .= $strDummy;

				if ($oldDate > 0) {
					if(defined $Lcontent{$d}{$r}{old} ) {
						if ($Lcontent{$d}{$r}{old} =~/[0-9]/g) {
							$strDummy = $Lcontent{$d}{$r}{old};
							$ok++;
						}
						else {
							$strDummy = $Lcontent{$d}{$r}{old};
						}
					}
					else {
						$strDummy = '';
					}
					$strLine .= " (was: $strDummy)";
				}



				if ($oldDate > 0) {
					if ($ok==2) {
						$strDummy = ", diff=" .  ($Lcontent{$d}{$r}{new} - $Lcontent{$d}{$r}{old});
					}
					else {
						$strDummy = '';
					}
					$strLine .= $strDummy;
				}
				$strLine .= "\n";

				# checking for alerts
				if ($r eq "cs"){
					if ($Lcontent{$d}{$r}{new} eq "Connected") {
						$color = $GREEN_PIC;	
						NAGIOS_SetStatus( $STATES{'OK'}, "cs ok" );
					}
					else {
						$color = $YELLOW_PIC;
						NAGIOS_SetStatus( $STATES{'WARNING'}, "cs warn" );
					}
				}
				elsif ($r eq "ro"){

					if ($Lcontent{$d}{$r}{new} eq $stateOK )
					{
						$color = $GREEN_PIC;	
						NAGIOS_SetStatus( $STATES{'OK'}, "ro ok" );
					}
					else {
						$color = $NOTstateOK;
						NAGIOS_SetStatus( $STATES{'CRITICAL'}, "ro critical" );
					}
				}	
				elsif ($r eq "ls"){
					if ($Lcontent{$d}{$r}{new} eq "Consistent") {
						$color = $GREEN_PIC;	
						NAGIOS_SetStatus( $STATES{'OK'}, "ls ok" );
					}
					else {
						$color = $YELLOW_PIC;
						NAGIOS_SetStatus( $STATES{'WARNING'}, "ls warn" );
					}
				}
				elsif ($r eq "ua"){
					if ($Lcontent{$d}{$r}{new} > 0) {
						$color = $YELLOW_PIC;
						NAGIOS_SetStatus( $STATES{'WARNING'}, "ua warn" );
					}
					else {
						$color = $GREEN_PIC;	

						NAGIOS_SetStatus( $STATES{'OK'}, "ua ok" );
					}
				}
				else {
					$color = $CLEAR_PIC;
					NAGIOS_SetStatus( $STATES{'OK'} );
				}
				$devColor = getMainColor($devColor,$color);
			
	
				# Add alert status and line content to the table body of the current device
				$body .= "$color$strLine";
			}
		}

		$strDummy = "$devColor DEVICE: $d"; 
		$head .= "$strDummy\n\n";

		
		# put out the table header and table body of this device
		$output .= $head;
		$output .= $body;
	}

}


# switch the main color if necessary
sub getMainColor($$)
{
	my ($sumColor,$lineColor) = @_;
	if ($sumColor eq $CLEAR_PIC) {
		return $lineColor;
	}
	if ($lineColor eq $RED_PIC || $sumColor eq $RED_PIC) {
		return $RED_PIC;

	}
	if ($lineColor eq $YELLOW_PIC || $sumColor eq $YELLOW_PIC) {
		return $YELLOW_PIC;
	}
	if ($lineColor eq $GREEN_PIC || $sumColor eq $GREEN_PIC) {
		return $GREEN_PIC;
	}
	return $lineColor;
}
	


sub setParameters ()
{
	$GREEN_PIC="&green";
	$RED_PIC="&red";
	$YELLOW_PIC="&yellow";
	$CLEAR_PIC="&clear";

	$pageColor = $CLEAR_PIC;  # default value for the hole page


	# define descriptions
	$defs{1}{sh} = "cs";
	$defs{1}{tx} = "connection state";

	$defs{2}{sh} = "ro";
	$defs{2}{tx} = "state";
	$defs{2}{stateOK} = $o_role;
 	$defs{2}{NOTstateOK} = $RED_PIC;
	

	$defs{3}{sh} = "ns";
	$defs{3}{tx} = "network send";
	$defs{4}{sh} = "nr";
	$defs{4}{tx} = "network receive";
	$defs{5}{sh} = "dw";
	$defs{5}{tx} = "disk write";
	$defs{6}{sh} = "dr";
	$defs{6}{tx} = "disk read";
	$defs{7}{sh} = "of";
	$defs{7}{tx} = "on the fly";
	$defs{8}{sh} = "pe";
	$defs{8}{tx} = "pending";
	$defs{9}{sh} = "ua";
	$defs{9}{tx} = "unacknowledged";
	$defs{10}{sh} = "al";
	$defs{10}{tx} = "activity log updates";
	$defs{11}{sh} = "lo";
	$defs{11}{tx} = "reference count on local device";
	$defs{12}{sh} = "ld";
	$defs{12}{tx} = "local data consistentency";
	$defs{13}{sh} = "bm";
	$defs{13}{tx} = "bitmap updates";
	$defs{14}{sh} = "ap";
	$defs{14}{tx} = "application requests expecting io-completion";

}

