#! /bin/sh # # Copyright 1999-2006 University of Chicago # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # # globus-job-run and globus-job-submit (same code base) # prefix="${GLOBUS_LOCATION-/cvmfs/dirac.egi.eu/dirac/v9.0.0a31/Linux-x86_64}" exec_prefix="${prefix}" sbindir="${exec_prefix}/sbin" bindir="${exec_prefix}/bin" includedir="/cvmfs/dirac.egi.eu/dirac/v9.0.0a31/Linux-x86_64/include/globus" datarootdir="${prefix}/share" datadir="${datarootdir}" libexecdir="/cvmfs/dirac.egi.eu/dirac/v9.0.0a31/Linux-x86_64/share/globus" sysconfdir="${prefix}/etc" sharedstatedir="${prefix}/com" localstatedir="${prefix}/var" PATH="${bindir}:${sbindir}:${libexecdir}:${PATH}" PROGRAM_NAME="${0##*/}" PROGRAM_VERSION='12.1' PACKAGE='globus_gram_client_tools' VERSION='12.1' DIRT_TIMESTAMP='1629915172' DIRT_BRANCH_ID='0' case "$PROGRAM_NAME" in *-run) short_usage="$PROGRAM_NAME <contact string> [-np N] <executable> [<arg>...]" std_file_statement="default to stdout/stdout of $PROGRAM_NAME." ;; *-submit) short_usage="$PROGRAM_NAME [-help] <contact string> [-np N] <executable> [<arg>...]" std_file_statement="is retrieved later using globus-job-get-output." ;; esac long_usage () { cat >&2 <<EOF Usage: $PROGRAM_NAME [-help|-usage] print usage and exit [-version[s]] print version and exit Usage: $PROGRAM_NAME [-dumprsl] output RSL, don't run job [-dryrun] verify RSL, don't run job [-verify] perform dryrun, then run job [-file file] read rest of arguments from file contact string only the hostname is required. [-np N] number of processing elements [-count N] same as -np [-host-count nodes] number of SMP nodes (IBM SP) [-m[axtime] minutes] time to allocate for the job [-p[roject] projectID] scheduling/accounting project ID [-q[ueue] queueID] scheduling/accounting queue ID [-d[ir] directory] working directory [-env name=value]... environment binding [-stdin [-l|-s] file] input [-stdout [-l|-s] file] output [-stderr [-l|-s] file] error output [-x rsl-clause] RSL extension capability [-l|-s] executable [args...] executable and clause arguments Job stdin defaults to /dev/null. Job stdout/stderr $std_file_statement The file modifiers -l and -s specify different filespaces: -l[ocal] file is relative to working directory of job (DEFAULT) -s[tage] file relative to job request is staged to job host The working directory of the submitted job defaults to \$HOME. Valid forms of the contact string are: hostname hostname:port hostname:port/service hostname/service hostname:/service hostname::subject hostname:port:subject hostname/service:subject hostname:/service:subject hostname:port/service:subject If more than one setting is defined (such as two -stdin definitions), the setting defined last on the command line will be used. EOF } rslfile=${TMPDIR:-/tmp}/globus_job_run.`whoami`.rsl.$$ tmpfile=${TMPDIR:-/tmp}/globus_job_run.`whoami`.tmp.$$ remove_files () { rm -f ${rslfile} ${tmpfile} } error_exit () { globus_args_short_usage exit $1 } stringify () { # # NOTE: if the argument contains the pattern $(...), it is most likely # an RSL substitution: if so, suppress quoting. # arg="`cat -`" if [ "X`printf "%s" "${arg}" | sed -n '/\$(.*)/p'`" = "X" ]; then printf "%s" "${arg}" | sed -e 's/"/""/g' -e 's/^.*$/"&"/g' else printf "%s" "${arg}" fi } parse_integer () { if expr "$2" + 1 - 1 \> 0 > /dev/null 2>&1 ; then result="$2" else globus_args_option_error "$1" "\"$2\" is not an integer" fi } get_real_pwd () { file="$1" # # Try to figure out PWD (the real PWD, not an automounted PWD or an # incorrect env.var...) # This code is at large based on code from the MPICH mpirun command, # where they try to solve the same problem. # PWDtest="`pwd | sed 's@/tmp_mnt/@/@g'`" if [ ! -d "$PWDtest" ] ; then PWDtest="`pwd`" fi if [ -n "$PWD" ] ; then PWDtest2=`echo $PWD | sed 's@/tmp_mnt/@/@g'` if [ ! -r "${PWDtest2}/file" ]; then PWD=$PWDtest2 else PWD=$PWDtest fi else PWD=$PWDtest fi echo "$PWD/$file" } normalize_filename() { case "$1" in /* ) file="$1" ;; * ) file=`get_real_pwd "$1"` ;; esac # collapse all sequences of '/'s to a single '/' # file=`echo $file | sed -e 's://*:/:g'` # collapse all instances of "/./" to a single '/' # note we must loop for all series forms "/././" because # the patterns overlap and only half match in each iteration # while echo $file | grep '/\./' > /dev/null 2>&1 do # this goes faster when we inline a couple iterations # into one sed command file=`echo $file | sed -e 's:/\./:/:g' \ -e 's:/\./:/:g'` done # reduce all '/../' expressions # root is its own parent # foo/bar/../ is foo iff bar!=.. while echo $file | fgrep '/\.\./' > /dev/null 2>&1 do file=`echo $file | sed -e 's:^/\.\./:/:g' \ -e 's:/[^./][^/]*/\.\./:/:g' \ -e 's:/\.[^./][^/]*/\.\./:/:g' \ -e 's:/\.\.[^/][^/]*/\.\./:/:g'` done # remove trailing '/.' or '/' # file=`echo $file | sed -e 's:/$::g' \ -e 's:\(/\.\)*$::g'` echo $file } read_argument_file() { cat $1 | ( arglist= while read inp ; do arglist="${arglist} ${inp}" done echo "${arglist}" ) } emit_subjob_rsl () { # # extra RSL should take precedence: therefore, it needs to come first # if [ ${job_is_multi} = "true" ]; then echo "( &${subjob_extra_rsl}(resourceManagerContact=\"${job_contact}\")" echo " (subjobStartType=strict-barrier)" echo " (label=\"subjob ${job_hostclause_count}\")" echo " (executable=$executable)" else if [ -n "${subjob_extra_rsl}" ] ; then echo " &${subjob_extra_rsl}" echo " (executable=$executable)" else echo " &(executable=$executable)" fi fi if [ ! "X$project" = "X" ] ; then echo " (project=$project)" fi if [ ! "X$queue" = "X" ] ; then echo " (queue=$queue)" fi if [ ! "X$maxtime" = "X" ] ; then echo " (maxtime=$maxtime)" fi if [ ! "X$directory" = "X" ] ; then echo " (directory=$directory)" fi if [ ! "X$job_environment" = "X" ] || \ [ ! "X$subjob_environment" = "X" ] ; then echo " (environment=${job_environment}${subjob_environment})" fi if [ ! "X$count" = "X" ] ; then echo " (count=$count)" fi if [ ! "X$host_count" = "X" ] ; then echo " (host_count=$host_count)" fi if [ ! "X$subjob_args" = "X" ] ; then echo " (arguments=$subjob_args)" elif [ ! "X$arguments" = "X" ] ; then echo " (arguments=$arguments)" fi if [ ! "X$subjob_stdin" = "X" ] ; then echo " (stdin=$subjob_stdin)" elif [ ! "X$job_stdin" = "X" ] ; then echo " (stdin=$job_stdin)" fi if [ ! "X$subjob_stdout" = "X" ] ; then echo " (stdout=$subjob_stdout)" elif [ ! "X$job_stdout" = "X" ] ; then echo " (stdout=$job_stdout)" fi if [ ! "X$subjob_stderr" = "X" ] ; then echo " (stderr=$subjob_stderr)" elif [ ! "X$job_stderr" = "X" ] ; then echo " (stderr=$job_stderr)" fi if [ ${job_is_multi} = "true" ]; then echo ")" fi } parse_fileopt () { # # given input: <option> [-l[ocal]|-s[tage]] filename ... # # where <option> is one of -std{in,out,err}, -file, executable # if -l or -s is not defined, -l is assumed. # # The following settings are triggered: # # PROGRAM_NAME option flag action # ----------------------------------------------------------- # run -stdin,executable -s enable GASS read # run -stdout,-stderr -s enable GASS write # submit -stdout,-stderr all disable GASS caching # opt="$1" if [ $# -eq 1 ]; then globus_args_option_error "${opt}" "needs a filename argument" fi stagevar=dummy dont_stringify=0 case "${PROGRAM_NAME}:${opt}" in *-run:-stdin | *-run:executable) stagevar=job_needs_gass_read ;; *-run:-stdout | *-run:-stderr) stagevar=job_needs_gass_write ;; *-submit:-stdout) job_cache_stdout=false ;; *-submit:-stderr) job_cache_stderr=false ;; *:-file) dont_stringify=1 ;; esac shift case "$1" in -s | -stage) if [ $# -eq 1 ]; then globus_args_option_error "${opt} $1" "needs a filename argument" fi file=`normalize_filename "$2" | stringify` result=`echo '$(GLOBUSRUN_GASS_URL)' '#' "${file}"` eval ${stagevar}=true stage_executable=true return 3 ;; -l | -local) if [ $# -eq 1 ]; then globus_args_option_error "${opt} $1" "needs a filename argument" return 0 fi result=`echo "$2" | stringify` return 3 ;; -*) globus_args_option_error "${opt}" "needs a filename argument" return 0 ;; *) if test "$dont_stringify" = 1; then result=$1 else result=`echo "$1" | stringify` fi return 2 ;; esac } parse_environment () { shift 1 if [ ! "$#" = "0" ] ; then case "$1" in ?*=*) name=`echo "$1" | sed -e 's/^\([^=]*\)=\(.*\)/\1/g'` value=`echo "$1" | sed -e 's/^\([^=]*\)=\(.*\)/\2/g'` echo "("`echo "$name" | stringify` `echo "$value" | stringify`")" return 2 ;; *) globus_args_option_error "-env" "invalid environment string \"$1\"" ;; esac else globus_args_option_error "-env" "missing environment string!" fi } parse_user_args () { shift_count=0 temp_arguments="" while expr "$#" \> 0 > /dev/null 2> /dev/null ; do arg=`printf "%s" "$1" | stringify` temp_arguments="${temp_arguments} ${arg}" shift shift_count=`expr "$shift_count" + 1 2> /dev/null` done echo "$temp_arguments" return $shift_count } parse_hostclause () { count="" host_count="" maxtime="" executable="" directory="" project="" queue="" subjob_environment="" subjob_stdin="" subjob_stdout="" subjob_stderr="" subjob_args="" clause_done="false" if [ $# -eq 0 ]; then echo "ERROR: empty host-clause" >& 2 return 0 fi # "$1" should be the contact string # case "$1" in -*) globus_args_option_error "$1" \ "contact string must be first in host-clause" ;; *) job_contact="$1" ;; esac shift 1 shift_count=1 while [ $# -gt 0 -a "${clause_done}" = "false" ]; do case "$1" in -np | -count | \ -host-count | \ -m | -maxtime | \ -p | -project | \ -q | -queue | \ -d | -dir | \ -x | -extrarsl) if [ $# -lt 2 ]; then globus_args_option_error "$1" "missing argument" fi case "$1" in -np | -count) parse_integer "$@" count=${result} ;; -host-count) parse_integer "$@" host_count=${result} ;; -m | -maxtime) parse_integer "$@" maxtime=${result} if [ ${maxtime} -gt ${job_maxtime} ]; then job_maxtime=${maxtime} fi ;; -p | -project) project=`echo "$2" | stringify` ;; -q | -queue) queue=`echo "$2" | stringify` ;; -d | -dir) directory=`echo "$2" | stringify` ;; -x | -extrarsl) case "$2" in \&*) subjob_extra_rsl=`echo "$2" | \ sed 's/^&//'` ;; *) subjob_extra_rsl="$2" ;; esac globusrun -p "&${subjob_extra_rsl}" \ 1>/dev/null 2>/dev/null if [ $? -ne 0 ]; then globus_args_option_error "$1" "cannot parse RSL stub" fi ;; esac shift 2 shift_count=`expr $shift_count + 2` ;; -stdin | -stdout | -stderr) parse_fileopt "$@" stdio_shift=$? if [ ${stdio_shift} -eq 0 ]; then return 0 fi case "$1" in -stdin) subjob_stdin=${result} ;; -stdout) subjob_stdout=${result} ;; -stderr) subjob_stderr=${result} ;; esac shift $stdio_shift shift_count=`expr $shift_count + $stdio_shift` ;; -env) subjob_environment=${subjob_environment}\ `parse_environment "$@"` env_shift=$? if [ ${env_shift} -eq 0 ] ; then return 0 else shift $env_shift shift_count=`expr $shift_count + $env_shift` fi ;; *) case "$1" in -l* | -s*) dummy=xyz ;; -*) globus_args_unrecognized_option "$1" ;; esac # # this should be [-l|-s] executable [args...] # where [args...] is terminated by EOL # # fileopt() needs a "executable" option first though. # parse_fileopt "executable" "$@" exec_shift=$? if [ ${exec_shift} -eq 0 ]; then return 0 fi executable=${result} # # added a phantom "executable" argument above: adjust for that exec_shift=`expr $exec_shift - 1` shift $exec_shift shift_count=`expr $shift_count + $exec_shift` # and now the arguments... # while [ ! "$#" = "0" ]; do if [ "$1" = "--" ]; then shift_count=`expr $shift_count + 1` if [ $# -ge 2 -a "$2" = "--" ]; then shift else shift continue fi fi subjob_args="$subjob_args `printf "%s" "$1" | stringify`" shift_count=`expr $shift_count + 1` shift done clause_done=true ;; esac done if [ -z "${executable}" ]; then echo "ERROR: no executable in host-clause" >&2 return 0 fi emit_subjob_rsl return $shift_count } globus_args_short_usage() { cat 1>&2 <<EOF Syntax : ${short_usage} Use -help to display full usage. EOF } globus_args_option_error() { cat 1>&2 <<EOF ERROR: option $1 : $2 EOF globus_args_short_usage exit 1 } globus_args_unrecognized_option() { globus_args_option_error $1 "unrecognized option" exit 1 } parse_global_opts () { while [ ! "$#" = "0" ] ; do case "$1" in -help | -h | --help | -usage | --usage) long_usage exit 0 ;; -version|--version) if [ "X${PROGRAM_NAME}" != "X" -a \ "X${PROGRAM_VERSION}" != "X" ]; then echo "${PROGRAM_NAME}: ${PROGRAM_VERSION}" elif [ "X${PACKAGE}" != "X" -a \ "X${VERSION}" != "X" ]; then echo "${PACKAGE}: ${VERSION}" else echo "No version information available." fi exit 0 ;; -versions|--versions) AT=@ if [ -n "${PACKAGE}" -a -n "${VERSION}" -a \ -n "${DIRT_TIMESTAMP}" -a -n "${DIRT_BRANCH_ID}" -a \ "X${DIRT_TIMESTAMP}" != "X${AT}DIRT_TIMESTAMP${AT}" -a \ "X${DIRT_BRANCH_ID}" != "X${AT}DIRT_BRANCH_ID${AT}" ]; then echo "${PACKAGE}: ${VERSION} (${DIRT_TIMESTAMP}-${DIRT_BRANCH_ID})" else echo "No DiRT information available." fi exit 0; ;; -dump | -dumprsl | --dump | --dumprsl) shift job_print_rsl=true job_submit=false ;; -dryrun | --dryrun) shift job_verify=true job_submit=false ;; -verify | --verify) shift job_verify=true job_submit=true ;; -- ) shift 1 arguments=`parse_user_args "$@"` shift $? ;; *) single_flag=`expr ${single_flag} + 1` if [ ${job_is_multi} = true -o ${single_flag} -gt 1 ]; then globus_args_option_error "$1" \ "Cannot mix single and multi-req syntax" fi parse_hostclause "$@" shift_count=$? if [ ${shift_count} -eq 0 ]; then return 1 fi shift $shift_count job_hostclause_count=`expr $job_hostclause_count + 1` ;; esac done if [ "$job_hostclause_count" = 0 ] ; then echo "ERROR: Every job requires at least one host-clause!" >&2 return 1 fi } parse_top () { # Default global settings # mds_search_options="" job_stdin="" job_stdout="" job_stderr="" job_environment="" job_contact="" job_maxtime=120 # two hours job_is_multi=false job_print_rsl=false job_verify=false job_submit=true job_needs_gass_read=false job_needs_gass_write=false job_needs_gass_output=true stage_executable=false job_cache_stdout=false job_cache_stderr=false job_gass_cache_tag="x-gass-cache://\$(GLOBUS_GRAM_JOB_CONTACT)" # there are some differences in default settings for job-run and # job-submit.... # case "${PROGRAM_NAME}" in *-submit) job_needs_gass_output=false job_cache_stdout=true job_cache_stderr=true job_stdout="${job_gass_cache_tag}stdout anExtraTag" job_stderr="${job_gass_cache_tag}stderr anExtraTag" ;; esac single_flag=0 job_hostclause_count=0 parse_global_opts "$@" } ################################################# ## validation pass gathers job argument list trap remove_files 0 1 2 9 13 15 if [ $# -eq 0 ]; then globus_args_short_usage exit 1 fi for file in ${rslfile} ${tmpfile} ; do rm -f ${file} touch ${file} if [ $? -ne 0 ] ; then echo "ERROR: Could not create temporary file \"${file}\"!" >&2 error_exit 1 fi done if parse_top "$@" > ${rslfile} then if [ "${job_print_rsl}" = "true" ]; then cat ${rslfile} fi gassflag="" batchflag="-fast-batch" if [ ${job_needs_gass_output} = true ]; then gassflag="-o" batchflag="-b" fi if [ ${job_needs_gass_read} = true ] || \ [ ${stage_executable} = true ] ; then gassflag="-s" batchflag="-b" fi if [ ${job_needs_gass_write} = true ]; then gassflag="-w" batchflag="-b" fi case "${PROGRAM_NAME}:${job_is_multi}" in *submit:true) echo "this statement should never have been executed" >&2 error_exit 1 ;; *submit:false) globusrun_args="${gassflag} ${batchflag} -r \"${job_contact}\" -f ${rslfile}" ;; *run:true) globusrun_args="${gassflag} -f ${rslfile}" ;; *run:false) globusrun_args="${gassflag} -r \"${job_contact}\" -f ${rslfile}" ;; esac # Check if proxy exists and is valid long enough. # if [ ${job_verify} = true -o ${job_submit} = true ]; then grid-proxy-info -exists if [ $? -ne 0 ]; then echo "ERROR: proxy does not exist" >&2 error_exit 1 fi hours=`expr ${job_maxtime} / 60 + 1` grid-proxy-info -exists -valid "${hours}:0" if [ $? -ne 0 ]; then echo "ERROR: proxy is not valid long enough " \ "(${hours} hours)" >&2 error_exit 1 fi fi # Dryrun to see if things will be OK. # if [ "${job_verify}" = "true" ]; then eval globusrun "-d ${globusrun_args}" 1>${tmpfile} 2>&1 if [ $? -ne 0 ]; then echo "ERROR: verify failed:" >&2 cat ${tmpfile} >&2 error_exit 1 else echo "Dryrun successful" >&2 fi if [ ${job_cache_stdout} = true -o ${job_cache_stderr} = true ]; then jobid=`grep x-nexus ${tmpfile}` basecmd="\$bindir/globus-gass-cache -cleanup-url x-gass-cache://" command= if [ ${job_cache_stdout} = true ]; then command="${basecmd}${jobid}stdout" fi if [ ${job_cache_stderr} = true ]; then command="${command} ; ${basecmd}${jobid}stderr" fi if [ -n "${command}" ]; then echo globusrun -q -b -r "${job_contact}" \ "&(executable=\${bindir}//globus-sh-exec) \ (arguments=-e \"${command}\")" fi fi fi # Just do it (tm). # if [ "${job_submit}" = "true" ]; then eval globusrun "-q ${globusrun_args}" return_status=$? exit $return_status fi exit 0 else error_exit 1 fi