#!/bin/ksh93 # ALTRAN_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # Copyright (C) Altran ACT S.A.S. 2017,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_add_mirror_pool.sh 1.6 # # 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_add_mirror_pool.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM #============================================================================ # # Name: KLIB_HACMP_add_mirror_pool # # Description: This is the main, FPATH function that is invoked by clmgr # to add new mirror pools to 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_add_mirror_pool { . $HALIBROOT/log_entry "$0()" "$CL" : version=@(#) 7d4c34b 43haes/lib/ksh93/hacmp/KLIB_HACMP_add_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 disks=${4//\"/} disks=${disks//,/ } typeset storage_location=${5//\"/} typeset -l mode=${6//\"/} typeset async_cache_lv=${7//\"/} typeset async_cache_hw_mark=${8//\"/} [[ $CLMGR_LOGGING == 'med' ]] && set +x # Only trace param values #=================================== : Declare and initialize variables #=================================== integer rc=$RC_UNKNOWN integer MAX_MIRROR_POOLS=3 #================= : Validate input #================= if [[ -n $mirror_pool ]]; then typeset BAD_CHARS=${mirror_pool//[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' "$mirror_pool" "${mirror_pool//[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=${#mirror_pool} for (( ; I<${#CMD}; I++ )) do if [[ ${CMD:$I} == $mirror_pool@([[: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 else 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 fi if (( rc != RC_UNKNOWN )) then log_return_msg "$rc" "$0()" "$LINENO" return $? fi typeset -i DISPLAY_VGS=0 if [[ -z $volume_group ]]; then typeset FOUND=$(CL=$LINENO KLIB_HACMP_is_known_mirror_pool "$mirror_pool") if (( $? == RC_SUCCESS )); then print -- "$FOUND" | read mirror_pool volume_group volume_group=${volume_group#\(} volume_group=${volume_group%\)} fi else CL=$LINENO KLIB_HACMP_is_known_volume_group "$volume_group" if (( $? != RC_SUCCESS )); then dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 '\nERROR: "%1$s" does not appear to exist!\n\n' "$volume_group" 1>&2 DISPLAY_VGS=1 rc=$RC_NOT_FOUND fi fi if (( $rc == RC_UNKNOWN )) && [[ -z $volume_group ]]; then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 101 '\nERROR: this operation requires the "%1$s" attribute.\n\n' VOLUME_GROUP 1>&2 DISPLAY_VGS=1 rc=$RC_MISSING_INPUT fi if (( DISPLAY_VGS )); then dspmsg -s $CLMGR_SET $CLMGR_MSGS 160 'Available Volume Groups:\n\n' 1>&2 typeset available CL=$LINENO KLIB_HACMP_list_volume_groups available for (( i=0; i<${#available[*]}; i++ )); do if [[ ${available[$i]} != *([[:space:]]) ]]; then print -u2 "\t${available[$i]}" fi done print -u2 "" fi if (( $rc == RC_UNKNOWN )); then typeset -A vgprops CL=$LINENO KLIB_HACMP_get_volume_group_attributes "$volume_group" vgprops if [[ ${vgprops[STRICT_MIRROR_POOLS]} == "super" ]]; then typeset -i mp_count=0 typeset mp="" for mp in ${vgprops[MIRROR_POOLS]//,/ }; do [[ $mp != *([[:space:]]) ]] && (( mp_count++ )) done if (( mp_count >= $MAX_MIRROR_POOLS )); then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1406 '\nERROR: volume group "%1$s" is configured for super-strict mirror pools, which limits it to a maximum of %3$d. Since "%1$s" already has 3 mirror pools, "%2$s" cannot be added to it.\n\n' "$volume_group" "$mirror_pool" "$MAX_MIRROR_POOLS" 1>&2 rc=$RC_ERROR fi fi fi if [[ -n $disks && -n $volume_group ]]; then #===================================================== : Verify that the specified disks are managed within : the specified volume group, $volume_group #===================================================== typeset KNOWN_PVS=${vgprops[PHYSICAL_VOLUMES]} KNOWN_PVS=${KNOWN_PVS//,/ } KNOWN_PVS=${KNOWN_PVS//@/ } typeset PV="" CAND_PVS=${_ENV_ARGS[PHYSICAL_VOLUMES]//\"/} for PV in ${CAND_PVS//,/ }; do if [[ " $KNOWN_PVS " != *\ $PV\ * ]]; then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1407 'Warning: the specified physical volume, "%1$s", does not appear to be managed by the indicated volume group, "%2$s". An attempt will be made to add it...\n' "$PV" "$volume_group" clmgr modify volume_group "$volume_group" ADD="$PV" if (( $? != RC_SUCCESS )); then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1408 '\nERROR: could not add physical volume "%1$s" to volume group "%2$s".\n\n' "$PV" "$volume_group" 1>&2 rc=$RC_INCORRECT_INPUT fi fi done fi if (( $rc == RC_UNKNOWN )); then typeset -A vgprops CL=$LINENO KLIB_HACMP_get_volume_group_attributes "$volume_group" vgprops if [[ -z $disks ]]; then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 278 '*** Warning: since no physical volumes were specified, all available physical volumes in volume group "%1$s" will be used for this mirror pool:\n\n' "$volume_group" print "$0()[$LINENO]($SECONDS): clmgr -cSa PHYSICAL_VOLUMES query mirror_pool VOLUME_GROUP=$volume_group" >>$CLMGR_TMPLOG typeset MP_DISKS=$(clmgr -cSa PHYSICAL_VOLUMES query mirror_pool VOLUME_GROUP=$volume_group) print "$0()[$LINENO]($SECONDS): clmgr RC: $?, MP_DISKS=$MP_DISKS" >>$CLMGR_TMPLOG MP_DISKS=${MP_DISKS//,/ } MP_DISKS=" ${MP_DISKS//$NL/ } " typeset PV="" REFNODE="" PVID="" REM="" for PV in ${vgprops[PHYSICAL_VOLUMES]//,/ }; do print -- "$PV" | IFS=@ read PV REFNODE PVID REM if [[ $MP_DISKS == *\ $PV\ * || $MP_DISKS == *\ $PVID\ * ]] then continue fi print "\t$PV ($PVID)" if [[ -n $disks ]]; then disks="$disks$NL" fi disks="$disks$PVID" done if [[ -z $disks ]]; then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1409 '\nERROR: no valid physical volumes appear to be available in volume group "%1$s".\n\n' "$volume_group" 1>&2 rc=$RC_MISSING_INPUT fi 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 && $mode != "async" ]]; then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 '\nERROR: "%1$s" requires a "%2$s" value of "%3$s".\n\n' ASYNC_CACHE_LV MODE ASYNC 1>&2 fi if [[ -n $async_cache_hw_mark && $mode != "async" ]]; then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 '\nERROR: "%1$s" requires a "%2$s" value of "%3$s".\n\n' ASYNC_CACHE_HW_MARK MODE ASYNC 1>&2 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 $storage_location ]] && [[ $storage_location == *[[:space:]]* || $storage_location == *[,]* ]] 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 #=============================================================== : Create the mirror_pool if no input errors have been detected #=============================================================== if (( $rc == RC_UNKNOWN )); then typeset Tflag="" if [[ -n $storage_location ]];then Tflag="-t$storage_location" fi print "$0()[$LINENO]($SECONDS): _CSPOC_CALLED_FROM_SMIT=true $HASBIN/cl_mp_disks -cspoc -n\"${vgprops[NODES]// /,}\" -p\"$mirror_pool\" $Tflag \"$volume_group\" $disks" >>$CLMGR_TMPLOG _CSPOC_CALLED_FROM_SMIT=true $HASBIN/cl_mp_disks -cspoc -n"${vgprops[NODES]// /,}" -p"$mirror_pool" $Tflag "$volume_group" $disks >>$CLMGR_TMPLOG rc=$? print "$0()[$LINENO]($SECONDS): cl_mp_disks RC: $rc" >>$CLMGR_TMPLOG if (( $rc != RC_SUCCESS )); then dspmsg -s $CLMGR_SET $CLMGR_MSGS 201 '\nERROR: failed to create "%1$s".\n\n' "$mirror_pool" 1>&2 rc=$RC_ERROR fi fi #===================================================================== : If the mirror pool was successfully created, apply any operational : modifications that may have been specified by the customer. #===================================================================== if (( $rc == RC_SUCCESS )); then if [[ -n "$mode$async_cache_lv$async_cache_hw_mark" ]]; then typeset AOpt="" cOpt="" hOpt="" [[ $mode == a* ]] && AOpt=" -A" || AOpt=" -S" [[ -n $async_cache_lv ]] && cOpt=" -c $async_cache_lv" [[ -n $async_cache_hw_mark ]] && hOpt=" -h $async_cache_hw_mark" print "$0()[$LINENO]($SECONDS): _CSPOC_CALLED_FROM_SMIT=true cl_chshmp -cspoc -n\"${vgprops[NODES]// /,}\"$AOpt$cOpt$hOpt -m $mirror_pool $volume_group" >>$CLMGR_TMPLOG _CSPOC_CALLED_FROM_SMIT=true cl_chshmp -cspoc -n\"${vgprops[NODES]// /,}\" $AOpt$cOpt$hOpt -m $mirror_pool $volume_group rc=$? print "$0()[$LINENO]($SECONDS): cl_chshmp RC: $rc" >>$CLMGR_TMPLOG if (( $rc != RC_SUCCESS )); then dspmsg -s $CLMGR_SET $CLMGR_MSGS 201 '\nERROR: failed to create "%1$s".\n\n' "$mirror_pool" 1>&2 rc=$RC_ERROR CL=$LINENO KLIB_HACMP_delete_mirror_pool $mirror_pool $volume_group fi fi fi #=========================================================== : If output from this operation was requested, retrieve it #=========================================================== if (( $rc == RC_SUCCESS )); then if (( CLMGR_VERBOSE )) || [[ -n $CLMGR_ATTRS ]]; then CL=$LINENO KLIB_HACMP_get_mirror_pool_attributes "$mirror_pool" properties fi 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" \ "add mirror_pool -h" "MIRROR POOL:" "$CLMGR_PROGNAME" 1>&2 fi log_return_msg "$rc" "$0()" "$LINENO" return $? } # End of "KLIB_HACMP_add_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_add_mirror_pool =head1 SYNOPSIS clmgr add mirror_pool \ VOLUME_GROUP= \ [ PHYSICAL_VOLUMES="[,,...]" ] \ [ STORAGE_LOCATION={default|flashstorage|} ]\ [ MODE={sync|async} ] \ [ ASYNC_CACHE_LV= ] \ [ ASYNC_CACHE_HW_MARK=## ] clmgr add mirror_pool \ [ VOLUME_GROUP= ] \ PHYSICAL_VOLUMES="[,,...]" \ [ STORAGE_LOCATION={default|flashstorage|} ] NOTE: if an "add" operation is performed on an existing mirror pool, the specified physical volumes will be added to that mirror pool. NOTE: alias for "mirror_pool" are "mp", "mi", and "pool". =head1 DESCRIPTION Attempts to add a new mirror pool to the specified volume group, using the indicated disks. =head1 ARGUMENTS 1. properties [REQUIRED] [hash ref] An associative array within which data about the created object can be returned to the caller. 2. mirror_pool [REQUIRED] [string] The label that is to be applied to this mirror pool. 3. volume_group [REQUIRED] [string] The name of the volume group to add this mirror pool to. 4. disks [REQUIRED] [string] The list of physical volumes to add to the 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, . 6. mode [OPTIONAL] [string] The mirroring mode for this mirror pool, synchronous or asynchronous. Valid values are: SYNC, ASYNC 7. 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 8. 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%. =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 #==============================================================================