#!/bin/ksh93 # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # 61haes_r720 src/43haes/usr/sbin/cluster/cspoc/cdsh.sh 1.16.1.3 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 1996,2015 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG # @(#)05 1.16.1.3 src/43haes/usr/sbin/cluster/cspoc/cdsh.sh, hacmp.cspoc, 61haes_r720, 1538A_hacmp720 9/4/15 14:29:33 #================================================ # The following, commented line enforces coding # standards when this file is edited via vim. #================================================ # vim:tabstop=4:shiftwidth=4:expandtab:smarttab #================================================ ############################################################################### # COMPONENT_NAME: CSPOC # # Name: # cdsh # # Description: # Performs remote execution of commands across the nodes of a cluster # and manages the stdout & stderr streams returned by those commands. # # Arguments: # prefix - temp file name prefix # node_list - comma separated list of nodes on which to run the underlying # AIX command # -q[1|2] - quiet flag # suppresses output to stdout and/or stderr # command - underlying AIX command to run # args - underlying AIX command arguments # # Return Values: # 0 - successfully connected to all the nodes # 2 - invalid arguments # ############################################################################### PROGNAME=${0##*/} PATH="$(/usr/es/sbin/cluster/utilities/cl_get_path all)" if [[ -n $_DEBUG ]] && (( $_DEBUG == 9 )) then export PS4='${PROGNAME}[$LINENO]: ' print -u2 'Version 1.16.1.3' set -x fi ############################################################################### # # Subroutine Name: # run_command # # Description: # Runs the given command on the specified host. Displays a message with # the return code if non-zero. # # Arguments: # Target host name # # Environment: # command - encoded command to run on remote node # CEXEC - command driver on remote node # emsg_cmd - command plus operands to display in error message # # Output: # command stdout and stderr # error message in case of error # function run_command { # : Run the command on the specified host. Print err msg if needed. # typeset host=$1 /usr/es/sbin/cluster/utilities/cl_rsh -n $host ${CEXEC} $command typeset RC=$? if (($RC)) then # : Get the actual script name that we are to execute : to correctly fill in error message for logs # # Have the following cases for $command: # 1) eval # 2) command # 3) command - - ... # 4) command # print $command | read CMD ecmd # CMD is typically but not always 'eval' for word in $ecmd do if [[ $word == -* ]] then demsg_cmd="$demsg_cmd $word" else demsg_cmd="$demsg_cmd $(print $word | /usr/es/sbin/cluster/cspoc/cldecodearg)" fi done if [[ $CMD == "eval" ]] then print $demsg_cmd | read demsg_cmd demsg_cmd_opts else demsg_cmd_opts=$demsg_cmd demsg_cmd=$CMD # CMD is the command that will be run CMD="" fi emsg_cmd="${CEXEC} $CMD $demsg_cmd $demsg_cmd_opts" print -u2 "cdsh: cl_rsh: (RC=$RC) $emsg_cmd" fi } ############################################################################### # # Subroutine Name: # FixUp # # Description: # Processes stdout and stderr from a command run on a remote node. # These always go to a log file, and may go on to stdout/stderr, or # be suppressed, based on caller input. # # Arguments: # Output type to be processed - "stdout" or "stderr" # # Environment: # suppress - output to be suppressed - "stdout", "stderr", "both", or # "none" # host - target node for command # OUT_FILE - caller provided log file name # # Output: # command stdout and stderr, log file contents # function FixUp { # : Suppress output if selected, otherwise prepend the hostname # typeset OUTPUT_TYPE=$1 if [[ $OUTPUT_TYPE == stdout ]] then # : Process the stdout # if [[ $suppress == @($OUTPUT_TYPE|both) ]] then # : Prepend hostname and send to logfile only # cat | sed "s/^/${host}: /" >> $OUT_FILE else # : Prepend hostname and send to logfile and FD3 : which is parent FD1 # cat | sed -u "s/^/${host}: /" | tee -a $OUT_FILE >&3 fi else # : Process the stderr # if [[ $suppress == @($OUTPUT_TYPE|both) ]] then # : Prepend hostname and send to logfile only # cat | sed "s/^/${host}: /" >> $ERR_FILE else # : Prepend hostname and send to logfile and STDERR # cat | sed -u "s/^/${host}: /" | tee -a $ERR_FILE | grep -uv ": RETURN_CODE=" >&2 fi fi } ############################################################################## # # Main MAIN main # # : Check usage # if (( $# < 3 )) then USAGE='USAGE: cdsh [-q[1|2]] [args]\n' nls_msg -2 2 3 "$USAGE" return 2 fi # : Local variables # typeset CEXEC=/usr/es/sbin/cluster/cspoc/cexec # : Get first two args: Temp file prefix and Node list # typeset PREFIX=$1 \ OUT_FILE=$PREFIX.out \ ERR_FILE=$PREFIX.err \ NODE_LIST=$2 \ # NOTE: THIS LINE ENDS CONTINUATION OF PREVIOUS LINE shift 2 # Skip past prefix and node list # : Ensure the error and output files exist # touch ${OUT_FILE} touch ${ERR_FILE} # : Suppress display of stderr and stdout as required # Notes: # - The return code that cexec stuffed into stderr is stripped # from the output returned to the user. # - Output from cdsh is appended to the temp files so that there # is one temp file per try statement. # - The quiet options supress stdout, stderr, or both as required. # typeset suppress="" case $1 in -q1) : suppress stdout suppress=stdout shift ;; -q2) : suppress stderr suppress=stderr shift ;; -q) : suppress both stdout and stderr suppress=both shift ;; *) : do not supress stdout or stderr suppress=none ;; esac # : Get the actual script name that we are to execute # command=$* # Complete, with operands # : Open FD3 and redirect to STDOUT so that FixUp can send direct to STDOUT # exec 3>&1 # : Executing the command on the nodes ${NODE_LIST} # for host in $(IFS=, set -- ${NODE_LIST} ; print $* ) do # : For each host, run and post-process the output # { run_command $host | FixUp stdout; } 2>&1 | FixUp stderr done exit 0