#!/usr/bin/perl

#################################################################################################
##
## check_bdd_request.pl version 1.0
## 2013 Alexandre Frandemiche
##
## 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 2 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.
## The GNU GPL V2 is available at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
##
## contact the author directly for more information at:
## slobberbone4884 at gmail.com or on http://www.slobberbone.net
##
##################################################################################################
##
## Check if the result of a MySQL request is ==, <, >, <=, => a number
## which is warning and/or critical when check_type=NUMERIC
## or, only return a result of a SQL request.
## It works with MySQL only for now.
## This plugin requires that perl, perl-DBD-MySQL, perl-DBI package are installed on the system.
##
## Exit 0 on success, providing some information
## Exit 2 on failure.
##

########## IMPORT PACKAGES ##########

use strict;
use Getopt::Long;
use DBI;

########## NAGIOS CODE ##########

my %ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);

########## VARIABLES ##########

my $Version='1.0';
my $Name=$0;
my $count = 0;
my $text = "";
my $state = "OK";
my $status = "";

my $o_host =		undef; 		# hostname 
my $o_help=		undef; 		# want some help ?
my $o_user= 		undef; 		# user
my $o_password=		undef;          # password
my $o_database=		undef;          # database
my $o_port=		undef;     	# port
my $o_request=		undef;		# SQL resquest
my $o_check_type=	undef;		# check type
my $o_operator=		undef;		# operator for numeric request
my $o_version= 		undef;  	# print version
my $o_warn_level=	undef;  	# number cause a warning
my $o_crit_level=	undef;  	# number cause an error
my $o_timeout=  	15;            	# default 15s Timeout

########## MAIN ##########

check_options();

# Connection to MySQL database
my $dbh = DBI->connect( "dbi:mysql:database=$o_database;host=$o_host;port=$o_port;", $o_user, $o_password )
  or die "Fail to connect to the database : $o_database !";

# Treatment for numeric result
if($o_check_type eq "NUMERIC"){
	$count = call_request_count($dbh,$o_request);
	 #print "$count $o_operator $o_crit_level \n\n";
	if ($o_operator eq "LT") {
		if ($count < $o_warn_level) { $state = "WARNING"; }
		if ($count < $o_crit_level) { $state = "CRITICAL"; }
		if ($count =~ m/\D/) { $state = "UNKNOWN"; }
		#print "$count < $o_crit_level \n\n";
	}
	elsif ($o_operator eq "GT") {
		if ($count > $o_warn_level) { $state = "WARNING"; }
		if ($count > $o_crit_level) { $state = "CRITICAL"; }
		if ($count =~ m/\D/) { $state = "UNKNOWN"; }
		#print "$count > $o_crit_level \n\n";
	}
	elsif ($o_operator eq "LE") {
		if ($count <= $o_warn_level) { $state = "WARNING"; }
		if ($count <= $o_crit_level) { $state = "CRITICAL"; }
		if ($count =~ m/\D/) { $state = "UNKNOWN"; }
		#print "$count <= $o_crit_level \n\n";
	}
	elsif ($o_operator eq "GE") {
		if ($count >= $o_warn_level) { $state = "WARNING"; }
		if ($count >= $o_crit_level) { $state = "CRITICAL"; }
		if ($count =~ m/\D/) { $state = "UNKNOWN"; }
		#print "$count => $o_crit_level \n\n";
	}

	if ($ERRORS{$state} >= 0) {
		$status = "Rows $state - $count rows\n";
	} else {
		$status = "Rows $state - mysql: $count\n";
	}
}
# Treatment for return information only
elsif($o_check_type eq "TEXT"){
	$text = call_request_text($dbh,$o_request);
	$state = "OK";
	$status = "$state - $text\n";
}
# Treatment unknown
else{
	print "Check type unknown";
	$state = "UNKNOWN";
	$status = "$state - Unknown operation\n";
}

# Return code to Nagios
print $status;
exit $ERRORS{$state};

########## FUNCTIONS ##########

# Display plugin's version
sub show_versioninfo { print "$Name version : $Version\n"; }

# Display plugin's usage
sub print_usage {
  print "Usage: $Name -H <host> -u <user> -p <password> -d <database> -P <port> -q request -t check_type -o <operator> [-w <warn_level> -c <crit_level> -T <timeout>] -V\n";
}

# Check parameters passed to the plugin
sub check_options {
  Getopt::Long::Configure ("bundling");
  GetOptions(
      'h'     => \$o_help,        'help'          => \$o_help,
      'H:s'   => \$o_host,        'hostname:s'	  => \$o_host,
      'u:s'   => \$o_user,        'user:s'	  => \$o_user,
      'p:s'   => \$o_password,    'password:s'	  => \$o_password,
      'd:s'   => \$o_database,    'database:s'	  => \$o_database,
      'P:i'   => \$o_port,        'port:i'	  => \$o_port,
      'q:s'   => \$o_request,     'request:s'     => \$o_request,
      't:s'   => \$o_check_type,  'check_type:s'  => \$o_check_type,
      'o:s'   => \$o_operator,    'operator:s'    => \$o_operator,
      'w:i'   => \$o_warn_level,  'warn:i'	  => \$o_warn_level,
      'c:i'   => \$o_crit_level,  'critical:i'	  => \$o_crit_level,
      'T:i'   => \$o_timeout,     'timeout:i'     => \$o_timeout,
      'V'     => \$o_version,     'version'       => \$o_version,

  );

  if (defined ($o_help)) { help(); exit $ERRORS{"UNKNOWN"}};
  if (defined($o_version)) { show_versioninfo(); exit $ERRORS{"UNKNOWN"}};
  if (defined($o_check_type)) {
	if ($o_check_type eq "NUMERIC") {
		if (((!defined($o_warn_level) && !defined($o_crit_level)) || (!defined($o_crit_level)) || (defined($o_warn_level) && defined($o_crit_level) && ($o_warn_level < 0 || $o_crit_level < 0)))) { 
		    print "Check warn and crit!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}
		}
		if (!defined($o_operator)) {
			print "Check operator, if not the case, use --check_type=TEXT !\n"; print_usage(); exit $ERRORS{"UNKNOWN"}
		}
	}
  }

  if (!defined($o_host) || !defined($o_user) || !defined($o_password) || !defined($o_database) || !defined($o_port) || !defined($o_request)){ print_usage(); exit $ERRORS{"UNKNOWN"}};
}

# Display help and plugin's features
sub help {
  print "Check_bdd_request for Nagios, version ",$Version,"\n";
  print "GPL licence, (c)2013 Slobberbone\n\n";
  print "Site http://www.slobberbone.net\n\n";
  print_usage();
  print <<EOT;
-h, --help
   print this help message
-H, --hostname=HOST
   name or IP address of MySQL server
-u, --user=USER
   mysql user to login
-p, --password=PASSWORD
   mysql password
-d, --database=DATABASE
   mysql database name
-P, --port=PORT
   Http port
-q, --request="REQUEST"
   Request to execute on the server	
-t, --check_type=TYPE
   Type of return :
	NUMERIC,
	TEXT
-o, --operator=OPERATOR
   Operator :
	EQ for =,
	LT for <,
	GT for >,
	LE for <=,
	GE for >=,
	DIF for !=
-w, --warn=INTEGER
   number that will cause a warning completed by the OPERATOR
   -1 for no warning
-c, --critical=INTEGER
   number that will cause an error completed by the OPERATOR
-T, --timeout=INTEGER
   timeout in seconds (Default: $o_timeout)
-V, --version
   prints version number
Note :
  The script will return
    * With warn and critical options:
        OK       if we are able to connect to the MySQL server and #request count result respect <warn_level>,
        WARNING  if we are able to connect to the MySQL server and #request count result unrespect <warn_level>,
        CRITICAL if we are able to connect to the MySQL server and #request count result unrespect <crit_level>,
        UNKNOWN  if we aren't able to connect to the MySQL server

EOT
}

# Execute SQL request for returned only information
sub call_request_text { 
  my $dbh = shift; 
  my $text = ""; 
  my $o_request = shift;
  my $request_SQL = $o_request;
 
  my @results; 
  my $prep = $dbh->prepare($request_SQL) or die $dbh->errstr; 
  $prep->execute() or die "Request faillure\n"; 
  while ( my ($result) = $prep->fetchrow_array ) { 
    push( @results, $result );
  } 
  $prep->finish(); 
  $text=@results[0];
  return $text; 
} 

# Execute SQL request for returned a number to compare
sub call_request_count { 
  my $dbh = shift; 
  my $count = 0; 
  my $o_request = shift;
  my $request_SQL = $o_request;
 
  my @results; 
  my $prep = $dbh->prepare($request_SQL) or die $dbh->errstr; 
  $prep->execute() or die "Request faillure\n"; 
  while ( my ($result) = $prep->fetchrow_array ) { 
    push( @results, $result );
    $count++;
  } 
  $prep->finish(); 
 
  return $count; 
} 
