#!/usr/bin/perl
#########################################################################
##
## © University of Southampton IT Innovation Centre, 2004
##
## Copyright in this library belongs to the IT Innovation Centre of
## 2 Venture Road, Chilworth Science Park, Southampton SO16 7NP, UK.
##
## This software may not be used, sold, licensed, transferred, copied
## or reproduced in whole or in part in any manner or form or in or
## on any media by any person other than in accordance with the terms
## of the Licence Agreement supplied with the software, or otherwise
## without the prior written consent of the copyright owners.
##
## This software is distributed WITHOUT ANY WARRANTY, without even the
## implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
## PURPOSE, except where stated in the Licence Agreement supplied with
## the software.
##
##      Created By :            Panos Melas
##      Created Date :          2004/06/25
##      Created for Project:    GRIA
##
#########################################################################
##
##      Dependencies : none
##
#########################################################################
##
##      Last commit info:       $Author: cruisecontrol $
##                              $Date: 2007-02-07 16:57:58 +0000 (Wed, 07 Feb 2007) $
##                              $Revision: 6548 $
##
#########################################################################
#
# This is a script template for parsing wrapper arguments for
# the following format:
#
# killJob 
#         -d <session directory>
#         [-e <application kill script>]
#         [-v ] verbose
#         [-h ] help
#         [-r <RM instructions>]...
#

use strict;
use File::Find;
use Cwd;
use Getopt::Std;
use Text::ParseWords;
use vars qw/ %opt /;



#############
# SECTION A #
#################################################
#
# Initialise Resource Manager global vars
#

my $RM_PATH="/usr/local/bin";
my $RM_QUEUE="${RM_PATH}/qstat -s ";


###################################################
# 
# Initialise timestamp variables used by the API
#

# time line
#              (1)           (2)     (3)        (4) (5)
#|--------------^-------------^-------^----------^---^----->
#     |___________|  queue    |       |__________|   |
#       startJob              |        application   |
#                             |______________________|
#                                  app-wrapper

# (1)
my $JOB_SUBMIT_TS=".job_submitted";
# (2)
my $APP_WRAPPER_STARTED_TS=".app_wrapper_started";
# (3)
my $APP_STARTED_TS=".app_started";
# (4)
my $APP_ENDED_TS=".app_ended";
# (5)
my $APP_WRAPPER_ENDED_TS=".app_wrapper_ended";

my $JOB_PID=".jobPID";



####################################################
#
# Default values for some command line args
#

my $SESSION_NAME="TEST";
my $SESSION_DIR=".";

my $APP_SP_SCRIPT;
my $WORK_DIR="work";

#############
# SECTION B #
####################################################
#
# Verbose mode flags
#


# my debug flag 
my $debug=1;

################################################
#
# deal with arguments first
#
#      -h           : this (help) message
#      -v           : verbose output
#      -d directory : session directory
#      -w work dir  : working directory
#      -e app       : application kill script

my $opt_string = 'hvd:e:';

getopts( "$opt_string", \%opt ) or usage();
usage() if $opt{h};
$debug=1 if $opt{v};

$SESSION_DIR=$opt{d} if defined $opt{d};
print "Use session directory: $opt{d}\n " if $debug;

$APP_SP_SCRIPT=$opt{e} if defined $opt{e};
print "Use application specific kill script: $APP_SP_SCRIPT\n" if $debug;

##############################################
#
# print header information and date
#

printHeader();

my $now = localtime time;
print "$now\n";


##############################################
#
# identifySessionDirs, cd session directory
#

identifySessionDirs();
my $OLD_DIR=cwd();

chdir($SESSION_DIR) or die "Can't cd to $SESSION_DIR: $!, stopped ";


##############################################
#
# check for the job submission file job_pid
# this file contains a single line with the
# pbs job id
#

die "Error: Submit failed to generate job PID file: S!, stopped " unless -f $JOB_PID;

print "DEBUG\tJOB_PID file found!\n" if $debug;

open(FILE, $JOB_PID) || die ("Error cannot open $JOB_PID file: $!, stopped ");
my @file_cont=<FILE>; close(FILE);


my $PID=$file_cont[0];
$PID =~ s/\r\n$/\n/; $PID =~ s/\n$//;

my $shortPID=$PID;
$shortPID =~ s/^([0-9]+)(.*)$/$1/;

my $concatPID=$PID;
$concatPID =~ s/^(.{15}).*$/$1/;

print "DEBUG\tPID: $PID, $shortPID, $concatPID\n" if $debug;




#############
# SECTION C #
#############################################
#
# RM_QUEUE to find out what RM says for that job_id
#
my $qString;

open(QUEUE, "${RM_QUEUE} $PID |") or die ("Error: cannot get ${RM_QUEUE} output: ($!), stopped ");
while(<QUEUE>) {
        chomp;
        if (/^$concatPID.*$/) {
                $qString = $_;
        }
}
close QUEUE;

my @words = &quotewords('\s+', 0, $qString);
my $jStatus = $words[9]; 

print "qString: $qString\n" if $debug;





############################################
#
# if job_id is not found in active Q ... 
# job has either finished or was not submitted!
#

if ( $qString eq "" ) {
    print "DEBUG\tJob is not found in Q\n" if $debug;

    print "Job is not running. ";

    # check for finish file
    die "Error: cannot find finish file $APP_WRAPPER_ENDED_TS: $!" unless -e $APP_WRAPPER_ENDED_TS ;

    # then the job has finished
    print "Job cannot be killed because it is not running (i.e. terminated or finished)\n";
    exit 0;
}




##########################################
#
# else kill the job now
#

print "killing job $PID\n";
my $dia=0;

if ( defined $APP_SP_SCRIPT) {
   print "Do gracefull job killing\n";
   chdir $WORK_DIR or die "Error: cannot change dir to $WORK_DIR: $!, stopped ";
   $dia = extInvoke("system", $APP_SP_SCRIPT);
   chdir "../" or die "Error: ($!), stopped ";
} else {
   print "Do brutal job killing\n";
   
   $dia= extInvoke("system", "${RM_PATH}/qdel $PID");
   print "DIA: $dia\n";
}

if ( $dia == 0 ) {
    open(FILE, "> .killed") or die "ERROR: cannnot create kill file: $!, stopped ";
    close(FILE);
} else {
    die "ERROR: failed to pass kill signal to process ($PID) return value: $dia for $SESSION_DIR, stopped ";
}

exit 0;



############## perl subroutines ###################


sub extInvoke () {
	my $l_cmd = shift;
	my $l_app = shift;
	my $l_dia = 0;
	
	if($l_cmd eq "system") {
		$l_dia = system($l_app);
	} else {
	        $l_dia = exec($l_app);
	}
	
	if ($l_dia == -1) {
		print "<$l_app> failed to execute: $!\n";
	}
	elsif ($l_dia & 127) {
		printf "<$l_app> child died with signal %d, %s coredump\n",
		($l_dia & 127),  ($l_dia & 128) ? 'with' : 'without';
	}
	else {
		printf "<$l_app> child exited with value %d\n", $l_dia >> 8;
	}

	return $l_dia >> 8;
}


#
# identify session directories, etc.
#

sub identifySessionDirs ()
{
    die "Session directory $SESSION_DIR does not exist ($!), stopped " 
	unless -e $SESSION_DIR;
 
    use File::Basename;
    $SESSION_NAME=basename($SESSION_DIR);
    print "session name: $SESSION_NAME\n" if $debug;
    return 0;
}




#
# Message about this program and how to use it
#
sub usage()
{
    print STDERR << "    EOF";
    
    This program kills a job
	
      usage: $0 [-h] [-v] <-d directory> [-e kill script]
      
      -h           : this (help) message
      -v           : verbose output
      -d directory : session directory
      -e app       : application kill script
      
    example: $0 -v -d tmp
    
    EOF
    exit;
}


#
# Print header line
#
sub printHeader() 
{   
    print << "    EOF";
    killJob ver: 5.0.0
    
    +--------------------------------------------------+
    |                                                  |  
    |   GRIA  Job killJob wrapper (\$Revision: 6548 \$)  |
    |                                                  |  
    +--------------------------------------------------+

    EOF
    return;
}


