#!/bin/bash

#-----------------------------------------------------------
# $Id: distexe.sh 128 2009-06-26 08:43:23Z rosiere $
#-----------------------------------------------------------

declare    VERSION="1.0"
declare -i SLEEP=3

# Need : test, echo, cd, dirname, basename, ssh, ps aux

#-----[ distexe_usage ]-------------------------------------
function distexe_usage ()
{
    echo "Usage     : ${0} file [ dir ]";
    echo "Arguments : ";
    echo " * file       : list of command";
    echo " * dir        : work directory (default is current directory).";
#   echo " * nb_process : number of process (default (and maximum) is the number of processor)";
    echo "";
    echo "Note      : ";
    echo " * File content list of command. Each line is execute by an host.";
    echo "   A line can content many shell command.";
    echo "   Don't forgot the final end of line (else the last command is not executed)";
    echo "   example : ";
    echo '   echo "export PATH=${PATH}:${HOME}/my_appli/bin; my_appli 13"  > command_file.txt';
    echo '   echo "export PATH=${PATH}:${HOME}/my_appli/bin; my_appli 21" >> command_file.txt';
    echo '   echo "export PATH=${PATH}:${HOME}/my_appli/bin; my_appli  7" >> command_file.txt';
    echo '   echo ""                                                      >> command_file.txt';    
    echo " * For each command, a directory (in work directory) is created : Task_X (X is the number of line in command file).";
    echo "   The command is execute in this directory. (Warning, set your environment !).";
    echo "   Two file is generate : \"distexe.output\" is the output (standard and error) of the execution, and \"distexe.command\" is the command lunch.";
#   echo " * A command empty (no command on a line of file) is a synchronisation with all process"
    echo " * The environment variable DISTEXE_HOSTS list hosts to execute command";
    echo "   After each host, a number is to the number of process. It's optionnal, the default value is the number of processor.";
    echo "   example :";
    echo '   export DISTEXE_HOSTS="localhost/1 nod/4 gdi/2"';
    echo " * All hosts must have network file systems (per example nfs or samba)";
    echo "   Work directory must be in this network file systems !";
    echo "";
    exit;
}

#-----[ my_date ]-------------------------------------------
function my_date ()
{
    date +"%F %T";
}

#-----[ distexe_test_usage ]--------------------------------
function distexe_test_usage ()
{
    if test ${#} -ne 1 -a ${#} -ne 2; then
	distexe_usage;
    fi;

    if test -z "${MORPHEO_SCRIPT}"; then
        echo "Environment variable MORPHEO_SCRIPT is not set";
        distexe_usage;
    fi;

    if test ! -f ${1}; then
	echo "File \"${1}\" is invalid";
	distexe_usage;
    fi;

    if test ! -s ${1}; then
	echo "File \"${1}\" is empty.";
	distexe_usage;
    fi;

    if test ${#} -eq 2; then
        if test ! -d ${2}; then
	    echo "Directory \"${2}\" is invalid.";
	    distexe_usage;
        fi;
    fi;
}

#-----[ header ]--------------------------------------------
function header ()
{
    echo "distexe ${VERSION}";
}

#-----[ distexe ]-------------------------------------------
function distexe ()
{
    distexe_test_usage ${*};

    # construct file command with absolute path
    cd $(dirname ${1});
    local FILE_CMD=${PWD}/$(basename ${1});
    cd -;

    # Absolute path of work directory
    local    PATH_EXE;
    if test ${#} -eq 2; then
        cd ${2} &> /dev/null;
        PATH_EXE=${PWD};
        cd -  &> /dev/null;
    else
        PATH_EXE=${PWD};
    fi;

    local FILE_CPT="${PATH_EXE}/control-"$(basename ${FILE_CMD});
    
    header;

    echo "  * {"$(my_date)"} <${HOSTNAME}> file  : ${FILE_CMD}";
    echo "  * {"$(my_date)"} <${HOSTNAME}> path  : ${PATH_EXE}";
    echo "  * {"$(my_date)"} <${HOSTNAME}> sleep : ${SLEEP}";

    local hosts="${DISTEXE_HOSTS}";
    local -a commands;
    local -i cpt=0;

    for line in ${hosts}; do
        local    host=$(echo ${line} | cut -d/ -f1);
        local -i nb_process=$(echo ${line} | cut -d/ -f2);

        echo "  * {"$(my_date)"} <${HOSTNAME}> station : ${host} (${nb_process}) ... ";

        # lunch service
        local cmd="export MORPHEO_SCRIPT=${MORPHEO_SCRIPT};${MORPHEO_SCRIPT}/execute_n.sh ${PATH_EXE} ${FILE_CMD} ${FILE_CPT} ${nb_process};";
        ssh ${host} ${cmd} &

	commands[${cpt}]="${cmd}";
	cpt=$((${cpt}+1));
    done;

    echo "  * {"$(my_date)"} <${HOSTNAME}> all hosts working";

    cpt=0;
    while test ${cpt} -lt ${#commands[*]}; do
        local -i res=1

        while true; do
            res=$(ps aux | grep -c "${commands[${cpt}]}");

            if test ${res} -eq 0; then
                break;
            fi;

            # wait (to not have 100% cpu)
            sleep ${SLEEP};
        done

	cpt=$((${cpt}+1));
    done;

    echo "  * {"$(my_date)"} <${HOSTNAME}> all hosts is done";
    rm ${FILE_CPT};
}

#-----[ Corps ]---------------------------------------------
distexe ${*};
