#!/bin/ksh export try_out try_err cspoc_tmp_log export FPATH=/usr/es/sbin/cluster/cspoc cspoc_tmp_log=/var/hacmp/log/cel$$_tmplog log_cmd $cspoc_tmp_log $0 $* trap 'cexit $cspoc_tmp_log $?' EXIT function cel_f1 { cel_s1=/tmp/cel$$_s1 try_err=${cel_s1}.err try_out=${cel_s1}.out trap "log_output $cspoc_tmp_log ${cel_s1} eval $LSLPP_CMD" EXIT cdsh $cel_s1 $Check_nodes -q1 eval $LSLPP_CMD IFS=,$IFS for node in $Check_nodes; do cel_rc=$(get_rc ${cel_s1} $node) case $cel_rc in esac done IFS=${IFS#,} return $cel_rc } function cel_f2 { cel_s2=/tmp/cel$$_s2 try_err=${cel_s2}.err try_out=${cel_s2}.out trap "log_output $cspoc_tmp_log ${cel_s2} lsdev -l $lsdev_name" EXIT IFS=,$IFS for node in $Check_nodes; do cdsh $cel_s2 $node -q lsdev -l $lsdev_name cel_rc=$(get_rc ${cel_s2} $node) case $cel_rc in 0) # : lsdev always returns success, so we have to check : the output to see if there is anything there # if grep '^'${node}':' $try_out | egrep -qw -e "${Check_name}|r${Check_name}" then bad_nodes=${bad_nodes:+$bad_nodes","}${node} try_rc=1 fi ;; esac done IFS=${IFS#,} return $cel_rc } function cel_f3 { cel_s3=/tmp/cel$$_s3 try_err=${cel_s3}.err try_out=${cel_s3}.out trap "log_output $cspoc_tmp_log ${cel_s3} ls $slashdev" EXIT IFS=,$IFS for node in $Check_nodes; do cdsh $cel_s3 $node -q ls $slashdev cel_rc=$(get_rc ${cel_s3} $node) case $cel_rc in 0) # : The ls command should always return success. This : formulation chosen to avoid filling up the log with : spurious remote command failure messages. Now, see : if the name we are checking for is there. # if grep '^'${node}':' $try_out | egrep -qw -e "${Check_name}|r${Check_name}" then bad_nodes=${bad_nodes:+$bad_nodes","}${node} try_rc=1 fi ;; esac done IFS=${IFS#,} return $cel_rc } function cel_f4 { cel_s4=/tmp/cel$$_s4 try_err=${cel_s4}.err try_out=${cel_s4}.out trap "log_output $cspoc_tmp_log ${cel_s4} eval $ECMD" EXIT IFS=,$IFS for node in $Cluster_node; do cdsh $cel_s4 $node -q1 eval $ECMD cel_rc=$(get_rc ${cel_s4} $node) case $cel_rc in 0) # : Comma separated list of nodes on which the disk : appears that are not in \$_TARGET_NODES # Disk_nodes=${Disk_nodes:+$Disk_nodes","}${node} # : Corresponding comma separated list of names that : the disk appears under on those nodes # Disk_names=${Disk_names:+$Disk_names","},$(grep -w ^${node} $try_out | cut -f2 -d: | cut -f2 -d' ') ;; esac done IFS=${IFS#,} return $cel_rc } function cel_f5 { cel_s5=/tmp/cel$$_s5 try_err=${cel_s5}.err try_out=${cel_s5}.out trap "log_output $cspoc_tmp_log ${cel_s5} eval $rename_cmd" EXIT cdsh $cel_s5 $_TARGET_NODES -q1 eval $rename_cmd IFS=,$IFS for node in $_TARGET_NODES; do cel_rc=$(get_rc ${cel_s5} $node) case $cel_rc in *) if [ $cel_rc != 0 ]; then ran_cmd="$(print $rename_cmd | cldecodearg)" nls_msg -2 -l $cspoc_tmp_log $_MSET 82 "cl_rendisk: rename of $DOld_disk to $DNewName ($ran_cmd) failed on node $node\n" $DOld_name $DNewName "$ran_cmd" $node try_rc=1 fi ;; esac done IFS=${IFS#,} return $cel_rc } function cel_f6 { cel_s6=/tmp/cel$$_s6 try_err=${cel_s6}.err try_out=${cel_s6}.out trap "log_output $cspoc_tmp_log ${cel_s6} eval $rename_cmd" EXIT IFS=,$IFS for node in $disk_node; do cdsh $cel_s6 $node -q1 eval $rename_cmd cel_rc=$(get_rc ${cel_s6} $node) case $cel_rc in *) if [ $cel_rc != 0 ]; then ran_cmd="$(print $rename_cmd | cldecodearg)" nls_msg -2 -l $cspoc_tmp_log $_MSET 82 "cl_rendisk: rename of $disk_name to $DNewName ($ran_cmd) failed on node $node\n" $disk_name $DNewName "$ran_cmd" $node try_rc=1 IFS=${IFS#,} return fi ;; esac done IFS=${IFS#,} return $cel_rc } # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # 61haes_r714 src/43haes/usr/sbin/cluster/cspoc/plans/cl_rendisk.cel 1.3 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 2010,2011 # 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 # $Id$ ############################################################################### # # Name: # cl_rendisk.cel # # Description: # The cl_rendisk command renames a physical volume on all nodes of the cluster # # Usage: cl_rmmp -cspoc "[-f] [-g ResourceGroup | -n NodeList ]" \ # -N NewDiskName [-Y PVID ] CurrentDiskName # # Arguments: # Current disk name on the given list of nodes # Proposed new disk name # Disk PVID, indicating that the disk with that PVID is to be renamed on # all cluster nodes # # The C-SPOC specific arguments are as follows: # -f C-SPOC force flag # -g ResourceGroup Resource group on which to execute cl_chvg # -n NodeList Cluster nodes on which to execute cl_chvg # # Return Values: # 0 success # 1 failure # ################################################################################ ###################################################################### # # Function: Check to make sure that the 'rendev' command is # available on all nodes on which the disk is going # to be changed # # Input: Current Device name # Proposed new device name # List of nodes to check in $Check_nodes # # Output: return code # 0 = command is available # ###################################################################### can_rendev() { [[ -n $_DEBUG ]] && { print "DEBUG: Entering can_rendev version $Source: 61haes_r711 43haes/usr/sbin/cluster/cspoc/plans/cl_rendisk.cel 1$2" (( $_DEBUG >= 8 )) && { typeset PROGNAME=can_rendev set -x } } integer V R M F typeset -Z2 R # two digit release typeset -Z3 M # three digit modification typeset -Z3 F # three digit fix integer VRMF=0 typeset do_check=false # need to check each node typeset LSLPP_CMD typeset NODE_LIST typeset bad_nodes integer rc=0 # return code # : Pick up passed parameters. Used for error messages # Orig_name=$1 # current disk name, unencoded Check_name=$2 # proposed new disk name, unencoded bad_nodes="" # nodes on which there is a name collision # : First, check the already collected level of PowerHA across the : cluster. If its 7.1 or greater, the known AIX pre-req means : that mirror pools are supported # if [[ -s /usr/es/sbin/cluster/etc/config/haver.info ]] then tail +2 /usr/es/sbin/cluster/etc/config/haver.info | \ while read node ha_level do if (( $ha_level <= 7100 )) then # : PowerHA is at level $ha_level on node $node # do_check=true break fi done else do_check=true fi # : The check of the collected PowerHA levels shows some earlier than 7.1 : So, have to check the AIX level on each node # if [[ $do_check == true ]] then # : The device rename command 'rendev' is only available on nodes : running bos.rte.methods 6.1.6 or later. : Check to see what is installed. # LSLPP_CMD=$(print -- 'lslpp -lcqOr bos.rte.methods | cut -f3 -d:' | clencodearg) cel_f1 # : Process the output from that check - is any node at lower : than 6.1.6? # if [[ ! -s $try_out ]] then bad_nodes=$Check_nodes else while IFS=: read node version_info do print -- "$version_info" | IFS=. read V R M F VRMF=$V$R$M$F if (( $VRMF < 601006000 )) then # : This node is not at a level that supports : the 'rendev' command # bad_nodes=${bad_nodes:+$bad_nodes","}${node} fi done < $try_out fi fi # : Print an informative error message if the operation is not possible # if [[ -n $bad_nodes ]] then nls_msg -2 -l $cspoc_tmp_log $_MSET 106 "cl_rendisk: $Orig_name cannot be renamed to $Check_name on nodes $bad_nodes because those nodes do not support the device rename command. The device rename command is part of AIX 6.1.6\n" $Orig_name $Check_name $bad_nodes return 1 else return 0 fi } ###################################################################### # # Function: Check to make sure that a device name - or its raw name # equivalent - is not already in use in the cluster # # Input: Current Device name # Proposed new device name # # Output: return code # 0 = no name conflict # ###################################################################### name_use_check() { [[ -n $_DEBUG ]] && { print "DEBUG: Entering name_use_check version $Source: 61haes_r711 43haes/usr/sbin/cluster/cspoc/plans/cl_rendisk.cel 1$2" (( $_DEBUG >= 8 )) && { typeset PROGNAME=name_use_check set -x } } Orig_name=$1 # current disk name, unencoded Check_name=$2 # proposed new disk name, unencoded bad_nodes="" # nodes on which there is a name collision # : Check to see if there is already a device with the given name : on any of the nodes # try_rc=0 lsdev_name=$(print '*'${Check_name} | clencodearg) cel_f2 if (( $try_rc != 0 )) then nls_msg -2 -l $cspoc_tmp_log $_MSET 79 "cl_rendisk: $Orig_name cannot be renamed to $dev_name on node $bad_nodes because that name is already in use by another device\n" $Orig_name $dev_name $bad_nodes return $try_rc fi # : Check to see if there is already a device with the given : raw device name on any of the nodes # bad_nodes="" try_rc=0 slashdev=$(print -- '/dev' | clencodearg) cel_f3 if (( $try_rc != 0 )) then nls_msg -2 -l $cspoc_tmp_log $_MSET 80 "cl_rendisk: $Orig_name cannot be renamed to $Check_name on node $bad_nodes because /dev/$Check_name already exists\n" $Orig_name $Check_name $bad_nodes $Check_name fi return $try_rc } ############################################################################# # : Include the PATH and PROGNAME initialization stuff # # @(#)69 1.8 src/43haes/usr/sbin/cluster/cspoc/plans/cl_path.cel, hacmp.cspoc, 61haes_r720, 1539B_hacmp720 9/10/15 13:28:25 # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # 61haes_r720 src/43haes/usr/sbin/cluster/cspoc/plans/cl_path.cel 1.8 # # Licensed Materials - Property of IBM # # Restricted Materials of IBM # # COPYRIGHT International Business Machines Corp. 1999,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 ################################################################################ # COMPONENT_NAME: CSPOC # # Name: # cl_path.cel # # Description: # C-SPOC Path Initialization Routine. This routine is to be included # in all C-SPOC Execution Plans (e.g. '%include cl_path.cel'). # it sets up the PATH environment variable to prevent hardcoding of # path names in the CSPOC code. # # Arguments: # None. # # Return Values: # None. # # Environment Variables Defined: # # PUBLIC: # PROGNAME Represents the name of the program # HA_DIR Represents the directory the HA product is shipped under. # ################################################################################ PROGNAME=${0##*/} PATH="$(/usr/es/sbin/cluster/utilities/cl_get_path all)" # set the HA_DIR env variable to the HA directory HA_DIR="es" # Set up useful prompt for when 'set -x' is turned on through _DEBUG if [[ -n $_DEBUG ]] && (( $_DEBUG == 9 )) then PS4='${PROGNAME:-$_CMD}[$LINENO]: ' set -x fi [[ -n $_DEBUG ]] && print "DEBUG $PROGNAME version $Source: 61haes_r711 43haes/usr/sbin/cluster/cspoc/plans/cl_rendisk.cel 1$" # : Initialize variables needed to parse input # _CMD_NAME=${0##*/} _CSPOC_OPT_STR="d:f?[g:n:]" _OPT_STR="+1N^Y:" _USAGE="$(dspmsg -s 21 cspoc.cat 81 'Usage: cl_rendisk -cspoc \"[-f] [-g ResourceGroup | -n NodeList]\" -N new_disk_name [-Y PVID] hdisk_name\n')" _MSET=127 # : Include CELPP init code and verification routines. # # ALTRAN_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # Copyright (C) Altran ACT S.A.S. 2017,2018,2019,2021. All rights reserved. # # ALTRAN_PROLOG_END_TAG # # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # 61haes_r721 src/43haes/usr/sbin/cluster/cspoc/plans/cl_init.cel 1.16.7.9 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 1996,2016 # 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 # @(#) 7d4c34b 43haes/usr/sbin/cluster/cspoc/plans/cl_init.cel, 726, 2147A_aha726, Feb 05 2021 09:50 PM ################################################################################ # # COMPONENT_NAME: CSPOC # # Name: # cl_init.cel # # Description: # C-SPOC Initialization Routine. This routine is to be included # in all C-SPOC Execution Plans (e.g. '%include cl_init.cel'). # It defines the ksh functions required to implement C-SPOC commands. # # Arguments: # None. # # Return Values: # None. # # Environment Variables Defined: # # PUBLIC: # _OPT_STR Specifies the list of valid command flags. # Must be specified in the execution plan. # # _CSPOC_OPT_STR Specifies the list of valid CSPOC flags. # Must be specified in the execution plan. # # cspoc_tmp_log Full path of the cspoc log file # (/var/hacmp/log/cspoc.log). # # _CLUSTER_NODES A comma separated list of all nodes in the cluster. # # _NODE_LIST A comma separated list of nodes from the command # line (i.e. Those specified by -n or implied by -g). # # _TARGET_NODES A comma separated list that specify the target # nodes for a generated C-SPOC script. # # BADNODES A space-separated list that specifies the nodes # that are either not defined in the cluster or not # reachable for a generated C-SPOC script. # # _RES_GRP The resource group specified by -g on the # command line # # _SPOC_FORCE Set to "Y" when -f specified. Otherwise not set. # # _DEBUG Set to when -d specified. # Otherwise not set. # # _CMD_ARGS The AIX Command Options and arguments from the # C-SPOC command # # _NUM_CMD_ARGS The number of AIX Command Options and arguments # from the C-SPOC command # # _NON_FLG_ARGS The non-flag arguments from the C-SPOC command. # # _OF_NA A list of the optional command flags specified # that do NOT require an option argument. # # _MF_NA A list of the mandatory command flags specified # that do NOT require an option argument. # # _OF_WA A list of the optional command flags specified # that require an option argument. # # _MF_WA A list of the mandatory command flags specified # that require an option argument. # # _VALID_FLGS A list of valid command flags. # # _CSPOC_OPTS The CSPOC Options specified on the command line # following the '-cspoc' flag. # # _CSPOC_OF_NA A list of the optional CSPOC flags specified that # do NOT require an option argument. # # _CSPOC_MF_NA A list of the mandatory CSPOC flags specified that # do NOT require an option argument. # # _CSPOC_OF_WA A list of the optional CSPOC flags specified that # require an option argument. # # _CSPOC_MF_WA A list of the mandatory CSPOC flags specified that # require an option argument. # # _CSPOC_VALID_FLGS A list of valid CSPOC flags for this CSPOC command. # # CLUSTER_OVERRIDE Flag to Cluster Aware AIX Commands to signal that # base AIX commands should be allowed to operate. # Applies to 7.1.0 and later. # ################################################################################ ################################################################################ # # _get_node_list # # DESCRIPTION: # Generates two lists _CLUSTER_NODES is a list of all nodes in the cluster. # ################################################################################ function _get_node_list { if [[ -n $_DEBUG ]] then print "DEBUG: Entering _get_node_list version 1.16.7.9" if (( $_DEBUG >= 8 )); then typeset PROGNAME="_get_node_list" set -x fi fi unset _CLUSTER_NODES typeset NODE IP_ADDR # : GET A comma separated LIST OF ALL NODES IN THE CLUSTER # _CLUSTER_NODES=$(IFS=, set -- $(clodmget -q "object = COMMUNICATION_PATH" -f name -n HACMPnode) ; print "$*") if [[ -n $_DEBUG ]] then print "DEBUG: CLUSTER NODES [${_CLUSTER_NODES}]" print "DEBUG: Leaving _get_node_list" fi # : ENSURE THAT NODES FOUND FOR THE CLUSTER # if [[ -z ${_CLUSTER_NODES} ]]; then nls_msg -2 21 6 \ "${_CMD}: The cluster does not appear to be configured - no nodes are defined. \n Configure the cluster, nodes and networks then try this operation again.\n" $_CMD return 1 fi return 0 } # End of "_get_node_list()" ################################################################################ # # _get_target_nodes # # DESCRIPTION # Sets environment variable $_TARGET_NODES to the list of cluster # on which the C-SPOC command is to be executed. # # 1 - If a node list was specified $_TARGET_NODES is set to # the nodes listed. # # 2 - If a resource group was specified $_TARGET_NODES is set # to the list of nodes that are participating in that # resource group. # # 3 - If neither a node list or resource group has been specified # then $_TARGET_NODES is set to a list of all nodes in the cluster. # ################################################################################ function _get_target_nodes { if [[ -n $_DEBUG ]] then print "DEBUG: Entering _get_target_nodes version 1.16.7.9" if (( $_DEBUG >= 8 )) then typeset PROGNAME="_get_target_nodes" set -x fi fi typeset NODE="" integer GTN_RC=-1 # : If given a node list, or the nodes in a resource group, use those # if [[ -n $_NODE_LIST || -n $_RG_NODE_LIST ]] then _TARGET_NODES=$(IFS=, set -- $_NODE_LIST $_RG_NODE_LIST ; print "$*") GTN_RC=0 # : If no node list given, assume all cluster nodes, if we can find them # elif [[ -n $_CLUSTER_NODES ]] then _TARGET_NODES="$_CLUSTER_NODES" GTN_RC=0 # : Else cannot figure out where to run this # else nls_msg -2 -l ${cspoc_tmp_log} 4 6 \ "%s: Unable to determine target node list!\n" "$_CMD" GTN_RC=1 fi return $GTN_RC } # End of "_get_target_nodes()" ################################################################################ # # _get_rgnodes # # DESCRIPTION # Gets a list of nodes associated with the resource group specified. # ################################################################################ function _get_rgnodes { if [[ -n $_DEBUG ]] then print "DEBUG: Entering _get_rgnodes version 1.16.7.9" if (( $_DEBUG >= 8 )) then typeset PROGNAME="_get_rgnodes" set -x fi fi if [[ -z $1 ]] then nls_msg -2 -l ${cspoc_tmp_log} 4 9 \ "%s: _get_rgnodes: A resource group must be specified.\n" "$_CMD" return 1 fi _RG_NODE_LIST=$(clodmget -q "group = $1" -f nodes -n HACMPgroup) if [[ -z $_RG_NODE_LIST ]] then nls_msg -2 -l ${cspoc_tmp_log} 4 50 \ "%s: Resource group %s not found.\n" "$_CMD" "$1" return 1 fi return 0 } # End of "_get_rgnodes()" ####################################################################### # # _getopts # # DESCRIPTION # Parses comand line options for C-SPOC commands. # ####################################################################### # # OPTION STRING # The _getopts() routine requires the execution plan to define the # environment variable $_OPT_STR which is refered to as the option # string. The option string is used to define valid and/or required # flags, the required number of non-flag arguments, and what flags # may or may not be specified together. # # Operator Description Example # -------- ------------------------------------------ --------- # () Groups mutually required flags (c!d:) # [] Groups mutually exclusive flags [f,b,] # # ? Optional flag (default) b? # ! Mandatory flag c! # # : Optional flag that requires an argument d: # ^ Mandatory flag that requires an argument e^ # # . Optional multi-byte flag # , Mandatory multi-byte flag f, # # +N Indicates that N non-flag arguments are. +2 # required. It must be at the beginning of # the option string. # # Notes: # 1 - A flag that can be specified with or without an argument # would be specified twice as follows: _OPT_STR="a?a:" # # 2 - A flag that requires an argument cannot also be the first # letter of a multi-byte flag. (i.e. -b arg -boot ) as there # is no way to differentiate between the two. # # Example: # The following option string would correspond to the usage below # In the usage '[]' indicates optional flags and '()' indicates # grouping. # # _OPT_STR="+2ab?(c!d:)e^[f,b,]g." # # Usage: # cmd [-a] [-b] -c [-d arg] -e arg ( -foo | -bar ) [-go] arg1 arg2 [arg3] # # ####################################################################### function _getopts { if [[ -n $_DEBUG ]] then print "DEBUG: Entering _getopts 1.16.7.9" if (( $_DEBUG >= 8 )) then typeset PROGNAME="_get_opts" set -x fi fi typeset CMD=${0##*/} # unset the following variables to avoid these variables being # influenced implicitly by external environment. Note that we will # not unset/touch _DEBUG since it is being checked even before hitting # this part of the code. i.e. depending upon the _DEBUG flag we set # set -x option initially itself. unset _NODE_LIST unset _RES_GRP unset _CSPOC_QUIET # LOCAL VARIABLES typeset _OPT_STR _CSPOC_OPT_STR OPT X Y typeset _VALID_FLGS _CSPOC_VALID_FLGS typeset _OF_NA _MF_NA _OF_WA _MF_WA typeset _CSPOC_OF_NA _CSPOC_MF_NA _CSPOC_OF_WA _CSPOC_MF_WA typeset _GOPT=no _NOPT=no # THE FIRST TWO ARGS MUST BE OPTION STRINGS _CSPOC_OPT_STR=$1 _OPT_STR=$2 shift 2 # CHECK CSPOC OPT STRING SPECIFIED IN THE EXECUTION PLAN # FOR OPTIONAL OR REQUIRED FLAGS [[ $_CSPOC_OPT_STR == *g^* ]] && _GOPT=req [[ $_CSPOC_OPT_STR == *g:* ]] && _GOPT=opt [[ $_CSPOC_OPT_STR == *n^* ]] && _NOPT=req [[ $_CSPOC_OPT_STR == *n:* ]] && _NOPT=opt # CHECK IF THE OPTION STRINGS SPECIFY A REQUIRED NUMBER OF NON-FLAG ARGS if [[ $_OPT_STR == +* ]] then X=${_OPT_STR#??} Y=${_OPT_STR%"$X"} _OPT_STR=$X _NUM_ARGS_REQ=${Y#?} fi # PARSE THE OPTION STRING ($_OPT_STR) INTO FIVE LISTS # ${_OF_NA} is a list of optional flags that DO NOT take an option arg. # ${_MF_NA} is a list of mandatory flags that DO NOT take an option arg. # ${_OF_WA} is a list of mandatory flags that DO take an option argument # ${_MF_WA} is a list of optional flags that DO take an option argument # ${_VALID_FLGS} is a list of all valid flags. # Note that both strings start and end with a space (to facilitate grepping) # and contain a list of space separated options each of which is preceded # by a minus sign. # THE FOLLOWING WHILE LOOP SIMPLY ORGANIZES THE VALID FLAGS INTO # FOUR LISTS THAT CORRESPOND TO THE FOUR FLAG TYPES LISTED ABOVE # AND A FIFTH LIST THAT INCLUDES ALL VALID FLAGS. X=${_OPT_STR} [[ $X == '-' ]] && X="" while [[ -n ${X} ]] do # GET THE NEXT LETTER OF THE OPTION STRING Y=${X#?} OPT=${X%"$Y"} X=${Y} # CHECK FOR AND PROCESS MUTALLY REQUIRED OR MUTUALLY EXCLUSIVE FLAGS case $OPT in '(') # STARTS A GROUP OF MUTUALLY REQUIRED FLAGS if [[ -n $MUTREQ ]] then print '$_CMD: _getopts: Invlid format for $_OPT_STR' print '$_CMD: _getopts: Unexpected character "("' return 1 fi MUTREQ=Y continue ;; ')') # ENDS A GROUP OF MUTUALLY REQUIRED FLAGS if [[ -z $MUTREQ ]] then print '$_CMD: _getopts: Invlid format for $_OPT_STR' print '$_CMD: _getopts: Unexpected character ")"' return 1 fi MUTREQ="" MUTREQ_FLAGS=$MUTREQ_FLAGS" " continue ;; '[') # STARTS A GROUP OF MUTUALLY EXCLUSIVE FLAGS if [[ -n $MUTEX ]] then print '$_CMD: _getopts: Invlid format for $_OPT_STR' print '$_CMD: _getopts: Unexpected character "["' return 1 fi MUTEX=Y continue ;; ']') # ENDS A GROUP OF MUTUALLY EXCLUSIVE FLAGS if [[ -z $MUTEX ]] then print '$_CMD: _getopts: Invlid format for $_OPT_STR' print '$_CMD: _getopts: Unexpected character "]"' return 1 fi MUTEX="" MUTEX_FLAGS=$MUTEX_FLAGS" " continue ;; esac # KEEP A LIST OF MUTUALLY EXCLUSIVE FLAGS if [[ -n $MUTEX && $MUTEX_FLAGS != *${OPT}* ]]; then MUTEX_FLAGS=${MUTEX_FLAGS}${OPT} fi # KEEP A LIST OF MUTUALLY REQUIRED FLAGS if [[ -n $MUTREQ && $MUTREQ_FLAGS != *${OPT}* ]]; then MUTREQ_FLAGS=${MUTREQ_FLAGS}${OPT} fi # KEEP A LIST OF ALL VALID FLAGS _VALID_FLGS="${_VALID_FLGS} -$OPT" # DETERMINE THE FLAG TYPE AS DESCRIBED ABOVE # ADD THE FLAG TO THE APPROPRIATE LIST AND # STRIP OFF THE FLAG TYPE IDENTIFIER FROM # THE OPTION STRING '${_OPT_STR}'. case $X in '.'*) # OPTIONAL MULTI-BYTE FLAG X=${X#.} _OF_MB="${_OF_MB} -$OPT" ;; ','*) # MANDATORY MULTI-BYTE FLAG X=${X#,} _MF_MB="${_MF_MB} -$OPT" ;; ':'*) # OPTIONAL FLAG THAT REQUIRES AN ARGUMENT X=${X#:} _OF_WA="${_OF_WA} -$OPT" ;; '^'*) # MANDATORY FLAG THAT REQUIRES AN ARGUMENT X=${X#^} _MF_WA="${_MF_WA} -$OPT" ;; '!'*) # MANDATORY FLAG X=${X#!} _MF_NA="${_MF_NA} -$OPT" ;; '?'*) # OPTIONAL FLAG X=${X#?} _OF_NA="${_OF_NA} -$OPT" ;; *) # OPTIONAL FLAG _OF_NA="${_OF_NA} -$OPT" ;; esac done # End of the option "while" loop # TACK A SPACE ONTO THE END OF EACH LIST TO MAKE OPTION GREPPING SIMPLE _VALID_FLGS=$_VALID_FLGS" " _OF_NA=$_OF_NA" " ; _OF_WA=$_OF_WA" " ; _OF_MB=$_OF_MB" " _MF_NA=$_MF_NA" " ; _MF_WA=$_MF_WA" " ; _MF_MB=$_MF_MB" " if [[ -n $_DEBUG ]] && (( $_DEBUG >= 3 )) then print "DEBUG(3): _OF_NA=$_OF_NA" print "DEBUG(3): _MF_NA=$_MF_NA" print "DEBUG(3): _OF_WA=$_OF_WA" print "DEBUG(3): _MF_WA=$_MF_WA" print "DEBUG(3): _OF_MB=$_OF_MB" print "DEBUG(3): _MF_MB=$_MF_MB" print "DEBUG(3): _VALID_FLGS=$_VALID_FLGS" fi # PARSE THE COMMAND LINE ARGS let _NUM_CMD_ARGS=0 while [[ -n $* ]] do THIS_FLAG=$1 THIS_ARG=${THIS_FLAG#??} THIS_FLAG=${THIS_FLAG%"$THIS_ARG"} if [[ -n $_DEBUG ]] then print "THIS_FLAG=\"$THIS_FLAG\"" print "THIS_ARG=\"$THIS_ARG\"" fi if [[ $1 == '-cspoc' ]] then # : Check for and process any CSPOC flags # _CSPOC_OPTS=$2 if [[ -z $_CSPOC_OPTS || $_CSPOC_OPTS == *([[:space:]]) ]] then SHIFT=1 else SHIFT=2 while getopts ':fd#n:?g:q' _CSPOC_OPTION $_CSPOC_OPTS do case $_CSPOC_OPTION in f ) : Force option export _SPOC_FORCE=Y ;; d ) : Debug level export _DEBUG=$OPTARG ;; n ) : Target node list export _NODE_LIST=$(print $OPTARG | sed -e"s/['\"]//g") ;; g ) : Target resource group export _RES_GRP=$(print $OPTARG | sed -e"s/['\"]//g") ;; q ) : Suppress output to stdout export _CSPOC_QUIET=YES ;; : ) : Missing operand - ignored ;; * ) : Invalid flag specified nls_msg -2 -l ${cspoc_tmp_log} 4 13 \ "%s: Invalid C-SPOC flag [%s] specified.\n" \ "$_CMD" "$_CSPOC_OPTION" print "$_USAGE" exit 2 ;; esac done fi # : Validate required and mutually exclusive CSPOC operands # if [[ $_GOPT == "no" && -n $_RES_GRP ]] then # : Is "-g" allowed # nls_msg -2 -l ${cspoc_tmp_log} 4 60 \ "%s: C-SPOC -g flag is not allowed for this command.\n" \ "$_CMD" print "$_USAGE" return 2 elif [[ $_NOPT == "no" && -n $_NODE_LIST ]] then # : Is "-n" allowed # nls_msg -2 -l ${cspoc_tmp_log} 4 61 \ "%s: C-SPOC -n flag is not allowed for this command.\n" \ "$_CMD" print "$_USAGE" return 2 elif [[ $_GOPT == "req" && $_NOPT == "req" ]] && \ [[ -z $_RES_GRP && -z $_NODE_LIST ]] then # : Check for "-g" or "-n" present when one : or the other is required # nls_msg -2 -l ${cspoc_tmp_log} 4 62 \ "%s: Either the '-g' or the '-n' C-SPOC flag must be specified.\n" "$_CMD" print "$_USAGE" return 2 elif [[ -n $_RES_GRP && -n $_NODE_LIST ]] then # : Check that both "-g" and "-n" are not specified together # nls_msg -2 -l ${cspoc_tmp_log} 4 63 \ "%s: C-SPOC -g and -n flags are mutually exclusive.\n" \ "$_CMD" print "$_USAGE" return 2 elif [[ $_NOPT != "req" && $_GOPT == "req" && -z $_RES_GRP ]] then # : Is only "-g" allowed # nls_msg -2 -l ${cspoc_tmp_log} 4 64 \ "%s: C-SPOC -g flag is required.\n" "$_CMD" print "$_USAGE" return 2 elif [[ $_GOPT != "req" && $_NOPT == "req" && -z $_NODE_LIST ]] then # : Is only "-n" required # nls_msg -2 -l ${cspoc_tmp_log} 4 65 \ "%s: C-SPOC -n flag is required.\n" "$_CMD" print "$_USAGE" return 2 fi shift $SHIFT elif [[ "$THIS_FLAG" != -* ]] then # AIX COMMAND ARGUMENT THAT IS NOT AN OPTION FLAG # NEED TO ACCOMODATE OPTIONS THAT MAY OR MAY NOT HAVE AN ARGUMENT. # IF OPT_ARG DOESN'T START WITH A '-' ITS AN ARGUMENT OTHERWISE # CONSIDER IT TO BE THE NEXT OPTION let _NUM_CMD_ARGS=$_NUM_CMD_ARGS+$# TMP_FLAG="" while (( $# > 0 )) do case "$1" in -*) TMP_FLAG=$(echo $1 | cut -c1-2) _CMD_ARGS=${_CMD_ARGS:+"${_CMD_ARGS} "}"$TMP_FLAG" TMP_ARG1=$(echo $1 | cut -c3-) if [[ -n $TMP_ARG1 ]] then TMP_ARG1="$(print -- $TMP_ARG1 |\ clencodearg $_ENCODE_ARGS)" _CMD_ARGS=${_CMD_ARGS:+"${_CMD_ARGS} "}"$TMP_ARG1" TMP_FLAG="" fi ;; *) TMP_ARG2="$(print -- $1 | clencodearg $_ENCODE_ARGS)" _CMD_ARGS=${_CMD_ARGS:+"${_CMD_ARGS} "}${TMP_ARG2} if [[ -z $TMP_FLAG ]] then _NON_FLG_ARGS=${_NON_FLG_ARGS:+"${_NON_FLG_ARGS} "}"${TMP_ARG2}" fi TMP_FLAG="" esac shift done break else # COME INTO HERE WITH $THIS_FLAG and $THIS_ARG SET ARG_CHECK=Y ARG_NEXT="" while [[ -n $ARG_CHECK ]] do # NOW CHECK IF WE STILL HAVE MORE FLAGS TO PROCESS [[ -z $THIS_ARG ]] && ARG_CHECK="" if print -- "$_OF_MB $_MF_MB" | grep -- "$THIS_FLAG" > /dev/null then # THIS IS A MULTI-BYTE FLAG if [[ -z $THIS_ARG ]] then ( print -- "$_OF_NA $_MF_NA" | grep -- "$THIS_FLAG" > /dev/null ) || \ { # THIS FLAG REQUIRES AN ARGUMENT nls_msg -2 -l ${cspoc_tmp_log} 4 19 \ "%s: Invalid option [%s].\n" "$_CMD" "$1" print "$_USAGE" exit 2 } fi # VALID AIX COMMAND MULTI-BYTE OPTION (WITHOUT AN ARGUMENT) _CMD_ARGS=${_CMD_ARGS:+"${_CMD_ARGS} "}"$THIS_FLAG$THIS_ARG" shift ARG_CHECK="" # Disable further processing of $THIS_ARG as flags elif print -- "$_OF_WA $_MF_WA" | grep -- "$THIS_FLAG" > /dev/null then # THIS IS A FLAG THAT REQUIRES AN ARGUMWENT # HANDLE OPTIONAL SPACE BETWEEN FLAG AND ITS ARG if [[ -z $THIS_ARG && -z $ARG_NEXT ]] then THIS_ARG=$2 # THERE WAS A SPACE SHIFT=2 else SHIFT=1 # THERE WAS NO SPACE fi # NOW VALIDATE THAT WE HAVE AN ARG AND THAT IT IS VALID if [[ -z $THIS_ARG || $THIS_ARG == -* ]] then # IF THERE IS NO ARG THEN CHECK IF FLAG MAY BE SPECFIED WITHOUT ONE print -- "$_OF_NA $_MF_NA" | grep -q -- "$THIS_FLAG" ||\ { # THIS FLAG REQUIRES AN ARGUMENT nls_msg -2 -l ${cspoc_tmp_log} 4 19 \ "%s: Option [%s] requires an argument.\n" "$_CMD" "$1" print "$_USAGE" exit 2 } fi # VALID AIX COMMAND OPTION WITH AN ARGUMENT _CMD_ARGS=${_CMD_ARGS:+"${_CMD_ARGS} "}"$THIS_FLAG $(print -- $THIS_ARG | clencodearg $_ENCODE_ARGS)" shift $SHIFT # Disable further processing of $THIS_ARG as flags ARG_CHECK="" elif print -- "$_OF_NA $_MF_NA" | grep -q -- "$THIS_FLAG" then # THIS IS A FLAG THAT DOES NOT TAKE AN ARGUMENT _CMD_ARGS=${_CMD_ARGS:+"${_CMD_ARGS} "}"$THIS_FLAG" # IF THIS FLAG WAS OBTAINED FROM $THIS_FLAG THEN WE WANT TO # SHIFT. IF IT WAS OBTAINED FROM $THIS_ARG THEN WE DONT [[ -z $ARG_CHECK ]] && shift # THIS FLAG DOES NOT TAKE AN OPTION ARGUMENT SO ASSUME # THAT "$THIS_ARG" SPECIFIES MORE FLAGS TO PROCESS. if [[ -n $THIS_ARG ]] then # GET THE NEXT FLAG, ADJUST $THIS_ARG, # AND KEEP PROCESSING. X=${THIS_ARG#?} THIS_FLAG="-${THIS_ARG%$X}" THIS_ARG=$X ARG_NEXT=Y fi else nls_msg -2 -l ${cspoc_tmp_log} 4 26 \ "%s: Invalid option [%s].\n" "$_CMD" "$1" print "$_USAGE" exit 2 fi done fi done ## # PERFORM CHECKING OF THE AIX COMMAND FLAGS ## # CHECK FOR REQUIRED NUMBER OF NON-FLAG ARGUMENTS if (( ${_NUM_CMD_ARGS:-0} < ${_NUM_ARGS_REQ:-0} )) then nls_msg -2 -l ${cspoc_tmp_log} 4 27 \ "%s: Missing command line arguments.\n" "$_CMD" print "$_USAGE" return 2 fi # THIS IS WHERE WE CHECK FOR MANDATORY FLAGS, MUTUALLY EXCLUSIVE FLAGS, # AND MUTUALLY REQUIRED FLAGS # CHECK FOR MUTUALLY REQUIRED FLAGS # FOR EACH GROUP OF FLAGS SPECIFIED IN $MUTREQ_FLAGS WE WILL COUNT HOW # MANY WE NEED AND HOW MANY ARE GIVEN ON CMD LINE. IF THESE VALUES ARE # NOT EQUAL PRINT AN ERROR AND RETURN NON-ZERO typeset -i CNT=0 N=0 for GROUP in $MUTREQ_FLAGS do # GET A COUNT OF HOW MANY FLAGS IN THIS GROUP print -n $GROUP | wc -c | read N integer CNT=0 F="" while [[ -n $GROUP ]] do # GET THE NEXT FLAG IN THE GROUP A=${GROUP#?} B=${GROUP%"$A"} GROUP=$A # IF THIS FLAG IS USED INCREMENT THE COUNTER if [[ "$(print -- $_CMD_ARGS | grep -- '-'${B})"' ' != ' ' ]] then (( CNT = CNT + 1 )) fi F=${F:+"$F, "}"-"$B done # VERIFY THAT THE COUNTER EQUALS THE TOTAL NUMBER OF FLAGS IN THE GROUP if (( $CNT != $N )) then print "$_CMD: One or more flags [$F] were not specified." print "$_CMD: Specifying any one of these flags requires the others." return 2 fi done # CHECK FOR MUTUALLY EXCLUSIVE FLAGS # FOR EACH GROUP OF FLAGS SPECIFIED IN $MUTEX_FLAGS WE WILL COUNT HOW # MANY ARE GIVEN ON CMD LINE. IF MORE THAN ONE IS GIVEN THEN PRINT # AN ERROR AND RETURN NON-ZERO for GROUP in $MUTEX_FLAGS do # GET A COUNT OF HOW MANY FLAGS IN THIS GROUP integer CNT=0 F="" while [[ -n $GROUP ]] do # GET THE NEXT FLAG IN THE GROUP A=${GROUP#?} B=${GROUP%"$A"} GROUP=$A # IF THIS FLAG IS USED INCREMENT THE COUNTER if [[ -n "$(print -- $_CMD_ARGS | grep -- '-'${B})" ]] then (( CNT = CNT + 1 )) fi F=${F:+"$F, "}"-"$B done # VERIFY THAT THE COUNTER EQUALS THE TOTAL NUMBER OF FLAGS IN THE GROUP if (( $CNT > 1 )) then print "$_CMD: The flags [$F] are mutually exclusive." print "$_CMD: Only one of these flags may be specified." return 2 fi done # CHECK FOR ALL MANDATORY FLAGS for X in $_MF_NA $_MF_WA do # CHECK THAT MANDATORY FLAG IS ON COMMAND LINE if [[ -z "$(print -- $_CMD_ARGS | grep -- ${X})" ]] then # THE FLAG WAS NOT SPECIFIED SO WE MUST FIRST CHECK IF ANOTHER # FLAG WAS SPECIFIED THAT IS MUTUALLY EXCLUSIVE WITH THIS ONE. for GROUP in $MUTEX_FLAGS do OK="" while [[ -n $GROUP ]] do Y=${GROUP#?} Z=${GROUP%"$Y"} GROUP=$Y print -- " $_CMD_ARGS " |\ grep -- "-${Z} " > /dev/null && OK=Y done [[ -n $OK ]] && break done # "$OK" IS NULL IF NO FLAG IN THIS MUTEX GROUP WAS GIVEN if [[ -z $OK ]] then nls_msg -2 -l ${cspoc_tmp_log} 4 29 \ "%s: Mandatory option [%s] not specified.\n" "$_CMD" "$X" print "$_USAGE" return 2 fi fi done if [[ -n $_DEBUG ]] && (( $_DEBUG >= 3 )) then print -- "DEBUG(3): _CMD_ARGS=$_CMD_ARGS" fi return 0 } # End of "_getopts()" ################################################################################ # # DESCRIPTION: # Updates the C-SPOC logfile # ################################################################################ function cexit { if [[ -n $_DEBUG ]] then print "DEBUG: Entering cexit version 1.16.7.9" if (( $_DEBUG >= 8 )) then typeset PROGNAME=cexit set -x fi fi typeset USAGE="USAGE: cexit " # CHECK USAGE (( $# != 2 )) && print "$_CMD: $USAGE" typeset TEMP_LOG=$1 typeset RC=$2 # : Read the HACMPlogs ODM for the pathname of the cspoc.log log file : If the ODM is empty or corrupted, use /var/hacmp/log/cspoc.log # DESTDIR=$(clodmget -q "name = cspoc.log" -f value -n HACMPlogs) if [[ -n $DESTDIR ]] then CSPOC_LOG="$DESTDIR/cspoc.log" else dspmsg scripts.cat 463 "The cluster log entry for %s could not be found in the HACMPlogs ODM.\n" "cspoc.log" dspmsg scripts.cat 464 "Defaulting to log directory %s for log file %s.\n" "/var/hacmp/log" "cspoc.log" CSPOC_LOG="/var/hacmp/log/cspoc.log" fi # : CHECK ARGS # if [[ ! -f ${TEMP_LOG} ]] then nls_msg -2 -l ${CSPOC_LOG} 4 39 \ "%s: Unable to open file: %s\n" "${TEMP_LOG}" "$_CMD" return 1 fi # : If the log file does not exist, create it. # if [[ ! -f ${CSPOC_LOG} ]]; then touch ${CSPOC_LOG} fi # : Keep the information in the log file if we have write permission # if [[ -w $CSPOC_LOG ]] then cat ${TEMP_LOG} >> $CSPOC_LOG fi if (( $RC == 0 )) && ( [[ -z $_DEBUG ]] || (( $_DEBUG <= 8 )) ) then rm -f ${TEMP_LOG%_*}* rm -f /tmp/cel$$_s*.err rm -f /tmp/cel$$_s*.out rm -f /tmp/cel$$.cache fi } # End of "cexit()" ################################################################################ # # _cspoc_verify - Performs verification of a number of CSPOC requirments. # Certain requirements, if not met, produce a hard error # and the routine produces an immediate exit of the script. # Other requirements, if not met, produce soft errors that # result in the routine returning a value of '1'. The # calling script will then exit unless the CSPOC force flag # has been set. # ################################################################################ function _cspoc_verify { if [[ -n $_DEBUG ]] then print "DEBUG: Entering _cspoc_verify version 1.16.7.9 + 20527,842,758" if (( $_DEBUG >= 8 )) then typeset PROGNAME="_cspoc_verify" set -x fi fi typeset NODE typeset bad_targets # space separated list of unreachable nodes typeset CAA_down_nodes # target hosts CAA says are down typeset CAA_node_name # CAA host node name integer _RETCODE=0 # Assume OK until proven otherwise typeset BADNODES # Space separated list of invalid nodes typeset down_ha_nodes # target HA nodes CAA says are down typeset good_targets # target HA nodes that should work typeset bad_level_nodes # target HA nodes below minimum release level if [[ $_CSPOC_CALLED_FROM_SMIT != 'true' ]] then # : If not called from SMIT, which will surely set things : up correctly, check to make sure target nodes are valid. # for NODE in $(IFS=, set -- $_TARGET_NODES ; print $*) do # : Collect a list of given nodes that do not : show up in the local cluster definition. # if [[ $_CLUSTER_NODES != @(?(*,)$NODE?(,*)) ]] then BADNODES=${BADNODES:+$BADNODES" "}$NODE nls_msg -2 -l ${cspoc_tmp_log} 4 44 \ "%s: The node [%s] is not a part of this cluster.\n" "$_CMD" "$NODE" fi done if [[ -n $BADNODES ]] then # : Remove any invalid node names from the node list # save_targets="" for ha_node in $(IFS=, set -- $_TARGET_NODES ; print $*) do if [[ $BADNODES != @(?(* )${ha_node}?( *)) ]] then save_targets=${save_targets:+"${save_targets},"}${ha_node} fi done _TARGET_NODES=$save_targets if [[ -z $_TARGET_NODES ]] then nls_msg -2 -l ${cspoc_tmp_log} 4 9999 \ "%s[%d]: The command will not be run because all of the target nodes, %s, are not part of this cluster\n" "$_CMD" $LINENO "$BADNODES" exit 1 # No valid nodes found else _RETCODE=1 # Continue if 'forced' specified fi fi fi cluster_version=$(clodmget -f cluster_version -n HACMPcluster) if [[ -x /usr/lib/cluster/incluster ]] && /usr/lib/cluster/incluster || \ (( $cluster_version >= 15 )) then # : If at a level where CAA is in place, check to see if : CAA can provide information on the state of nodes. # LC_ALL=C lscluster -m 2>/dev/null | \ egrep 'Node name:|State of node:' | \ cut -f2 -d: | \ paste -d' ' - - | \ while read CAA_node_name state do if [[ -n $CAA_node_name ]] then if [[ $state != 'UP' && \ $state != @(?(* )NODE_LOCAL?( *)) && \ $state != @(?(* )REACHABLE THROUGH REPOS DISK ONLY?( *)) && \ $state != 'DOWN STOPPED' ]] then # # The purpose of this check is to avoid long timeouts # trying to talk to a node known to be dead. # - The local node is always reachable # - A stopped node may be reachable; halevel checks below # - A node reachable only through the repository disk # may be reachable: just because CAA declares the # network to be down doesn't mean clcomd can't get # through; hlevel checks below # : Node $CAA_node_name is 'DOWN' # CAA_down_nodes=${CAA_down_nodes:+"${CAA_down_nodes} "}${CAA_node_name} # : Find the PowerHA node name corresponding to the : $CAA_node_name - the name must be a label on an : interface on some node. # host_ip=$(LC_ALL=C host $CAA_node_name | cut -f3 -d' ') host_ip=${host_ip%,} if [[ -n $host_ip && $host_ip == @(+([0-9.])|+([0-9:])) ]] then down_ha_node=$(clodmget -q "identifier = ${host_ip}" -f nodename -n HACMPadapter) if [[ -n $down_ha_node ]] then down_ha_nodes=${down_ha_nodes:+"$down_ha_nodes "}${down_ha_node} nls_msg -2 -l ${cspoc_tmp_log} 4 9999 \ "%s[%d]: The CAA lscluster command indicates that node %s[%s] is \"%s\" and not active.\n" "$_CMD" $LINENO $down_ha_node $CAA_node_name "$state" fi fi fi fi done fi if [[ -n $down_ha_nodes ]] then # : CAA says that nodes $down_ha_nodes are not active : Construct a list of the remaining nodes, to use to : check to see if clcomd is running. # for ha_node in $(IFS=, set -- $_TARGET_NODES ; echo $* ) do if [[ $down_ha_nodes != @(?(* )${ha_node}?( *)) ]] then good_targets=${good_targets:+"${good_targets} "}${ha_node} fi done else # : CAA gives no reason to suspect nodes are not reachable # good_targets=$(IFS=, set -- $_TARGET_NODES ; echo $* ) fi # : CAA has not ruled out talking to node $good_targets # if [[ -n $_SPOC_FORCE ]] && /usr/lib/cluster/incluster then # : It is possible that the target node list contains names : that do not correspond to CAA host names after the CAA : cluster is created. # Before the CAA cluster is created, all target nodes are # naturally not in a CAA cluster. Ordinarily, this can be # left to clhaver to find, though it does not distinguish # between nodes it cannot connect to, and nodes that are # that are not in the CAA cluster. If the force flag was # specified, and we are already in a CAA cluster, : Silently elide names in the target list that do not : correspond to CAA host names. # save_targets=$good_targets good_targets="" for given_node in $save_targets do if cl_query_hn_id -q -i $given_node >/dev/null 2>&1 then good_targets=${good_targets:+"${good_targets} "}${given_node} else print "$(date) ${_CMD}._cspoc_verify[$LINENO]: Given target \"$given_node\" cannot be converted to a CAA host name. It will be skipped." >> $clutilslog fi done fi if [[ -n $good_targets ]] then # : CAA thinks that nodes \"$good_targets\" : are active. See if clcomd can talk to them, : and what level of PowerHA is present. # clhaver -c $_VER $good_targets | \ while IFS=: read ha_node caa_host VRMF do if [[ -z $caa_host ]] then # : Add $ha_node, which clhaver cannot communicate to : through clcomd, to the list of nodes not to try : to run the command on. # down_ha_nodes=${down_ha_nodes:+"${down_ha_nodes} "}${ha_node} elif (( $VRMF < $_VER )) then # : Add $ha_node to the list of nodes below the minimum : HA release level. # bad_level_nodes=${bad_level_nodes:+"${bad_level_nodes} "}${ha_node} fi done if [[ -n $bad_level_nodes ]] then # : Nodes \"$bad_level_nodes\" report that they are running a : version of PowerHA below the required level $_VERSION # if [[ -z $_SPOC_FORCE ]] then nls_msg -2 -l ${cspoc_tmp_log} 4 9999 \ "%s[%d]: The command will not be run because the following nodes are below the required level %s: %s\n" "$_CMD" $LINENO $_VERSION "$bad_level_nodes" elif [[ $bad_level_nodes == $good_targets ]] then nls_msg -2 -l ${cspoc_tmp_log} 4 9999 \ "%s[%d]: The command will not be run because all nodes are below the required level %s: %s\n" "$_CMD" $LINENO $_VERSION "$bad_level_nodes" else # : If force was specified, command processing continues : but skips nodes \"$bad_level_nodes\" # nls_msg -2 -l ${cspoc_tmp_log} 4 9999 \ "%s[%d]: The command will be run, but not on the following nodes, which are below the required level %s: %s\n" "$_CMD" $LINENO $_VERSION "$bad_level_nodes" fi down_ha_nodes=${down_ha_nodes:+"${down_ha_nodes} "}${bad_level_nodes} _RETCODE=1 fi fi if [[ -n $down_ha_nodes ]] then # : The nodes in \$down_ha_nodes, \"$down_ha_nodes\", are not acceptable : targets for this command, either because CAA says they are down, : or clcomd cannot talk to them, or they are running too far a back : level of PowerHA. Remove them from the list of C-SPOC target nodes. # save_targets="" for ha_node in $good_targets do if [[ $down_ha_nodes != @(?(* )${ha_node}?( *)) ]] then save_targets=${save_targets:+"${save_targets} "}${ha_node} fi done good_targets=$save_targets bad_targets=$(IFS=, set -- $down_ha_nodes ; print "$*" ) if [[ -z $good_targets ]] then nls_msg -2 -l ${cspoc_tmp_log} 4 9999 \ "%s[%d]: The command will not be run because all of the target nodes, %s, are not reachable\n" "$_CMD" $LINENO "$bad_targets" exit 1 elif [[ -n $bad_targets ]] then if [[ -z $_SPOC_FORCE ]] then if [[ $bad_targets == @(*,*) ]] then nls_msg -2 -l ${cspoc_tmp_log} 4 9999 \ "%s[%d]: The command will not be run because the target nodes, %s, are not reachable\n" "$_CMD" $LINENO "$bad_targets" else nls_msg -2 -l ${cspoc_tmp_log} 4 9999 \ "%s[%d]: The command will not be run because the target node, %s, is not reachable\n" "$_CMD" $LINENO "$bad_targets" fi _RETCODE=1 else if [[ $bad_targets == @(*,*) ]] then nls_msg -2 -l ${cspoc_tmp_log} 4 9999 \ "%s[%d]: The command will be run, but not on the unreachable nodes %s\n" "$_CMD" $LINENO "$bad_targets" else nls_msg -2 -l ${cspoc_tmp_log} 4 9999 \ "%s[%d]: The command will be run, but not on the unreachable node %s\n" "$_CMD" $LINENO "$bad_targets" fi fi fi fi _TARGET_NODES=$(IFS=, set -- $good_targets ; print "$*" ) # : \$_TARGET_NODES, \"$_TARGET_NODES\", is a list of nodes that are : up, contactable by clcomd, and running a reasonably up to date : level of PowerHA. # return $_RETCODE } # End of "_cspoc_verify()" ################################################################################ # # Start of main, Main, MAIN # ################################################################################ if [[ -n $_DEBUG ]] then print "\n[C-SPOC Initialization Started version 1.16.7.9" fi _VER=${_VER:-"6100"} _VERSION=${_VERSION:-"6.1.0.0"} export CLUSTER_OVERRIDE="yes" # Allow CAAC commands to run... 710 _CMD=${0##*/} integer TRY_RC=0 # : since root is needed to determine node lists and what not - clgetaddr : we may as well disable everything right here right now. By putting : in an explicit check we can provide a more intuitive message rather : than something about not being able to execute some command later on. # if [[ $(whoami) != "root" ]] && ! ckauth PowerHASM.admin then nls_msg -2 -l ${cspoc_tmp_log} 4 52 \ "%s: All C-SPOC commands require the user to either be root, or have PowerHASM.admin authorization\n" "$_CMD" exit 2 fi # : Set a default value, unless this script is called from SMIT, in which : case _CSPOC_MODE will already be defined. By default, this should determine : what the request mode type. # export _CSPOC_MODE=${_CSPOC_MODE:-"both"} # : By default, assume that we are being called from the command line # export _CSPOC_CALLED_FROM_SMIT=${_CSPOC_CALLED_FROM_SMIT:-"false"} # : Make sure that the _CMD_ARGS variable is visible everywhere # export _CMD_ARGS="" [[ -n $_DEBUG ]] && print "\n[Parsing Command Line Options ... ]" # : Tell clencodearg to skip the special escape processing for '=' # if [[ $SKIP_EQ_ESC == true ]] then export _ENCODE_ARGS="-e" else export _ENCODE_ARGS="" fi _CSPOC_OPT_STR=${_CSPOC_OPT_STR:--} _OPT_STR=${_OPT_STR:--} _getopts "$_CSPOC_OPT_STR" "$_OPT_STR" "$@" || exit 1 if [[ -n $_DEBUG ]] then print "_CMD_ARGS=${_CMD_ARGS}" print "_NUM_CMD_ARGS=${_NUM_CMD_ARGS}" print "_NON_FLG_ARGS=${_NON_FLG_ARGS}" print "\n[Getting Cluster Node List ... ]" fi # : Determine the nodes in the cluster, and the nodes to which this operation : aplies. # export ODMDIR=/etc/objrepos _get_node_list || exit 1 _get_target_nodes || exit 1 if [[ -n $_DEBUG ]] then print "_CLUSTER_NODES=${_CLUSTER_NODES}" print "\n[Verifying C-SPOC Requirements ... ]" fi if [[ -z $clutilslog ]] then clutilslog=$(clodmget -q 'name = clutils.log' -f value -n HACMPlogs)"/clutils.log" fi # : If not all nodes are reachable, stop now, unless the "force" flag was : specified, implying continue despite unreachable nodes # _cspoc_verify || { [[ -z $_SPOC_FORCE ]] && exit 1 } if [[ -n $_DEBUG ]] then print "\n[C-SPOC Initialization Completed.]" print "DEBUG: Entering ${0##*/}" (( $_DEBUG >= 8 )) && set -x fi # : Parse operands # NewName="" PVID="" while getopts ":N:Y:" opt $_CMD_ARGS do case $opt in N ) : New disk name ; NewName=$OPTARG ;; Y ) : PVID ; PVID=$OPTARG ;; * ) print $_USAGE return -1 ;; esac done Old_disk=$_NON_FLG_ARGS DOld_disk=$(print $Old_disk | cldecodearg) DNewName=$(print $NewName | cldecodearg) # : The disk must be renamed at least on the nodes given in the : node list. However, if the user specified that all instances : of this PVID are to be renamed, then if the disk has a different : name on some node, it must be renamed there, too. So, if that : option was selected, find out what extra nodes the rename must : be done on. # Disk_nodes="" if [[ -n $PVID ]] then D_PVID=$(print $PVID | cldecodearg) ECMD=$(print -- "lspv | grep -w " | clencodearg -e) ECMD="${ECMD}${PVID}" Disk_names="" for Cluster_node in $(IFS=, set -- $_CLUSTER_NODES ; print $*) do if [[ $_TARGET_NODES != @(?(*,)$Cluster_node?(,*)) ]] then cel_f4 fi done fi # : Get a comma separated list of the nodes on which the new : disk name will appear, so we can check for a collision # Check_nodes=$_TARGET_NODES if [[ -n $Disk_nodes ]] then Check_nodes="${Check_nodes},${Disk_nodes}" fi # : Check to make sure that the new disk name is not in use : and that the rename disk function is available # if ! name_use_check $DOld_disk $DNewName || ! can_rendev $DOld_disk $DNewName then return 1 fi # : Rename the disk on the list of nodes specified on : the command # rename_cmd="$(print -- 'rendev -l '${DOld_disk}' -n ' | clencodearg -e )${NewName}" try_rc=0 cel_f5 if (( $try_rc != 0 )) then return $try_rc fi if [[ -n $Disk_nodes ]] then # : Also need to rename the disk on other nodes, where : it is not currently named $DOld_name # for disk_node in $(IFS=, set -- $Disk_nodes ; print $*) do # : Construct the appropriate rename command for $disk_node : using the list of the current value of the disk name # print $Disk_names | IFS=, read disk_name Disk_names rename_cmd="$(print -- 'rendev -l $disk_name -n ' | clencodearg -e )${NewName}" cel_f6 done fi if (( $try_rc == 0 )) then # : Success message on completion of rename on all appropriate nodes # dspmsg -s $_MSET cspoc.cat 83 "cl_rendisk: Physical volume $DOld_disk renamed to $DNewName on $Check_nodes\n" $DOld_disk $DNewName $Check_nodes fi