#!/usr/bin/perl

#'autor'       => 'Paulo Ribas',
#'revisao'     => 'Cleber Campanel, 25-05-2015' -> add Nagios::plugns
#'bug'         => 'Cleber Campanel, 13-11-2015' -> Ajuste nos thresholds para não mostar : no dado de performance e utilizar o valor após os :
#release - 1.6 => 'Cleber Campanel, 29-03-2016' -> hash map mensage code printer
#release - 1.7 => 'Cleber Campanel, 22-04-2016' -> hash map mensage code ApplicationPool
#release - 1.8 => 'Guilherme Hoescher, 05-05-2016' -> hash map mensage code ClusterResourceGroup
#release - 1.9 => 'Guilherme Hoescher, 12-12-2016' -> hash map message code exitNetConnectionStatus

use strict;
use Nagios::Plugin;
#use Getopt::Long;
use Getopt::Long qw(:config no_ignore_case bundling);
use File::Basename;
use Term::ANSIColor;
use Data::Dumper;

our ($no_ssl, $query_wmi);
our (@dataParser , $argumento );

#evil globals but Perl loves them
use vars qw($sess $np $status $msg);

#Other vars
my ($VERSION,$PROGNAME);
my ($onlyTest,$warn,$crit);

our %exitPrinterForhuman = ( 0 => 'OK',
                  1 => 'Unknown Error',
                  2 => 'Unknown Error',
                  3 => 'Low Paper',
                  4 => 'No Paper',
                  5 => 'Low Toner',
                  6 => 'No Toner',
                  7 => 'Door Open',
                  8 => 'Jammed',
                  9 => 'Offline',
                  10 => 'Service Requested',
                  11 => 'Output Bin Full',
                   );

our %exitApplicationPoolForhuman = (
                  1 => 'Uninitialized',
                  2 => 'Initialized',
                  3 => 'Running',
                  4 => 'Disabling',
                  5 => 'Disabled',
                  6 => 'Shutdown Pending',
                  7 => 'Delete Pending',
                   );

our %exitClusterResourceGroupForHuman = ( 0 => 'Online',
                  1 => 'Offline',
                  2 => 'Failed',
                  3 => 'Partial Online',
                  4 => 'Pending',
                   );	

our %exitNetConnectionStatus = ( 0 => 'Interface Disabled - Check if is necessary to monitor this interface and then enable it.',
                  1 => 'Connecting',
                  2 => 'Connected',
                  3 => 'Disconnecting',
                  4 => 'Interface Disabled - Check if is necessary to monitor this interface and then enable it.',
				  5 => 'Interface Disabled - Check if is necessary to monitor this interface and then enable it.',
				  6 => 'Hardware Malfunction',
				  7 => 'Cable Disconnected',
				  8 => 'Authenticating',
				  9 => 'Authentication Succeeded',
				  10 => 'Authentication Failed',
				  11 => 'Invalid Address',
				  12 => 'Credentials Required',				  
                   );					   


#INIT
$VERSION = "1.8";
$PROGNAME = basename($0);
$status = 0;
$msg = undef;
$onlyTest = 0;

$np = Nagios::Plugin->new(
  usage => "Usage: %s -H <host> [-p <port>] [ -C <command> ] -A \"<query wmi>\" [ -w <threshold> ] [ -c <threshold> ] ",
  version => $VERSION,
  blurb => "This plugin return query wmi",
  extra => "Note: ",
  shortname => " ",

);

# Define and document the valid command line options
# usage, help, version, timeout and verbose are defined by default.
$np->add_arg(
  spec => 'host|H=s',
  help =>
  qq{
 -H, --host=ADDRESS
   Host name or IP Address},
  required => 1
);

$np->add_arg(
  spec => 'wmi_query|A=s',
  help =>
  qq{
 -A, --wmi_query=Text
   Query WMI},
  required => 1
);

$np->add_arg(
  spec => 'command|C=s',
  help =>
  qq{-C, --command=STRING
   NRPE command (default: priaxwmi)
   },
  required => 0,
  default => 'priaxwmi'
);

$np->add_arg(
     spec => 'warning|w=s',
     help => '-w, --warning=INTEGER:INTEGER .  See '
       . 'http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT '
       . 'for the threshold format. ',
   );

$np->add_arg(
     spec => 'critical|c=s',
     help => '-c, --critical=INTEGER:INTEGER .  See '
       . 'http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT '
       . 'for the threshold format. ',
   );

$np->add_arg(
  spec => 'port|p=i',
  help =>
  qq{-p, --port=INTEGER
   Port nrpe agent},
  required => 0,
  default => 5666
);

$np->add_arg(
  spec => 'unit|u=s',
  help =>
  qq{-u, --unit=String },
  required => 0,
);

$np->add_arg(
  spec => 'replace_code|R=s',
  help =>
  qq{-R, --replace_code=String 
    This option is used to change the status code from checks. Sample: -R 9:2,18:1 This means that if the return from check is 9, then the exit code is set to 2 (Critical), if 18 the exit code is set to 1 (Warning) despite from Warning or Critical thresholds.},
  required => 0,
);

$np->add_arg(
  spec => 'service_name|S=s',
  help =>
  qq{-S, --service_name=String
   Service Name configurate in OpMon},
  required => 0,
  default => 'value'
);

$np->add_arg(
  spec => 'no_ssl|n',
  help =>
  qq{-n, --no_ssl=boolean
   Agent OpMon without ssl},
  required => 0,
);

$np->add_arg(
  spec => 'namespace|N=s',
  help =>
  qq{-N, --namespace=STRING
   namespace
   },
  default => 'ROOT\CIMV2'
);


##### Parse arguments end do error checking !!!MORE CHECKS NEEDED!!!
$np->getopts;

#print Dumper $np;

$no_ssl = "-n" if($np->opts->no_ssl) ;

#print "ssl: $no_ssl \n";

if($np->opts->wmi_query =~ /Win32_PerfFormattedData_Tcpip_NetworkInterface/i){
        my @split_where = split /where/i,$np->opts->wmi_query ,2;
  #     print Dumper \@split_where[1];
        @split_where[1] =~ tr/(/[/;
        @split_where[1] =~ tr/)/]/;
        @split_where[1] =~ tr/#/_/;
        @split_where[1] =~ tr/\//_/;
  # print Dumper \@split_where;
  $query_wmi = join(' WHERE ', @split_where);
}else{

  $query_wmi = $np->opts->wmi_query;
}
#print Dumper $np->opts;
my $host = $np->opts->host;
my $port = $np->opts->port;
my $command = $np->opts->command;
my $namespace = $np->opts->namespace;

#my $output = "/usr/local/opmon/libexec/priax/nrpe/check_nrpe -H $host $no_ssl -p $port -t 30 -c $command -a \"$query_wmi\" \"$namespace\"";
#print "$output\n";
#exit;
my $output = `/usr/local/opmon/libexec/priax/nrpe/check_nrpe -H $host $no_ssl -p $port -t 30 -c $command -a \"$query_wmi\" \"$namespace\"`;
my $exit_code = $?>>8;

#caso a query esteja errada o exit_code deve ser desconhecido
if($output =~ /error: execquery/i){
        $output = "The query was not syntactically valid.";
        $exit_code = 3;
}
if($output =~ /No Result/i){
        $output = "No results found. Nothing to show or maybe some parameter is not set appropriately.";
        $exit_code = 3;
}

if($output =~/Could not complete SSL handshake/i){
        $output = "Could not complete SSL handshare. Check SSL connection parameters.";
        $exit_code = 3;
}
if($output =~/2147749947/i){
        $output = "Could not run WMI query.Disk is out of space or the 4 GB limit on WMI repository size is reached. Check for WMI error 2147749947.";
        $exit_code = 3;
}

chomp($output);

#my @return = split (/ /,$check_disk);
#print Dumper $output;
#print Dumper $exit_code;
#exit;


if($exit_code >= 3){
  #($output,$exit_code);

  $np->nagios_exit(UNKNOWN,$output);
}

#verifica thresholds
my $code = $np->check_threshold( check => $output);
#print Dumper $code;

#adiciona perf data
#setar apenas o valor de end para o opmon entender corretamente, o checagem ja foi feita.
$np->set_thresholds(warning => $np->threshold->warning->end, critical => $np->threshold->critical->end );
#print Dumper $np->threshold;
#print Dumper $np->threshold->critical->start;
$np->add_perfdata(
      label => "'".$np->opts->service_name."'",
      value => $output,
      uom => $np->opts->unit,
      threshold => $np->threshold
   );

#print Dumper $np;

##mudar a saida os codigos da impressora para as mensagens

my $outputForHuman = $output;
#Printer
if( $query_wmi =~ /DetectedErrorState FROM Win32_Printer/i ){
  if( $exitPrinterForhuman{$output}){
    $outputForHuman = $exitPrinterForhuman{$output};
  }

  if($np->opts->replace_code){
    #print Dumper $np->opts->replace_code;
    my @forHumanCodes = split /,/, $np->opts->replace_code;
    #print Dumper @forHumanCodes;
    foreach (@forHumanCodes)
    {
      my $string = $_;
      my @subForHumanCodes = split /:/, $string;
      #print Dumper $output;
      #print Dumper(@subForHumanCodes[0]);
      #print Dumper(@subForHumanCodes[1]);
      if(@subForHumanCodes[0] == $output){
        $code = @subForHumanCodes[1];
      }
    }
  }
}

#NetConnectionStatus
if( $query_wmi =~ /NetConnectionStatus FROM Win32_NetworkAdapter/i ){
  if( $exitNetConnectionStatus{$output}){
    $outputForHuman = $exitNetConnectionStatus{$output};
  }

  if($np->opts->replace_code){
    my @forHumanCodes = split /,/, $np->opts->replace_code;
    foreach (@forHumanCodes)
    {
      my $string = $_;
      my @subForHumanCodes = split /:/, $string;
      if(@subForHumanCodes[0] == $output){
        $code = @subForHumanCodes[1];
      }
    }
  }
}

#ApplicationPool
if( $query_wmi =~ /CurrentApplicationPoolState from Win32_PerfFormattedData_APPPOOLCountersProvider_APPPOOLWAS/i ){
  if( $exitApplicationPoolForhuman{$output}){
    $outputForHuman = $exitApplicationPoolForhuman{$output};
  }

  if($np->opts->replace_code){
    #print Dumper $np->opts->replace_code;
    my @forHumanCodes = split /,/, $np->opts->replace_code;
    #print Dumper @forHumanCodes;
    foreach (@forHumanCodes)
    {
      my $string = $_;
      my @subForHumanCodes = split /:/, $string;
      #print Dumper $output;
      #print Dumper(@subForHumanCodes[0]);
      #print Dumper(@subForHumanCodes[1]);
      if(@subForHumanCodes[0] == $output){
        $code = @subForHumanCodes[1];
      }
    }
  }
}

#ClusterResourceGroup
if( $query_wmi =~ /State FROM MSCluster_ResourceGroup/i ){
  if( $exitClusterResourceGroupForHuman{$output}){
    $outputForHuman = $exitClusterResourceGroupForHuman{$output};
  }

  if($np->opts->replace_code){
    my @forHumanCodes = split /,/, $np->opts->replace_code;
    foreach (@forHumanCodes)
    {
      my $string = $_;
      my @subForHumanCodes = split /:/, $string;
        if(@subForHumanCodes[0] == $output){
        $code = @subForHumanCodes[1];
      }
    }
  }
}

##

my $msg = $np->opts->service_name." = ".$outputForHuman.$np->opts->unit;
$np->nagios_exit($code,$msg);
