#! /bin/sh -f
###################################################################
# globus-script-<scheduler>-queue script
# --------------------------------------
#
# The purpose of this script is to communicate the queue values and
# current queue entries (jobs) to the globus-gram-scheduler function.
# This function will then compile the information into C structures to 
# present a uniform interface to more easily facilitate multi queue
# analysis.
#
# queue information is output in the form:
#     GRAM_SCRIPT_Q:<gram queue parameter> <local scheduler value>
#
# queue entry information (i.e. jobs) are output in the form:
#     GRAM_SCRIPT_QE:<gram queue entry parameter> <local scheduler job value>
#      
#
###################################################################
# Below is a conversion chart for this scheduler queue's job status
# value to Globus job status value.
#
# The Status field can contain one of the following strings:
#
# string        stands for                      Globus context meaning
# --------------------------------------------------------------------
# Q             Queued                          PENDING
# S             Suspended (Unicos only)         SUSPENDED
# W             Waiting for delayed exection    PENDING
# H             Held                            SUSPENDED
# T             Being moved to new location     PENDING
# R             Running                         ACTIVE
# E             Exiting after having run        ACTIVE
#
# There are no states which indicate any type of failure.
# Once the job has completed information about it is no longer available.
# Therefore, the job will be considered completed.
########


. ${GLOBUS_LOCATION}/libexec/globus-script-initializer

globus_source ${libexecdir}/globus-gram-protocol-constants.sh
globus_source ${libexecdir}/globus-sh-tools.sh
globus_source ${libexecdir}/globus-gram-job-manager-tools.sh



# programs used in this script located by autoconf:
uptime=${GLOBUS_SH_UPTIME-uptime}
qstat=${GLOBUS_GRAM_JOB_MANAGER_QSTAT-qstat}
grep=${GLOBUS_SH_GREP-grep}                                 
awk=${GLOBUS_SH_AWK-awk}
wc=${GLOBUS_SH_WC-wc}
########

tmp_file="${local_tmpdir}/globus_tmp_file.$$"


############################################################
#
# GetNodeCountFork
#
#
# Get free and total nodes from the system.
#
# *** This routine in only used if the below GetNodeCount routine fails!
#

GetNodeCountFork () {

   # defaults...
   FREENODES=0
   TOTALNODES=0

   ${GLOBUS_LOCATION}/libexec/grid-info-cpufast-uptime -hostobj | \
   {
      while read attr val
      do
          case "$attr" in
              Mds-Cpu-Smp-size:)
                  TOTALNODES="$val"
              ;;


              Mds-Cpu-Free-1min:)
                  smp_free_1minX100="$val"
                  # truncate fixed-precision fraction to whole integer
                  FREENODES=`expr $smp_free_1min / 100`
              ;;
          esac
      done
      echo "${TOTALNODES} ${FREENODES}"
   }

} #########################


############################################################
#
# GetNodeCount
#
#
# Get free and total nodes from the system
#
# Note that at UChicago, the default queue does not have any size
# limitations, so it doesn't provide any information to the user.
# We'll use the Fork count if no numbers show up from the above, under
# the theory that the pbs queue manages the machine it's running on.
#
GetNodeCount() {
    TOTALNODES=0;
    FREENODES=0;
    # for PBS, the size of a PBS node may be defined as 2 CPUs, on
    # an Origin 2K, for example. If this is the case, modify the
    # PBS_NODESIZE variable to match your site's info
    PBS_NODESIZE=1


    eval `${qstat} -a | ${awk} '
    BEGIN {
        total=0; used=0;
    }
    /nodes used/ {
        slash = index($2, "/");
        used += int(substr($2,0,slash-1));
        total += int(substr($2,slash+1));
    }
    END {
        printf("TOTALNODES=%d ; FREENODES=%d ;", total, total-used);
    }'`


    TOTALNODES=`expr $TOTALNODES \* $PBS_NODESIZE`
    FREENODES=`expr $FREENODES \* $PBS_NODESIZE`


    if [ $TOTALNODES -eq 0 ] && [ $FREENODES -eq 0 ]; then
        NODE_COUNTS=`GetNodeCountFork`
        TOTALNODES=`echo "$NODE_COUNTS" | ${awk} '{ print $1 }'`
        FREENODES=`echo "$NODE_COUNTS" | ${awk} '{ print $2 }'`
    fi
} #########################


############################################################
#
# OutputQueueEntry
#
#
# convert scheduler specific information to the standard GRAM queue 
# entry parameters.
#
# format GRAM_SCRIPT_QE:<GRAM parameter> <scheduler value>
#
OutputQueueEntry() {
    echo "GRAM_SCRIPT_Q:StartQueue"
    echo "GRAM_SCRIPT_Q:queueName ${queueName}" 
    echo "GRAM_SCRIPT_Q:totalNodes ${TOTALNODES}"
    echo "GRAM_SCRIPT_Q:freeNodes ${FREENODES}"
    echo "GRAM_SCRIPT_Q:maxtime ${maxWalltime}"
    echo "GRAM_SCRIPT_Q:maxCPUtime ${maxCputime}"
    echo "GRAM_SCRIPT_Q:maxCount ${TOTALNODES}"
#   echo "GRAM_SCRIPT_Q:maxReqNodes ${maxReqNodes}"
    echo "GRAM_SCRIPT_Q:maxRunningJobs 0"
    echo "GRAM_SCRIPT_Q:maxJobsInQueue ${numMaxConcurrJobs}"
    echo "GRAM_SCRIPT_Q:maxTotalMemory ${maxJobMemory}"
    echo "GRAM_SCRIPT_Q:maxSingleMemory ${maxJobMemory}"
    echo "GRAM_SCRIPT_Q:whenActive 0"
    echo "GRAM_SCRIPT_Q:status ${queueStatus}"
    echo "GRAM_SCRIPT_Q:dispatchType batch"
#   echo "GRAM_SCRIPT_Q:priority 0"
#   echo "GRAM_SCRIPT_Q:allowedUser user1"
#   echo "GRAM_SCRIPT_Q:allowedUser user2"
#   echo "GRAM_SCRIPT_Q:jobWait 0"
#   echo "GRAM_SCRIPT_Q:schedulerSpecific"
#   echo "GRAM_SCRIPT_Q:notlistingjobentries"
    echo "GRAM_SCRIPT_Q:EndQueue"
}


############################################################
#
# OutputJobEntry
#
#
# convert scheduler specific information to the standard GRAM queue
# entry parameters.
#
# format GRAM_SCRIPT_QE:<GRAM parameter> <Job Entry Value>
#
OutputJobEntry() {
     echo "GRAM_SCRIPT_QE:startqueueentry"
     echo "GRAM_SCRIPT_QE:localjobid ${localjobid}"
     echo "GRAM_SCRIPT_QE:localusername ${localusername}"
     echo "GRAM_SCRIPT_QE:localjobname ${localjobname}"
     echo "GRAM_SCRIPT_QE:count ${count}"
     echo "GRAM_SCRIPT_QE:requesteddmemory ${reqdmemory}"
     echo "GRAM_SCRIPT_QE:requestedtime ${reqdtime}"
     echo "GRAM_SCRIPT_QE:elapsedtime ${elapsedtime}"
     echo "GRAM_SCRIPT_QE:status ${status}"
     echo "GRAM_SCRIPT_QE:endqueueentry"
} 


####################################################
# 
# main 
#
# Output Node information


# Ouput queue values where possible


GetNodeCount


# Collect job information into file for later processing
${qstat} -a > "${tmp_file}"


# Collect queue information 
msgfound="false"
${qstat} -q | while read entry ; do
    if [ $? != 0 ]; then
    break
    fi
    set -- ${entry}
    if [ "$1" = "Queue" ] ; then
    msgfound="true"
        continue
    elif [ $msgfound = "false" ]; then
    continue
    fi 


    firstchar=`echo $entry | cut -c1 | sed 's/[^a-zA-Z]//'`
    if [ "$firstchar" = "-" -o ! "$firstchar" ]
    then
        continue
    fi   


    queueName=$1
    shift


    if [ "$1" = "--" ] ; then
    maxJobMemory="unlimited"
    else
    maxJobMemory="$1"
    fi
    shift


    # Represent time in minutes for now since globus_job_manager casts to long 
    if [ "$1" = "--" ] ; then
    maxCputime="unlimited"
    else
    maxCputime=`echo "$1" | awk -F: '{ print 60 * $1 + $2 }'`
    fi
    shift 


    if [ "$1" = "--" ] ; then
    maxWalltime="unlimited"
    else
        maxWalltime=`echo "$1" | awk -F: '{ print 60 * $1 + $2 }'` 
    fi
    shift 


    if [ "$1" = "--" ] ; then
    maxReqNodes="unlimited"
    else
    maxReqNodes="$1"
    fi
    shift


    if [ "$1" = "--" ] ; then
    numRunningJobs="0"
    else
    numRunningJobs="$1"
    fi
    shift


    if [ "$1" = "--" ] ; then
    numQueuedJobs="0"
    else
    numQueuedJobs="$1"
    fi
    shift


    if [ "$1" = "--" ] ; then
    numMaxConcurrJobs="0"
    else
    numMaxConcurrJobs="$1"
    fi
    shift


    firstchar=`echo $1 | cut -c1`
    if [ "$firstchar" = "E" ] ; then
    queueStatus="enabled"
    elif [ "$firstchar" = "D" ] ; then
    queueStatus="disabled"
    else
    queueStatus="unknown"
    fi
    shift
    OutputQueueEntry


# obtain  information about jobs in this queue 
    while read jobentry ; do
    set -- ${jobentry}
    if [ "$3" != "$queueName" ] ; then
         continue
       else
         localjobid=$1
         localusername=$2
         localjobname=$4
         reqdnodes=$6
         reqdtasks=$7
         reqdmemory=$8
         if [ $reqdmemory = "--" ]; then
             reqdmemory="unknown"
         fi
         reqdtime=$9
         shift
         status=$9
         if [ $status = "R" ]; then
             status="running"
         fi
         if [ $status = "Q" ]; then
             status="queued"
         fi
         shift
         elapsedtime=`echo "$9" | awk -F: '{print 60 * $1 + $2}'`
         count=$reqdnodes
         if [ -z $count -o $count = "--" ]; then
             if [ -z $reqdtasks ]; then
          count="0"
             fi
             count=$reqdtasks
         fi
         OutputJobEntry
       fi

    done < "${tmp_file}"

done

rm ${tmp_file}
