#!/usr/bin/perl -w
# nagios: -epn
#
# Probe for checking of FTS service status
#
# Copyright (c) 2007 CERN
#
# Based on DPM-probe by Emir Imamagic
#
# Sep 2011 - taken over by FTS team
#

use strict;
use Getopt::Long;
use LWP::UserAgent;
use XML::Parser;
use Sys::Syslog;
use TOM::Nagios qw(nagios_debug);

local $SIG{__DIE__}  = \&TOM::Nagios::handle_die;
local $SIG{__WARN__} = \&TOM::Nagios::handle_warn;
openlog("FTS-probe", "ndelay,pid", "user");
nagios_debug("started");

use GridMon::sgutils qw($SERVICEURI $SERVICETYPE $METRICNAME $SRM_PATH $GLITE_LOCATION $GLOBUS_TCP_PORT_RANGE $VONAME $TIMEOUT $OUTPUT_TYPE @METRICS %ERRORS %OUTPUT_TYPES %COMMANDS &print_revision &support &printOutput &checkCommands &checkProxy &createProxy &checkHost &checkEnvironment &checkMetric &printWLCGList);

my $PROGNAME = "FTS-probe";
my $REVISION = "1.0";
# JC TODO - Update SERVICEVERSION
my $SERVICEVERSION = "1.0";
my $DEFAULT_PORT = 8443;
my $METHOD_URI = "glite-data-transfer-fts/services/ChannelManagement?method=listChannels";

$SERVICETYPE = "glite-FTS-WS";
@METRICS = ("ch.cern.FTS-ChannelList", "ch.cern.FTS-InfoSites");

sub print_usage () {
    print "Usage: $PROGNAME
    -u, --serviceuri=SERVICEURI
        Service URI. Accepted URIs are:
            [https://]host[:port]/
        Example:
            https://myhost:8443/
    
    -H, --hostname=HOST
        Name or IP address of host to check
        Option can be used only for Nagios style.        
    -p, --port=INTEGER
        Port that the server is running on <host> 
        (Default: $DEFAULT_PORT)
        Option can be used only for Nagios style.        
                    
    -c, --cert=CERTFILE
        Location of Nagios user's certificate file 
        (Default: \$HOME/.globus/usercert.pem)
    -k, --key=CERTFILE
        Location of Nagios user's key file 
        (Default: \$HOME/.globus/userkey.pem)
    -x, --proxy=CERTFILE
        Location of Nagios user's proxy file 
        (Default: /tmp/x509up_u$<)
    -f, --passfile=PASSPHRASEFILE
        Location of file where grid passphrase is stored 
        (Default: )
    -v, --vo=STRING
        Virtual organization of user 
        (Default: )        
    
    -t, --timeout=INTEGER
        Set timeout in seconds
        (Default: $TIMEOUT)
    -V, --version
        Print plugin version
    --verbose
        Print extra debugging information
    -h, --help
        Print help message
    
    -m, --metric=STRING (".join (", ", @METRICS).")
        Which metric to perform            
    -l
        Print WLCG-style metric list     
    -n
        Produce output in Nagios style
";
}


sub print_help () {
        print_revision($PROGNAME, $REVISION,$SERVICEVERSION);
        print "Copyright (c) 2007 CERN

Probe for checking $SERVICETYPE Service";

        print_usage();
        print "\n";
        support();
}

my $CHANNEL_COUNT = 0;

sub xmlChar {
    my $p = shift;
    my $data = shift;
    if ($p->in_element("listChannelsReturn")) {
	++$CHANNEL_COUNT;
    }
}

sub getChannelList {
    my $hostname = shift;
    my $port = shift;
    my $url = "https://$hostname:$port/$METHOD_URI";

    my $ua = LWP::UserAgent->new(env_proxy=>1);
    $ua->agent("Nagios $SERVICETYPE-probe/$REVISION");
    my $req = HTTP::Request->new(GET => $url);
    my $res = $ua->request($req);

    if (!$res->is_success) {
	return ($ERRORS{CRITICAL}, "Test failed with HTTP error: " . $res->status_line . "\n");
    }

    my $parser = new XML::Parser(ErrorContext => 2);
    $parser->setHandlers(Char => \&xmlChar );
    $parser->parse($res->content);
    if ($CHANNEL_COUNT==0) {
	return ($ERRORS{WARNING}, "Warning - No Channels Found\n");
    }
    return ($ERRORS{OK}, "OK - Found $CHANNEL_COUNT channels\n");
}

# variables for  parameters
my ($opt_V,$opt_h,$opt_H,$verbose,$opt_p,$opt_t,$opt_w,$opt_c,$hostname,$port);
my ($cert,$key,$proxy,$pass,$vo,$serviceurl);

sub getInfoSites{
	my $hostname = shift;
	my $output = "Checking if FTS node $hostname is registered in the infosystem:" if ($verbose) or '';
	my $cmd = "lcg-infosites --vo $vo fts";
	$output = $output."\n$cmd\n" if ($verbose);
	my $cmdout = `$cmd`;
    if ($? == 0) {
    	my @ftsURL = grep /$hostname/,split("\n",$cmdout);
    	if (@ftsURL) {
	    	if ($verbose) {
	    		$output = "OK: $ftsURL[0]\n".$output.$ftsURL[0]."\n";
	    	} else  {
	    		$output = "OK: $ftsURL[0]\nOK: $ftsURL[0]\n";
	    	}
			return ($ERRORS{OK}, $output);
    	} else {
    		return ($ERRORS{CRITICAL}, "CRITICAL: FTS node $hostname is NOT registered in the infosystem\nCommand used: $cmd\n");
    	}
    } else {
    	$output = $output.$cmdout if ($verbose);
    	return ($ERRORS{WARNING}, "WARNING: failed to get FTS info with lcg-infosites\n$output");
    }
}

##### Main program

my $res = undef;
my $answer = undef;
my $state = $ERRORS{OK};

my $nagios;
my $wlcgList;

# Just in case of problems, let's not hang Nagios
$SIG{ALRM} = sub {
    local $SIG{TERM} = 'IGNORE';
    kill TERM => -$$;
    printOutput($ERRORS{CRITICAL}, "Timeout occured during DPM query.\n");
};

local $SIG{TERM} = sub { 
    local $SIG{TERM} = 'IGNORE';
    kill TERM => -$$;
    printOutput($ERRORS{UNKNOWN},"Plugin received TERM signal.\n");
};

Getopt::Long::Configure('bundling');
if (!GetOptions
    ("verbose"      => \$verbose,
    "V"    => \$opt_V,      "version"      => \$opt_V,
    "h"    => \$opt_h,      "help"         => \$opt_h,
    "H=s"  => \$opt_H,      "hostname=s"   => \$opt_H,
    "p=s"  => \$opt_p,      "port=s"       => \$opt_p,
    "t=s"  => \$opt_t,      "timeout=s"    => \$opt_t,
    "c=s"  => \$cert,       "cert=s"       => \$cert,
    "k=s"  => \$key,        "key=s"        => \$key,
    "x=s" => \$proxy,       "proxy=s"      => \$proxy,
    "f=s" => \$pass,        "passfile=s"   => \$pass,
    "v=s" => \$vo,        "vo=s"   => \$vo,
    "n"   => \$nagios,
    "l"   => \$wlcgList,
    "u=s" => \$SERVICEURI, "serviceuri=s" => \$SERVICEURI,
     "m=s" => \$METRICNAME, "metric=s" => \$METRICNAME)) {
    exit 1;
}


if ($opt_V) {
    print_revision($PROGNAME, $REVISION,$SERVICEVERSION);
    exit $ERRORS{OK};
}

if ($opt_h) {
    print_help(); 
    exit $ERRORS{OK};
}

if ($wlcgList) {
    printWLCGList();
    exit $ERRORS{OK};
}

if ($nagios) {
    $OUTPUT_TYPE = $OUTPUT_TYPES{NAGIOS};
}

if ($OUTPUT_TYPE == $OUTPUT_TYPES{WLCG}) {
    printOutput ($ERRORS{UNKNOWN}, "Service URI must be defined.\n") unless($SERVICEURI);
}

# Options checking

# Checks external commands
checkCommands();

# Checks metric
checkMetric($METRICNAME);

if ($opt_t && $opt_t =~ /^([0-9]+)$/) { $TIMEOUT = $1; }

# Form full Service URI
if ($SERVICEURI) {
    if ($SERVICEURI =~ /(https:\/\/)?([-_.A-Za-z0-9]+)(:(\d+))?/) {
        $hostname = $2;    
        if ($4) {
            $port = $4;
        } else {
            $port = $DEFAULT_PORT;
        }
    } else {
        printOutput ($ERRORS{UNKNOWN}, "Service URI $SERVICEURI has incorrect form ([https://]host[:port]).\n");
    }
} else {
    $hostname = checkHost($opt_H);
    if ($opt_p) {
        if ($opt_p =~ /^([0-9]+)$/) {
            $port = $opt_p;
        } else {
            printOutput ($ERRORS{UNKNOWN}, "Port $opt_p has incorrect format.\n");        
        }
    } else {
        $port = $DEFAULT_PORT;
    }    
}

alarm($TIMEOUT);
#
($cert) and $ENV{'X509_USER_CERT'}=$cert;
($key) and $ENV{'X509_USER_KEY'}=$key;

($state,$answer,$res) = checkProxy($proxy);
if ( $state != $ERRORS{OK}) {
    ($state,$answer,$res) = createProxy($pass, $vo);
    printOutput ($state,$answer,$res) if ($state != $ERRORS{OK});
}

# GSI Stuff from http://www.gridsite.org/wiki/Perl_Clients for LWP
$ENV{HTTPS_CA_DIR} = (defined $ENV{X509_CERT_DIR})?$ENV{X509_CERT_DIR}:"/etc/grid-security/certificates";
# ---- GSI Magic to make it work ----
$ENV{HTTPS_CA_FILE}   = $ENV{X509_USER_PROXY};
$ENV{HTTPS_CERT_FILE} = $ENV{X509_USER_PROXY};
$ENV{HTTPS_KEY_FILE}  = $ENV{X509_USER_PROXY};
# ---- End of GSI Magic ----

if ($METRICNAME eq "ch.cern.FTS-ChannelList") {
    print "INFO: trying to query FTS ChannelList\n" if ($verbose);
    ($state, $answer) = getChannelList($hostname, $port);
    printOutput($state, $answer);
}   elsif ($METRICNAME eq "ch.cern.FTS-InfoSites") {
    ($state, $answer) = getInfoSites($hostname);
    printOutput($state, $answer);
}

