#!/usr/bin/perl
use strict;
use Data::Dumper;
use Grid::Request::HTC;
use Grid::Request::JobFormulator;
use Log::Log4perl qw(:easy);
use Config::IniFiles;
use Sys::Hostname;
Log::Log4perl->easy_init($DEBUG);
my $logger = Log::Log4perl->get_logger();
# Deterine what host we are running on.
my $host = hostname;
$logger->info("Running on $host");
# Load which grid we are using from the configuration file.
my $config_file = Grid::Request::HTC->config();
# The [section] heading in the configuration file.
my $section = $Grid::Request::HTC::config_section;
my $config = Config::IniFiles->new(-file => $config_file);
my $grid_type = $config->val($section, "drm");
$logger->debug("Grid type: $grid_type");
my $MW_PARAM_DELIMITER = ":";
# Get the task ID that we are. There are going to be several instances of this
# script running. We need to know which one we are. This is actually different
# for every execution environment (grid), so we have a subroutine to hide that.
my $task_id = get_task_id();
check_arguments();
# the first argument is the executable to invoke
my $executable = shift(@ARGV);
$logger->info("The executable is $executable.");
# The second argument is the blocksize, for the window of tasks to do.
my $block_size = shift(@ARGV);
$logger->info("The block size is $executable.");
# The remaining arguments are the MW parameters
my @mw_params = @ARGV;
$logger->debug("Number of MW parameters: " . scalar(@mw_params));
# Now that we have the MW parameters, let's just check that they
# make sense.
validate_mw_params(\@mw_params);
# If we are here, then the MW parameters look fine.
$logger->debug("MW parameters validated correctly.");
if (! defined $task_id || $task_id <= 0) {
$logger->logdie("Unable to determine this worker's ID.");
}
$logger->info("Task id for this worker: $task_id");
# an array of arrays for all the parameters to invoke
my @invocations = $jb->formulate($block_size, $, @mw_params);
@invocations = splice_task_invocations(\@invocations);
execute(\@invocations);
#############################################################################
sub splice_task_invocations {
}
sub execute {
$logger->debug("In execute.");
my ($arg_group_ref) = @_;
my ($success, $failed) = (0,0);
my $count = 0;
my $group_size = scalar @$arg_group_ref;
$logger->debug("The number of arguments each command invocation of will have: $group_size");
if ( $group_size > 0 ) {
# Length of the various argument arrays should all be the same, so we'll just use
# the length of the first one.
my $arg_length = scalar(@{ $arg_group_ref->[0] });
# This loop is to iterate across the argument arrays
for (my $arg_index = 0; $arg_index < $arg_length; $arg_index++) {
$count++;
my @exec = ();
for (my $group_index = 0; $group_index < $group_size; $group_index++) {
my $arg = $arg_group_ref->[$group_index]->[$arg_index];
# TODO: This should be done in the JobFormulator formulate() method
# Replace $(Index) with the task id.
$arg =~ s/\$\(Index\)/$task_id/g;
push(@exec, $arg);
}
$logger->info("Invoking: ", sub { join(" ", @exec) } );
if ($logger->is_debug()) {
$logger->debug("Arg list for invokation of $executable:\n", sub{ Dumper(\@exec) } );
$logger->debug(sub { sprintf("Invoking %s. This is time #%d", $executable, $count) } );
$logger->debug("==============================================================");
}
system(@exec);
my $exit_value = $? >> 8;
if ($logger->is_debug()) {
$logger->debug("==============================================================");
$logger->info(sub { sprintf("Completed run of %s. Exit value: %d", $executable, $exit_value) });
}
if ($exit_value == 0) {
$success++;
} else {
$failed++;
}
}
} else {
$logger->warn("No arguments! Just invoking the configured executable with no args.");
}
$logger->info(sub { sprintf("Successful: %d. Failed: %d. Total: %d", $success, $failed, $count) });
my $exit = ($failed == 0) ? 0 : 1;
$logger->info("$0 has completed execution. Exiting with exit value: $exit");
exit $exit;
}
sub check_arguments {
if (scalar @ARGV < 3) {
$logger->fatal("An invalid number of parameters was specified.");
print_usage();
}
# Check for a valid block size
my $block_size = $ARGV[1];
if (int($block_size) != $block_size || $block_size <= 0) {
$logger->logdie("A non-integer or non-positive block size was specified: $block_size.");
}
}
sub get_task_id {
my $task_id;
$grid_type = lc($grid_type);
# Delete the environment variables when done with them in case the
# executable somehow wants to submit jobs and pass the environment.
if ($grid_type eq "sge") {
$task_id = $ENV{SGE_TASK_ID};
delete $ENV{SGE_TASK_ID};
} elsif ($grid_type eq "condor") {
# Condor uses 0 based task IDs.
$task_id = $ENV{CONDOR_TASK_ID} + 1;
delete $ENV{CONDOR_TASK_ID};
} elsif ($grid_type eq "torque" || $grid_type eq "pbs") {
# TODO: Determine how to get the Task ID in PBS/Torque
$task_id = "";
} else {
$logger->logdie("Unsupported grid type: $grid_type");
}
return $task_id
}
sub print_usage {
print "Usage:\n\n";
print "$0 <remote_executable> <block_size> <MW_param_1> <MW_param_2> ... <MW_param_N>\n\n\n";
print "Example:\n";
print "$0 <remote_executable> 100 param:--parameter 'file:/path/to/file:\$(Name)'\n\n\n";
exit 1;
}
sub validate_mw_params {
my $param_ref = shift;
$logger->debug("Received " . scalar(@$param_ref) . " parameters to examine.");
foreach my $param (@$param_ref) {
my @components = split(/$MW_PARAM_DELIMITER/, $param);
if (scalar(@components) == 2) {
my ($type, $value) = @components;
$type = uc($type);
if ($type ne "PARAM") {
$logger->logdie("Only 2 fields for MW parameter found: \"$param\"");
}
} elsif (scalar(@components) == 3) {
my ($type, $value, $key) = @components;
$type = uc($type);
if ($type eq "DIR") {
# If it's not a directory, throw an exception
if (! -d $value) {
$logger->logdie("MW parameter $param specified an invalid directory: \"$value\".");
}
} elsif ($type eq "FILE") {
# If it's not a file or it's not readable, throw an exception...
if (! -f $value || ! -r $value) {
$logger->logdie("MW parameter $param specified a file that doesn't exist or isn't readable.");
}
} elsif ($type eq "PARAM") {
$logger->logdie("Only 2 fields are allowed for a type of PARAM.");
} else {
# Throw an exception
$logger->logdie("Unrecognized parameter type of \"$type\".");
}
} else {
$logger->logdie("Invalid MW parameter encountered: \"$param\"");
}
}
}