#!/bin/ksh93 # ALTRAN_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # Copyright (C) Altran ACT S.A.S. 2017,2018,2019,2020,2021. All rights reserved. # # ALTRAN_PROLOG_END_TAG # # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # 61haes_r714 src/43haes/lib/ksh93/hacmp/KLIB_HACMP_modify_mirror_pool.sh 1.7 # # Licensed Materials - Property of IBM # # Restricted Materials of IBM # # COPYRIGHT International Business Machines Corp. 2012,2013 # 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/lib/ksh93/hacmp/KLIB_HACMP_modify_mirror_pool.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM #============================================================================ # # Name: KLIB_HACMP_modify_mirror_pool # # Description: This is the main, FPATH function that is invoked by clmgr # to modify mirror pools in the cluster configuration. # # Inputs: See the "devDoc()" function, below. # # Outputs: The properties hash is populated. The only other outputs are # any error messages that might be needed. # # Returns: Zero if no errors are detected. Otherwise, an appropriate # non-zero value is returned. Refer to the "RETURN" section # of the "devDoc()" function, below, for the standard return # code values/meanings for clmgr. # #============================================================================ function KLIB_HACMP_modify_mirror_pool { . $HALIBROOT/log_entry "$0()" "$CL" : version=@(#) 7d4c34b 43haes/lib/ksh93/hacmp/KLIB_HACMP_modify_mirror_pool.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM : INPUTS: $* typeset -n properties=$1 typeset mirror_pool=${2//\"/} typeset volume_group=${3//\"/} typeset newname=${4//\"/} typeset storageloc=${5//\"/} typeset -l mode=${6//\"/} typeset -l force_sync=${7//\"/} typeset async_cache_lv=${8//\"/} typeset async_cache_hw_mark=${9//\"/} typeset disks_to_add=${10//\"/} disks_to_add=${disks_to_add//+([[:space:]])/,} typeset disks_to_remove=${11//\"/} disks_to_remove=${disks_to_remove//,/ } [[ $CLMGR_LOGGING == 'med' ]] && set +x # Only trace param values #================================================================ : Check for a defined cluster. No need to continue without one. #================================================================ CL=$LINENO isClusterDefined if (( $? != RC_SUCCESS )); then log_return_msg "$RC_MISSING_DEPENDENCY" "$0()" "$LINENO" return $? fi #=================================== : Declare and initialize variables #=================================== typeset -i rc=$RC_UNKNOWN typeset -i i=0 #================= : Validate input #================= if [[ -z $mirror_pool ]] then typeset CLASS=$(print -- $CLMGR_COMMAND | awk '{print $5}') cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1405 '\nERROR: missing the object name for class "%1$s".\n' "$CLASS" 1>&2 : Show them where the error is to add clarity typeset CMD=${CLMGR_COMMAND/ -T $CLMGR_TRANSACTION_ID/} CMD=${CMD/$CLASS/$CLASS \{\{??????\}\}} # Add placeholder to show where the data is missing print -u2 -n -- "$TAB$CMD\n$TAB" # Display the indented command integer I=0 for (( ; I<${#CMD}; I++ )) do if [[ ${CMD:$I:1} == '{' ]] then : Found the placeholder. Now under line it for emphasis. print -u2 "^^^^^^^^^^\n" break # Done. We can stop looping now. else print -n -u2 " " fi done rc=$RC_MISSING_INPUT else CL=$LINENO KLIB_HACMP_is_known_mirror_pool "$mirror_pool" "$volume_group" >/dev/null 2>&1 if (( $? != RC_SUCCESS )); then dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 '\nERROR: "%1$s" does not appear to exist!\n\n' "$mirror_pool" 1>&2 dspmsg -s $CLMGR_SET $CLMGR_MSGS 173 "Available Mirror Pools:\n\n" 1>&2 typeset available CL=$LINENO KLIB_HACMP_list_mirror_pools available for (( i=0; i<${#available[*]}; i++ )); do if [[ ${available[$i]} != *([[:space:]]) ]]; then print -u2 "\t${available[$i]}" fi done print -u2 "" rc=$RC_NOT_FOUND fi fi if (( $rc == RC_UNKNOWN )); then typeset FOUND="" integer COUNT=0 if [[ -n $volume_group ]]; then FOUND=$(CL=$LINENO KLIB_HACMP_is_known_mirror_pool "$mirror_pool" "$volume_group") else FOUND=$(CL=$LINENO KLIB_HACMP_is_known_mirror_pool "$mirror_pool") fi if [[ -n $FOUND ]]; then print -- "$FOUND" |\ while read mirror_pool volume_group; do (( COUNT++ )) done fi if (( COUNT > 1 )); then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 277 "\nERROR: more than one object matches the provided information:\n\n" 1>&2 print -u2 "$FOUND" rc=$RC_INCORRECT_INPUT elif [[ -n $FOUND ]]; then print -- "$FOUND" | read mirror_pool volume_group volume_group=${volume_group#\(} volume_group=${volume_group%\)} fi fi # : Retrieve the nodes that host the mirror pool volume group # typeset COMMPATH="" NNAME="" VGNODES="" clcmd ls /dev/$volume_group | grep -p "^/dev/" | grep -w NODE | sed 's/^NODE //g' | sort |\ while read COMMPATH do NNAME=$(clodmget -q "object=COMMUNICATION_PATH AND value=$COMMPATH" -f name -n HACMPnode) [[ -z $NNAME ]] && NNAME=${COMMPATH%%\.*} VGNODES=${VGNODES:+$VGNODES,}$NNAME done #======================================================== : Attempt to validate all provided disks, attempting to : convert them to PVID form, if needed. #======================================================== if [[ -n $disks_to_add || -n $disks_to_remove ]]; then typeset disks="$disks_to_add $disks_to_remove" typeset orig_disk="" typeset -i cmd_rc=$RC_UNKNOWN for disk in ${disks//,/ }; do [[ $disk == *([[:space:]]) ]] && continue orig_disk="$disk" # disks can be specified with a specific node using the form # @ # get the data from that node, if specified if [[ $disk == *@* ]]; then print -- "$disk" | IFS=@ read disk node if [[ " ${VGNODES//,/ } " != *\ $node\ * ]] then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1403 '\nERROR: The node specified in "%1$s" is either invalid, or not a member of volume group "%2$s".\n' "$orig_disk" "$volume_group" 1>&2 rc=$RC_INCORRECT_INPUT cmd_rc=$rc break else CL=$LINENO getDiskData "$disk" "$node" IDENTIFIERS true cmd_rc=$? fi else if [[ " ${VGNODES//,/ } " == *\ $LOCAL_NODE\ * ]]; then CL=$LINENO getDiskData "$disk" "$LOCAL_NODE" IDENTIFIERS true cmd_rc=$? fi fi if (( $cmd_rc != RC_SUCCESS )); then rc=$RC_NOT_FOUND # No such disk found break else : Convert to PVID, if needed print -- "$IDENTIFIERS" | IFS=: read devname pvid uuid refnode rest if [[ -n $disks_to_add ]] then if [[ " $disks_to_add " == *\ $devname?(\@*)\ * ]] then disks_to_add=${disks_to_add/$orig_disk/$pvid} fi fi if [[ -n $disks_to_remove ]] then if [[ " $disks_to_remove " == *\ $devname?(\@*)\ * ]] then disks_to_remove=${disks_to_remove/$orig_disk/$pvid} fi fi fi done fi if [[ -n $newname ]]; then typeset BAD_CHARS=${newname//[a-zA-Z0-9_-]/} if [[ "$BAD_CHARS" != *([[:space:]]) ]]; then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 105 '\nERROR: one or more invalid characters were detected in "%1$s" ("%2$s").\n\nValid characters include letters, numbers, and underscores only.\n\n' "$newname" "${newname//[a-zA-Z0-9_-]/}" 1>&2 # : Show the customer exactly which characters were bad # typeset CMD=${CLMGR_COMMAND/ -T $CLMGR_TRANSACTION_ID/} print -u2 -n -- "$TAB$CMD\n$TAB" # Display the indented command integer I=0 J=0 NAMELEN=${#newname} for (( ; I<${#CMD}; I++ )) do if [[ ${CMD:$I} == $newname@([[:space:]]*|) ]] then : When the object name is reached, start processing it for (( J=$I; J<$I+$NAMELEN; J++ )) do : Print an arrow under each bad character, and a space under good ones [[ ${CMD:$J:1} == [${BAD_CHARS//\^/\\^}] ]] && print -n -u2 "^" || print -n -u2 " " done break # Done. The entire object name has been processed. else print -n -u2 " " fi done print -u2 "\n" rc=$RC_INCORRECT_INPUT fi fi if [[ -n $mode ]]; then case $mode in @(a|A)*) mode=async ;; @(s|S)*) mode=sync ;; *) dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 '\nERROR: invalid value specified for "%1$s": "%2$s".\n' MODE "$mode" 1>&2 dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 'Valid valiues: %1$s\n\n' "sync, async" 1>&2 rc=$RC_INCORRECT_INPUT ;; esac fi if [[ -n $async_cache_lv ]]; then CL=$LINENO KLIB_HACMP_is_known_logical_volume $async_cache_lv if (( $? != RC_SUCCESS )); then dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 '\nERROR: "%1$s" does not appear to exist!\n\n' "$async_cache_lv" 1>&2 dspmsg -s $CLMGR_SET $CLMGR_MSGS 148 "Available Logical Volumes:\n\n" 1>&2 typeset available CL=$LINENO KLIB_HACMP_list_logical_volumes available for (( i=0; i<${#available[*]}; i++ )); do if [[ ${available[$i]} != *([[:space:]]) ]]; then print -u2 "\t${available[$i]}" fi done print -u2 "" rc=$RC_INCORRECT_INPUT fi fi if [[ -n $async_cache_hw_mark ]]; then CL=$LINENO verify_is_numeric $async_cache_hw_mark 2 # Check for positive integer (( $? != RC_SUCCESS )) && rc=$RC_INCORRECT_INPUT fi # Check if the provided storage location has spaces or commas if [[ -n $storageloc ]] && [[ $storageloc == *[[:space:]]* || $storageloc == *[,]* ]] then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1443 "\nERROR: Multiple storage locations are not allowed.\n\n" 1>&2 print "\nERROR: Multiple storage locations are not allowed.\n\n" >>$CLMGR_TMPLOG rc=$RC_INCORRECT_INPUT fi #============================================= : Make sure some modifications were provided #============================================= if [[ "$newname$mode$force_sync$async_cache_lv$async_cache_hw_mark$storageloc$disks_to_add$disks_to_remove" == *([[:space:]]) ]] then dspmsg -s $CLMGR_SET $CLMGR_MSGS 401 '\nERROR: no valid modifications were specified for "%1$s".\n\n' "$mirror_pool" 1>&2 rc=$RC_MISSING_INPUT fi #=============================================================== : Modify the mirror pool if no input errors have been detected #=============================================================== if (( $rc == RC_UNKNOWN )); then if [[ -n $newname ]]; then if [[ " ${VGNODES//,/ } " == *\ $LOCAL_NODE\ * ]]; then print "$0()[$LINENO]($SECONDS): cl_ren_mp -cspoc \"-n $VGNODES\" \"$volume_group\" \"$mirror_pool\" \"$newname\"" >>$CLMGR_TMPLOG cl_ren_mp -cspoc "-n $VGNODES" "$volume_group" "$mirror_pool" "$newname" else typeset remote_node=$VGNODES remote_node=${remote_node%%,*} print "$0()[$LINENO]($SECONDS): $CLRSH $remote_node $HASBIN/cl_ren_mp -cspoc \"-n $VGNODES\" \"$volume_group\" \"$mirror_pool\" \"$newname\"" >>$CLMGR_TMPLOG $CLRSH $remote_node $HASBIN/cl_ren_mp -cspoc "-n $VGNODES" "$volume_group" "$mirror_pool" "$newname" fi rc=$? print "$0()[$LINENO]($SECONDS): cl_ren_mp RC: $rc" >>$CLMGR_TMPLOG (( $rc == RC_SUCCESS )) && mirror_pool=$newname # Only if successful fi fi if (( $rc == RC_UNKNOWN || $rc == RC_SUCCESS)) && \ [[ "$mode$force_sync$async_cache_lv$async_cache_hw_mark$storageloc" != *([[:space:]]) ]] then typeset AOpt="" cOpt="" hOpt="" fOpt="" Tflag="" #Passing AOpt to cl_chshmp function only if mode is set to sync or async. [[ $mode == a* ]] && AOpt=" -A" [[ $mode == s* ]] && AOpt=" -S" [[ -n $async_cache_lv ]] && cOpt=" -c $async_cache_lv" [[ -n $async_cache_hw_mark ]] && hOpt=" -h $async_cache_hw_mark" [[ -n $force_sync && $force_sync == @(y|t|1)* ]] && fOpt=" -f" if [[ -n $storageloc ]] then Tflag="-t $storageloc" fi print "$0()[$LINENO]($SECONDS): _CSPOC_CALLED_FROM_SMIT=true cl_chshmp -cspoc -n\"$VGNODES\"$AOpt$cOpt$hOpt$fOpt -m $mirror_pool $Tflag $volume_group" >>$CLMGR_TMPLOG _CSPOC_CALLED_FROM_SMIT=true cl_chshmp -cspoc -n"$VGNODES" $AOpt$cOpt$hOpt$fOpt -m $mirror_pool $Tflag $volume_group rc=$? print "$0()[$LINENO]($SECONDS): cl_chshmp RC: $rc" >>$CLMGR_TMPLOG fi # : If there are not any known errors from any of the previous processing, : and the customer asked for disks to be added to the mirror pool, handle : that here. # if (( $rc == RC_UNKNOWN || $rc == RC_SUCCESS )) && [[ -n $disks_to_add ]] then disks_to_add=$(echo "$disks_to_add" | tr " " "\n" | sort -u | tr "\n" " ") print "$0()[$LINENO]($SECONDS): _CSPOC_CALLED_FROM_SMIT=true cl_mp_disks -cspoc -n\"$VGNODES\" -p $mirror_pool $volume_group $disks_to_add" >>$CLMGR_TMPLOG _CSPOC_CALLED_FROM_SMIT=true cl_mp_disks -cspoc -n"$VGNODES" -p $mirror_pool $volume_group $disks_to_add >>$CLMGR_TMPLOG rc=$? print "$0()[$LINENO]($SECONDS): cl_mp_disks RC: $rc" >>$CLMGR_TMPLOG fi # : If there are not any known errors from any of the previous processing, : and the customer asked for disks to be removed from the mirror pool, : handle that here. # if (( $rc == RC_UNKNOWN || $rc == RC_SUCCESS )) && [[ -n $disks_to_remove ]] then disks_to_remove=$(echo "$disks_to_remove" | tr " " "\n" | sort -u | tr "\n" " ") print "$0()[$LINENO]($SECONDS): _CSPOC_CALLED_FROM_SMIT=true cl_mp_disks -cspoc -n\"$VGNODES\" -P $volume_group $disks_to_remove" >>$CLMGR_TMPLOG _CSPOC_CALLED_FROM_SMIT=true cl_mp_disks -cspoc -n"$VGNODES" -P $volume_group $disks_to_remove >>$CLMGR_TMPLOG rc=$? print "$0()[$LINENO]($SECONDS): cl_mp_disks RC: $rc" >>$CLMGR_TMPLOG fi #======================================================================= : If a user input error was detected, provide some helpful suggestions #======================================================================= if (( $rc == RC_MISSING_INPUT || $rc == RC_INCORRECT_INPUT )) && \ [[ $CLMGR_GUI == *([[:space:]]) ]] then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 104 "For more information about available options and syntax, try\n\"$HAUTILS/clmgr %1\$s\". As an\nalternative, if the PowerHA SystemMirror man pages have been installed, invoke\n\"$HAUTILS/clmgr -hv\" (or \"/usr/bin/man clmgr\"),\nsearching for \"%2\$s\" in the displayed text.\n\n" \ "modify mirror_pool -h" "MIRROR POOL:" "$CLMGR_PROGNAME" 1>&2 elif (( $rc == RC_SUCCESS )) then : If output from this operation was requested, retrieve it if (( CLMGR_VERBOSE )) || [[ -n $CLMGR_ATTRS ]]; then CL=$LINENO KLIB_HACMP_get_mirror_pool_attributes "$mirror_pool" properties fi fi log_return_msg "$rc" "$0()" "$LINENO" return $? } # End of "KLIB_HACMP_modify_mirror_pool()" #============================================================================ # # Name: devDoc # # Description: This is a never-to-be-called, wrapper function that all the # clmgr FPATH functions implement in order to hide embedded # syntax from trace logging. This information is implemented # in POD format, and can be viewed in a number of ways using # POD tools. Some viewing suggestions for this function's POD- # formatted information are: # # perldoc # pod2text -c # pod2text -c --code # pod2html # # However, the more important use for this information is that # it is parsed by clmgr to display the syntax for this file's # operation. The information in the "SYNOPSIS" section is used # for this purpose. This feature was originally implemented # using the man page information. However, in a code review it # was pointed out that this approach had to be changed because # customers do not have to install the man pages! Therefore, a # built-in dependency on man page information would break the # automatic help feature of clmgr. So the SYNPOSIS section must # be used instead. # # IMPORTANT: As a result of this, it is imperative that the # information in this SYNOPSIS be kept in sync # with the man page information, which is owned # by the IDD team. # # Inputs: None. # # Outputs: None. # # Returns: n/a (not intended to be invoked) # #============================================================================ function devDoc { : <<'=cut' >/dev/null 2>&1 =head1 NAME KLIB_HACMP_modify_mirror_pool =head1 SYNOPSIS clmgr modify mirror_pool \ [ NAME= ] \ [ VOLUME_GROUP= ] \ [ ADD=[,disk#2,...] ] \ [ REMOVE=[,disk#2,...] ] \ [ STORAGE_LOCATION={default|flashstorage|} ] \ [ MODE={sync|async} ] \ [ FORCE_SYNC={false|true} ] \ [ ASYNC_CACHE_LV= ] \ [ ASYNC_CACHE_HW_MARK=## ] \ NOTE: aliases for "mirror_pool" are "mp", "mi", and "pool". =head1 DESCRIPTION Attempts to modify the specified mirror pool to conform to the provided specifications. =head1 ARGUMENTS 1. properties [REQUIRED] [hash ref] An associative array within which data about the modified object can be returned to the caller. 2. mirror_pool [REQUIRED] [string] The label of the mirror_pool that is to be modified. 3. volume_group [OPTIONAL] [string] The volume group that the specified mirror pool belongs to. If not provided, and effort will be made to determine the volume group automatically. 4. new_name [OPTIONAL] [string] A new label to attempt to apply to the specified mirror pool. 5. storage_location [REQUIRED] [string] Storage location for the associated physical volumes. It is a non-mandatory field, a blank or the word default will give the default behavior. Valid values are: default, flashstorage, sitenames. 6. mode [OPTIONAL] [string] The mirroring mode for this mirror pool, synchronous or asynchronous. Valid values are: SYNC, ASYNC 7. force_sync [OPTIONAL] [boolean] Forces a mirror pool from asynchronous mirroring to synchronous mirroring, even if the remote I/O cache is not accessible. 8. async_cache_lv [OPTIONAL] [string] The name of an asynchronous I/O-cache logical volume for the mirror pool to use for asynchronous mirroring. The logical volume must be of the aio_cache type and must not reside in the mirror pool 9. async_cache_hw_mark [OPTIONAL] [posint] Specifies the I/O-cache high watermark. The value is the percent of I/O cache size; the default value is 100%. 10. disks_to_add [OPTIONAL] [string] One or more disks to add to the mirror pool from the volume group. 11. disks_to_remove [OPTIONAL] [string] One or more disks to remove from the mirror pool. =head1 RETURN 0: no errors were detected; the operation appears to have been successful 1: a general error has occurred 2: a specified resource does not exist, or could not be found 3: some required input was missing 4: some detected input was incorrect in some way 5: a required dependency does not exist 6: a specified search failed to match any data =cut } # End of "devDoc()" #============================================================================== # The following, comment block attempts to enforce coding standards when this # file is edited via emacs or vim. This block _must_ appear at the very end # of the file, or the editor will not find it, and it will be ignored. #============================================================================== # Local Variables: # indent-tabs-mode: nil # tab-width: 4 # End: #============================================================================== # vim: tabstop=4 shiftwidth=4 expandtab #==============================================================================