[gridengine users] Change the format of sge delivered mail

Reuti reuti at staff.uni-marburg.de
Wed Oct 17 19:40:51 UTC 2018


Am 17.10.2018 um 19:50 schrieb Nelson Kick:

> Is there any way to add variables to the standard “beas” mail?  Would like to add
> additional info to this list… if possible, like SGE_O_PATH or other env variables.

Please find below the complete mail-wrapper script. Be default, we are interested in the context variables set by our script generator:

#$ -ac COMMAND=
#$ -ac OUTPUT=
#$ -ac MAIL_ATTACHMENT=
#$ -ac MAIL_RECIPIENTS_LIST=

The content of OUTPUT= and MAIL_ATTACHMENT= are most likely the same, but the users wanted a way to get the name of the output file without it being attached to the email all the time. Hence these two context variable, which have a similar purpose. A flag could have done the same. The mail-wrapper script also tries to mangle the suffix of the file from *.log or *.out file to read (only in the attachment) *.txt instead. This way even mail applications on a smartphone should be able to display the attachment without complaining.

The MAIL_RECIPIENTS_LIST= are alternate or additional receivers of the email. If the list starts with a "+", these will be added to the original receiver (bug/feature alert: if the list in SGE has several receivers already (added by -M in `qsub`), the mail-wrapper script will be called for each of them once – hence the additional receivers will get duplicate emails). Without the "+" the list will replace the original receiver. The list entries must be delimited by ";", as the "," will already be used to separate all the fields in SGE's output of the context variables.

(The context script I posted already will convert the ";" in ",", as in the context file it creates the entries are already on separates lines. The mail wrapper in turn will replace the "," with a " ", as this is what our mail application expects if several receivers are specified as delimiter.)

One variable is created by the prolog itself with the line:

qconf -ac NODES=…

to get a list of used nodes for this particular job.

Please let me know, if something is unclear. I hope it will work in a general case too.

-- Reuti

================ mail-wrapper script follows ================

#!/bin/sh

#
# Assemble an email and attach an output file.
# Note: SGE will call this routine for each and every recipient specified
# with the -M option. It won't use the feature of the mail application
# to honor a list of recipients. This wrapper will do.
#

export PATH=/usr/local/bin:/bin:/usr/bin
. /usr/sge/default/common/settings.sh

line() {
    if [ -f /var/spool/sge/context/$JOB_ID -a -r /var/spool/sge/context/$JOB_ID ]; then
        echo $(sed -n -e "/^${1}=/s///p" /var/spool/sge/context/$JOB_ID)
    fi
}
     
entry() {
    RESULT=$(line ${1})
    if [ -n "${RESULT}" ]; then
        echo "${1}: ${RESULT}"
    else
        echo "${1}: [none recorded]"
    fi
}

command_line() {
    COMMAND_LINE=$(qstat -j ${JOB_ID} | sed -n -e "/^context/{s/^context: *//;s/,/\n/g;s/;/,/g;p}" | sed -n -e "/^COMMAND=/s///p")
    echo
    if [ -n "${COMMAND_LINE}" ]; then
        echo "COMMAND: ${COMMAND_LINE}"
    else
        echo "COMMAND: [none recorded]"
    fi
}

context() {
    echo
    entry COMMAND
    entry OUTPUT
    entry NODES
}

assemble_recipients_list() {
    if [ -n "${MAIL_RECIPIENTS_LIST}" ]; then
        if [ "${MAIL_RECIPIENTS_LIST:0:1}" = "+" ]; then
            MAIL_RECIPIENTS_LIST="$1,${MAIL_RECIPIENTS_LIST:1}"
        fi
    else
        MAIL_RECIPIENTS_LIST="${1}"
    fi
    MAIL_RECIPIENTS_LIST="${MAIL_RECIPIENTS_LIST//,/ }"
}

check_and_prepare_attachment() {

    tmpdir="/tmp"

    if [ -n "${MAIL_ATTACHMENT}" ]; then
       if [ ! -f "${MAIL_ATTACHMENT}" ]; then
           ATTACHMENT_ERROR="The requested attachment file \`${MAIL_ATTACHMENT}' does not exist."
           return 1
       elif [ ! -r "${MAIL_ATTACHMENT}" ]; then
           ATTACHMENT_ERROR="The requested attachment file \`${MAIL_ATTACHMENT}' couldn't be read."
           return 1
       fi

       filename=$(basename "${MAIL_ATTACHMENT}")
       suffix=${filename##*.}
       if [ "${suffix}" = "${filename}" ]; then
           suffix=""
       fi
       filename="${filename%.*}"
       if [ $(stat --printf="%s" "${MAIL_ATTACHMENT}") -gt 1048576 ]; then
           ATTACHMENT_WARNING1="The requested attachment file \`${MAIL_ATTACHMENT}' has a size > 1 MiB. The attachment in this email was truncated and contains the last MiB only."
           filename="${filename}_last_MiB"
           mangle_attachment="1"
       fi

       if [ -z "${suffix}" -o "${suffix}" = "log" -o "${suffix}" = "out" -o "${suffix}" = "last" ]; then
           ATTACHMENT_WARNING2="The suffix of the requested attachment file \`${MAIL_ATTACHMENT}' was mangled to \`.txt' for this email only."
           suffix="txt"
           mangle_attachment="1"
       fi
       
       if [ -n "${mangle_attachment}" ]; then
           if [ ! -d "${tmpdir}" -o ! -w "${tmpdir}" -o ! -r "${tmpdir}" ]; then
               ATTACHMENT_ERROR="The temporary scratch space can't be accessed to create a directory for the mangled attachment."
               return 1
           fi
           if ! directory=$(mktemp -d); then
               ATTACHMENT_ERROR="The directory in the temporary scratch space can't be created to store a mangled mangled."
               return 1
           fi
    
           target_filename="${directory}/${filename}${suffix:+.${suffix}}"
           if ! tail -c 1048576 "${MAIL_ATTACHMENT}" > "${target_filename}"; then
               ATTACHMENT_ERROR="A mangled attachment couldn't be saved."
               MAIL_ATTACHMENT=""
               return 1
           else
               MAIL_ATTACHMENT="${target_filename}"
           fi
       fi
   fi
}

clean_attachment() {
    if [ -n "${directory}" -a "${directory:0:${#tmpdir}}" = "${tmpdir}" ]; then
        if [ -w "${tmpdir}" -a -r "${tmpdir}" ]; then
            rm -rf "${directory}"
        fi
    fi
}

processing_error() {
    if [ -n "${ATTACHMENT_ERROR}" -o -n "${APPENDIX}" -o \
         -n "${ATTACHMENT_WARNING1}" -o  -n "${ATTACHMENT_WARNING2}" ]; then
        echo
    fi

    if [ -n "${APPENDIX}" ]; then
        echo "Reason for job abort:"
        echo "${APPENDIX}"
        if [ -n "${ATTACHMENT_ERROR}" ]; then
            echo
        fi
    fi
    if [ -n "${ATTACHMENT_WARNING1}" ]; then
        echo "${ATTACHMENT_WARNING1}"
    fi
    if [ -n "${ATTACHMENT_WARNING2}" ]; then
        echo "${ATTACHMENT_WARNING2}"
    fi
    if [ -n "${ATTACHMENT_ERROR}" ]; then
        echo "${ATTACHMENT_ERROR}"
    fi
}

#
# Distinguish between normal jobs and an array job.
#

case `echo "$2" | cut -d " " -f 1` in

      Job) JOB_ID=`echo "$2" | cut -d " " -f 2`
           CONDITION=`echo "$2" | cut -d " " -f 4` ;;

Job-array) JOB_ID=`echo "$2" | cut -d " " -f 3`
           CONDITION=`echo "$2" | cut -d " " -f 5` ;;

        *) ;;

esac

#
# Get the entries for the context of the job and the
# reason in case of an abortion of the job.
#

if [ "$CONDITION" = "Started" ]; then

#
# Now construct and send the email for started jobs.
#
    MAIL_RECIPIENTS_LIST=$(qstat -j ${JOB_ID} | sed -n -e "/^context/{s/^context: *//;s/,/\n/gp}" | sed -n -e "/^MAIL_RECIPIENTS_LIST=/s///p")
    assemble_recipients_list "${3}"

    (cat; command_line) | mail -s "$2" ${MAIL_RECIPIENTS_LIST}

elif [ "$CONDITION" = "Complete" -o "$CONDITION" = "Aborted" ]; then

#
# Now construct and send the email for completed or aborted jobs.
#
    if [ "$CONDITION" = "Aborted" ]; then
        if [ -f /var/spool/sge/$HOSTNAME/messages -a -r /var/spool/sge/$HOSTNAME/messages ]; then
            APPENDIX=`egrep "[|]job $JOB_ID([.][[:digit:]]+)? exceed" /var/spool/sge/$HOSTNAME/messages | head -n 1`
        fi
    
        if [ -z "$APPENDIX" ]; then
            APPENDIX="Unknown, no entry found in messages file on the master node of the job."
        fi
    fi

#
# Extra Processing for attachments.
#
    MAIL_RECIPIENTS_LIST=$(line MAIL_RECIPIENTS_LIST)
    assemble_recipients_list "${3}"
    MAIL_ATTACHMENT=$(line MAIL_ATTACHMENT)
    check_and_prepare_attachment

    if [ -z "${ATTACHMENT_ERROR}" -a -n "${MAIL_ATTACHMENT}" ]; then
       (cat; context; processing_error) | mail -a "${MAIL_ATTACHMENT}" -s "$2" ${MAIL_RECIPIENTS_LIST}
    else
       (cat; context; processing_error) | mail -s "$2" ${MAIL_RECIPIENTS_LIST}
    fi
    
    if [ -f /var/spool/sge/context/$JOB_ID -a -w /var/spool/sge/context/$JOB_ID ]; then
        rm -f /var/spool/sge/context/$JOB_ID
    fi

    clean_attachment
else
    mail -s "$2" "$3"
fi




More information about the users mailing list