#!/usr/bin/perl
#===============================================================================
#
#         FILE: check_opcem.pl
#
#        USAGE: ./check_opcem.pl
#
#       AUTHOR: Bruno Miranda
# ORGANIZATION: OpServices
#      VERSION: 1.0.1
#      CREATED: 09-05-2013 14:02:32
#===============================================================================

use strict;
use warnings;
use utf8;
use Getopt::Long;
use File::Basename;
use IPC::Open3;
use Switch;
use Date::Parse;
no strict 'refs';

my $VERSION='1.0.1';
my $check_nrpe = '/usr/local/opmon/libexec/check_nrpe';

sub version() {
    print "Version: ", $VERSION, "\n";
}

sub usage(){
	print "Usage:\n";
	print "    ", basename($0), " -H <hostname1,hostname2...> -p <port> -P <path> [OPTIONS]...\n";
}

sub help() {
    print  << 'HELP';

    This plugin performs the reading of the execution log of the robots
graphics, in one or more hosts at one time. To check the status of a robot in
more than one host at the same time it is necessary that the directory where
the robot was created to be the same.

    This plugin uses the OpMon agent 3.9 or higher.

HELP
    usage();
    print << 'HELP';

 -c | --critical       Maximum time in minutes that the robot can get without
                   executed. If CRITICAL time not defined, Robot will not be
                   checked if it is still running.
 -h | --help           Show this help.
 -H | --hostname       Address of host where robots run.
 -n | --nossl          Do not use ssl for check.
 -p | --port           NRPE port.
 -P | --path           Directory where the robot was created.
 -t | --timeout        Timeout so that the host will answer the request.
                   Default is 10;
 -V | --version        Shows the version of this plugin.
 -v | --verbose        Verbose level. Default is 0.

HELP
}
sub getOptions() {
	my %args;

    Getopt::Long::Configure('bundling');
    Getopt::Long::Configure('pass_through');
    GetOptions(
		'c|critical=s'	=> \$args{ critical },
		'h|help'		=> \$args{ help },
       	'n|nossl'		=> \$args{ ssl },
       	'H|hostname=s'	=> \$args{ hostname },
       	'p|port=s'	    => \$args{ port },
       	'P|path=s'	    => \$args{ path },
		'v|verbose=i'	=> \$args{ verbose },
		'V|Version'		=> \$args{ version },
		't|timeout=i'	=> \$args{ timeout },
    );

	if (defined($args{ version })){
        version();
        exit(0);
    }

	if (defined($args{ help })){
        help();
        exit(0);
    }

    if ((not defined($args{ port })) || (not defined($args{ hostname })) || (not defined($args{ path }))) {
        usage();
        exit(3);
    }

	$args{ verbose } = 0 if (not defined($args{ verbose }));
	$args{ timeout } = 10 if (not defined($args{ timeout }));
    if (defined($args{ critical })) {
		$args{ critical } =~ s/m//;
	    $args{ critical } *= 60;
    } else {
        $args{ critical } = 0;
    }

    @{ $args{ hostname } } = split(',',$args{ hostname });

    return %args;
} ## --- end sub getOptions


sub getRobotStatus($%) {
        my ($hostname,%args) = @_; 
        my $ret_command;

        my $command = $check_nrpe . ' -H ' . $hostname . ' -p ' . $args{ port } . ' -c read_file -t ' . $args{ timeout };
        $command = $command . ' -n' if (defined($args{ ssl }));
        $command = $command . ' -a "' . $args{ path } . '\status.log"';

        print $command . "\n" if ($args{ verbose } > 0) ;

        $ret_command = `$command `;

        if ($args{ verbose } > 0) {
                print $ret_command;
                print "--------------------------------------------------------\n";
        }   

        return $ret_command;
} ## --- end sub execCommand

sub checkLogAge($@) {
    my ($critical, @robot_logs) = @_;
    my ($date, $time_log, @ret);

    if ($critical > 0) {
        foreach(@robot_logs) {
            if ($_ =~ /.*(\d\d)\/(\d\d)\/(\d\d\d\d).*(\d\d:\d\d:\d\d).*/) {
                $date = $3 . '-' . $2 . '-' . $1 . ' ' . $4;
                $time_log = str2time($date);
                push(@ret, $_) if ($time_log > (time() - $critical));
            }
        }

        return @ret if (defined($ret[0]));
    }
    return;
} ## --- end sub checkLogAge

sub checkReturnStatus($) {
    my $robot_log = shift;
    my @status = split(':', $robot_log);

    return "OK" if ($status[0] =~ /^ok/i);
    return "WARNING" if ($status[0] =~ /^warning/i);
    return "CRITICAL" if ($status[0] =~ /^critical/i);

    return "UNKNOWN";
} ## --- end sub checkReturnStatus

sub compareNotTimeout(@){
    my @logs = @_;
    my ($better_time, $time, $log);

    $better_time = 99999999;

    foreach(@logs) {
        if($_ =~ /.* (\d+.?\d*) (segundos|seconds).*/) {
            $time = $1;
            if ($time < $better_time) {
                $better_time = $time;
                $log = $_;
            }
        }
    }

    return $log;
}

sub compareTimeout(@) {
    my @logs = @_;
    my $latest = -9999999999;
    my ($log, $date, $time_log);

    foreach(@logs) {
        if ($_ =~ /.*(\d\d)\/(\d\d)\/(\d\d\d\d).*(\d\d:\d\d:\d\d).*/) {
            $date = $3 . '-' . $2 . '-' . $1 . ' ' . $4;
            $time_log = str2time($date);
            if ($time_log > $latest) {
                $latest = $time_log;
                $log = $_;
            }
        }
    }

    return $log;
}
sub selectLog($@){
    my ($critical, @logs) = @_;
    my (@pri_logs, @aux);

    @aux = checkLogAge($critical, @logs);

    return $logs[0] if ((@aux == 0) && (($logs[0] =~ /.*CHECK_NRPE:.*(Error|timeout|timed out).*/i) || ($logs[0] =~ /.*Connection refused or timed out.*/i)));
    return if (@aux == 0);
    @logs = @aux;

    foreach(@logs) {
        push(@pri_logs, $_) if ($_ =~ /^OK/);
    }

    if (@pri_logs == 0) {
        foreach(@logs) {
            push(@pri_logs, $_) if ($_ =~ /^WARNING/);
        }
    }

    if (@pri_logs == 0) {
        foreach(@logs) {
            push(@pri_logs, $_) if ($_ !~ /^CRITICAL:.*timeout.*/);
        }
    }

    @pri_logs = @logs if (@pri_logs == 0);

    return compareNotTimeout(@pri_logs) if (($pri_logs[0] !~ /.*CHECK_NRPE:.*(Error|timeout|timed out).*/i) && ($pri_logs[0] !~ /.*Connection refused or timed out.*/i));
    return compareTimeout(@pri_logs) if ($pri_logs[0] =~ /^CRITICAL:.*timeout.*/i);
    return $pri_logs[0];
}

sub main{
    my %args = getOptions();
    my (@robot_log, $selected_log);

    push (@robot_log, getRobotStatus($_, %args)) foreach (@{$args{ hostname }});

    $selected_log = selectLog($args{ critical }, @robot_log);
    
    if (not defined($selected_log)) {
        print "CRITICAL: Robo sem execucao a mais de ", $args{ critical } / 60, " minutos.\n";
        exit(2);
    }

    chomp($selected_log) if (defined($selected_log));

    switch(checkReturnStatus($selected_log)) {
        case 'OK' { print $selected_log, "\n"; exit(0) }
        case 'WARNING' { print $selected_log, "\n"; exit(1) }
        case 'CRITICAL' { print $selected_log, "\n"; exit(2) }
        case 'UNKNOWN' { print "UNKNOWN: Nao foi possivel obter o status do robo: \"$selected_log\"\n"; exit(3) }
    }

    print "CRITICAL: Comportamento inesperado ao verificar o status do robo.\n";
    exit(2);
} &main
