#!/bin/ksh93 # ALTRAN_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # Copyright (C) Altran ACT S.A.S. 2017,2019,2021. All rights reserved. # # ALTRAN_PROLOG_END_TAG # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # 61haes_r720 src/43haes/lib/ksh93/hacmp/KLIB_HACMP_get_physical_volume_attributes.sh 1.21.1.4 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 2010,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 # @(#) 7d4c34b 43haes/lib/ksh93/hacmp/KLIB_HACMP_get_physical_volume_attributes.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM #============================================================================ # # Name: KLIB_HACMP_get_physical_volume_attributes # # Description: This is the main, FPATH function that is invoked by # clmgr to collect physical volume information. # # Inputs: See the "devDoc()" function at the bottom of this file. # # 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 at the bottom of this file for # the standard return code values/meanings for clmgr. # #============================================================================ function KLIB_HACMP_get_physical_volume_attributes { . $HALIBROOT/log_entry "$0()" "$CL" : version=@(#) 7d4c34b 43haes/lib/ksh93/hacmp/KLIB_HACMP_get_physical_volume_attributes.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM : INPUTS: $* typeset DISKS=${1//\"/} DISKS=${DISKS//,/ } # Get the "properties" associative array reference, and initialize it if [[ -z $2 ]] || [[ -n $CLMGR_LOGGING && $2 == "|" ]]; then DISKS= typeset -n properties=$1 shift else typeset -n properties=$2 shift; shift fi typeset nodes="" if (( $# >= 1 )); then nodes=${1//\"/} nodes=${nodes//,/ } shift fi typeset -l TYPE="" if (( $# >= 1 )); then TYPE=${1//\"/} shift fi [[ $CLMGR_LOGGING == 'med' ]] && set +x # Only trace param values #=================================== : Declare and initialize variables #=================================== for k in ${!properties[*]}; do unset properties[$k]; done typeset -u name_uc= pvid_uc= vg_uc= typeset STORAGE= name= vg= uuid= rest= SIZE=-1 PVDATA= DEVDATA= typeset -i INDEX=1 rc=$RC_UNKNOWN typeset key= nodedata= DATA= DISK_DATA= querypv= gsclvmd= typeset -i matches=0 lqueryvg_rc=$RC_UNKNOWN typeset -u attr= uc_key= ALL= typeset -A queries typeset clcomd_contacts= typeset -A common if [[ $TYPE != *([[:space:]]) ]]; then if [[ $TYPE == "tb" ]]; then TYPE="tiebreaker" else CL=$LINENO verify_in_set TYPE "$TYPE" "available, all, tiebreaker" TYPE (( $? != RC_SUCCESS )) && rc=$RC_INCORRECT_INPUT fi fi # Allowing to retrieve used disk information as well [[ -n "$DISKS" ]] && TYPE="all" [[ $TYPE == "all" ]] && ALL="-A" #=================================================== : Check for any specified attribute=value pairs. : If any are found, use those to query the output. #=================================================== while (( $# > 0 )); do value="$1" shift LC_ALL=C sleep .01 # Slow down the loop if [[ $value == *=* ]]; then attr=${value%%=*} # "attr" makes this uppercase [[ $attr == @(TYPE|NODE)* ]] && continue queries[$attr]="${value#*=}" fi done #================================================== : If no nodes were specified, use all known nodes #================================================== if [[ $nodes == *([[:space:]]) ]]; then print "$0()[$LINENO]($SECONDS): clnodename" >>$CLMGR_TMPLOG # Always log commands nodedata=$(clnodename 2>>$CLMGR_TMPLOG) print "$0()[$LINENO]($SECONDS): clnodename RC: $?; nodedata == \"$nodedata\"" >>$CLMGR_TMPLOG # Always log command result if [[ " $nodedata " == *[[:space:]]${LOCAL_NODE}[[:space:]]* ]]; then nodes=$LOCAL_NODE for node in $nodedata; do [[ $node == $LOCAL_NODE ]] && continue nodes="$nodes $node" done else nodes=${nodedata//+([[:space:]])/ } fi if [[ $nodes == *([[:space:]]) ]]; then print "$0()[$LINENO]($SECONDS): hostname" >>$CLMGR_TMPLOG # Always log commands nodes=$(hostname) print "$0()[$LINENO]($SECONDS): hostname RC: $?; nodes == \"$nodes\"" >>$CLMGR_TMPLOG # Always log command result fi fi nodes=$(CL=$LINENO trim "${nodes//+([[:space:]])/ }") # Remove any newlines # : If this was invoked from KLIB_HACMP_list_physical_volume, : the validity of the disks has already been ascertained. # if [[ $CLMGR_STACK != *KLIB_HACMP_list_physical_volume* ]] then for disk in $DISKS; do CL=$LINENO KLIB_HACMP_is_known_physical_volume $disk ${nodes%%\ *} if (( $? != RC_SUCCESS )); then dspmsg -s $CLVT_SET $CLVT_MSGS 102 '\nERROR: "%1$s" does not appear to exist!\n\n' "$disk" 1>&2 rc=$RC_NOT_FOUND fi done fi if (( $rc == RC_NOT_FOUND )); then typeset HEADER=$(dspmsg -s $CLVT_SET $CLVT_MSGS 153 "Available Physical Volumes:\n\n") if [[ -n $nodes ]]; then HEADER=${HEADER%%+([[:space:]])} HEADER="$HEADER (${nodes// /,})\n" fi print -u2 "$HEADER" typeset available CL=$LINENO KLIB_HACMP_list_physical_volume available "$nodes" "" for (( i=0; i<${#available[*]}; i++ )); do if [[ ${available[$i]} != *([[:space:]]) ]]; then print -u2 "\t${available[$i]}" fi done print -u2 "" else for disk in $DISKS; do [[ $disk != *@* ]] && continue node=${disk##*@} [[ -z $node ]] && continue [[ " $nodes " == *\ $node\ * ]] && continue nodes="$nodes $node" done fi if [[ $nodes == *([[:space:]]) ]]; then dspmsg -s $CLMGR_SET $CLMGR_MSGS 116 "\nERROR: no nodes are defined on this host, and none were specified\n via the \"NODES\" attribute.\n\n" 1>&2 rc=$RC_MISSING_DEPENDENCY elif (( $rc == RC_UNKNOWN )); then #================================================================ : Populate the return hash with the retrieved attributes/values #================================================================ typeset -i isLocalNode=0 print "$0()[$LINENO]($SECONDS): LC_ALL=C host $(hostname)" >>$CLMGR_TMPLOG # Always log commands LC_ALL=C host $(hostname) 2>>$CLMGR_TMPLOG |\ read localhost junk localip rem print "$0()[$LINENO]($SECONDS): host RC: $?; localhost:$junk:$localip:$rem" >>$CLMGR_TMPLOG # Always log command result localip=${localip%%,*} if [[ $TYPE == "tiebreaker" ]]; then list_tiebreakers "$nodes" "$DISKS" common clcomd_contacts else # : Retrieve the repositories. To be used as a filter, if needed. # typeset DEFINED_REPOSITORIES=" $(clodmget -d' ' -n -f repository,backup_repository HACMPsircol) " typeset -i count=0 for node in $nodes; do (( count++ )) isLocalNode=0 PVDATA=$(CL=$LINENO list_disks "$node") rc=$? if (( $rc == RC_SUCCESS )) && [[ -n $PVDATA ]]; then clcomd_contacts="$clcomd_contacts $node" [[ $node == $LOCAL_NODE ]] && isLocalNode=1 else : Warn the user that there is a comm problem typeset HDATA="" typeset CP=$(clodmget -n -f value -q "name = $node AND object = COMMUNICATION_PATH" HACMPnode) if [[ -n $CP ]]; then HDATA=$(LC_ALL=C host $CP) HDATA=${HDATA%%,*} HDATA=${HDATA/ is/,} fi dspmsg -s $CLMGR_SET $CLMGR_MSGS 182 '\nERROR: unable to communicate with "%1$s" (%2$s).\n\n' "$node" "$HDATA" 1>&2 unset PVDATA rc=$RC_ERROR fi if [[ $PVDATA == *([[:space:]]) ]]; then #=========================================================== : Since "$node" does not have any free disks, we are done. #=========================================================== unset common break fi if (( count == 1 )); then #========================================================== : Load all the disks from the first node to be processed, : "$node", into the "common" array, to initialize it with : disks. #========================================================== print -- "$PVDATA" |\ while read name pvid vg uuid rest do typeset disk_node= if [[ $DISKS != *([[:space:]]) && \ $pvid != *([[:space:]]) ]] then #============================================== : Since the user indicated an interest in a : specific set of disks, check for those now, : throwing out any disks that were not : expressly asked for. #============================================== for disk in $DISKS; do if [[ $disk == *@* ]]; then disk_node=${disk##*@} disk=${disk%%@*} elif [[ $disk == *+([[:space:]])* ]]; then disk_node=${disk##*+([[:space:]])} disk=${disk%%+([[:space:]])*} else disk_node= fi pvid_uc=$disk uc_key=$pvid [[ $uc_key == $pvid_uc ]] && break uc_key=$name [[ $uc_key == $pvid_uc ]] && break #disks could be passed in form of uuid too #so comparing pvid_uc with uuid uc_key=$uuid [[ $uc_key == $pvid_uc ]] && break pvid_uc="" done if [[ -z $pvid_uc ]]; then : Current disk does not match the user disk continue fi fi #==================================================== : Only keep "free" disks, that are not already in a : volume group, or in use as a repository, unless : the customer specifically asked to include disks : that are already in use. #==================================================== vg_uc=$vg if [[ $vg_uc == "NONE" && $DEFINED_REPOSITORIES != *\ $pvid\ * ]] || [[ -n $ALL ]] then if [[ -n $disk_node ]]; then common[_$pvid]="$disk_node:$name:$vg:$uuid" else common[_$pvid]="$node:$name:$vg:$uuid" fi fi done else #======================================================= : For all subsequent nodes, compare the disks found to : those in the "common" array. Throw out all "common" : entries that do not occur in the hosts data, because : they are obviously *not* common! #======================================================= unset disks # Make sure any previous contents are removed typeset -A disks= print -- "$PVDATA" |\ while read name pvid vg uuid rest do [[ -z ${common[_$pvid]} ]] && continue vg_uc=$vg if [[ $vg_uc == "NONE" && $DEFINED_REPOSITORIES != *\ $pvid\ * ]] || [[ -n $ALL ]] then #================================================== : Only keep "free" disks, that are not already in : a VG, unless the customer specifically asked to : include disks that are already in use. #================================================== disks[_$pvid]="$node:$name:$vg:$uuid" fi done #============================================== : Throw out any/all disks that are not common #============================================== for pvid in ${!common[*]}; do if [[ -z ${disks[$pvid]} ]]; then unset common[$pvid] elif (( isLocalNode )); then #================================================== : Always prefer localnode data over remote nodes, : because it will always be the controlling node : from the perspective of a remote management UI. #================================================== common[$pvid]=${disks[$pvid]} fi done fi done # End of the "nodes" loop fi if [[ -n $DISKS ]]; then #========================================================= : Specific disks were requested. See if they were found. #========================================================= typeset -i FOUND=0 for disk in ${DISKS//,/ }; do FOUND=0 name="" uuid="" for pvid in ${!common[*]}; do print "${common[$pvid]}" |\ IFS=: read host name vg uuid rem if [[ ":${pvid#_}:$name:$uuid:" == *:$disk:* ]] then FOUND=1 break fi done if (( ! FOUND )); then if [[ $CLMGR_STACK != *KLIB_HACMP_replace_repository* ]] then # Only display this for non-replacement operations cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 468 '\nERROR: "%1$s" was not found in the data that you requested.\n\n' "$disk" 1>&2 if [[ ${!common[*]} != *([[:space:]]) ]]; then dspmsg -s 2 command.cat 3 'Valid values: %1$s\n\n' "" 1>&2 name="" uuid="" for pvid in ${!common[*]}; do print "${common[$pvid]}" |\ IFS=: read host name vg uuid rem print -u2 "\t$name (${pvid#_})" done fi fi #======================================================= : The disks the customer requested were not all found, : so go ahead and exit, returning no results at all. #======================================================= log_return_msg "$RC_NOT_FOUND" "$0()" "$LINENO" return $? fi done fi #================================================================= : Retrieve the remaining information for the shared/common disks #================================================================= typeset -A CLGETPVID for pvid in ${!common[*]} do print "${common[$pvid]}" |\ IFS=: read host name vg uuid rem properties[NAME$INDEX]="$name" properties[UUID$INDEX]="$uuid" properties[VOLUME_GROUP$INDEX]="$vg" properties[PVID$INDEX]=${pvid#_} if [[ ${host%%\.*} == ${localhost%%\.*} || $host == $localip || $host == $LOCAL_NODE ]] then if [[ -z ${CLGETPVID[$LOCAL_NODE]} ]] then : Get the local disks print "$0()[$LINENO]($SECONDS): clgetpvid $ALL" >>$CLMGR_TMPLOG # Always log commands CLGETPVID[$LOCAL_NODE]=$(clgetpvid $ALL) print "$0()[$LINENO]($SECONDS): clgetpvid RC: $?" >>$CLMGR_TMPLOG # Always log command result fi : Process locally retrieved data: ${localhost%%\.*} print -- "${CLGETPVID[$LOCAL_NODE]}" |\ while IFS=: read dname dpvid concurrent ecm size rem do if [[ _$dpvid == $pvid ]]; then properties[SIZE$INDEX]=$size properties[CONCURRENT$INDEX]=false if [[ $concurrent == "C" ]]; then properties[CONCURRENT$INDEX]=true fi properties[ENHANCED_CONCURRENT_MODE$INDEX]=false if [[ $ecm == "Y" ]]; then properties[ENHANCED_CONCURRENT_MODE$INDEX]=true fi break fi done # : If the stack indicates we are only listing disks, and this is : not a full blown query, we already have the necessary data and : do not need to collect any more. This provides a performance : improvement. # if [[ $CLMGR_STACK == *KLIB_HACMP_list_physical_volume* ]] then (( INDEX++ )) [[ $INDEX == *0 ]] && (( INDEX++ )) continue fi : Find out if the disk is SCSI Persistent Reserve Type 7H capable clpr_verifycap $name 2>>$CLMGR_TMPLOG typeset -i rc_cap=$? if (( $rc_cap == 0 ));then properties[SCSIPR_CAPABLE$INDEX]="Yes" elif (( $rc_cap == 1 ));then properties[SCSIPR_CAPABLE$INDEX]="No" else properties[SCSIPR_CAPABLE$INDEX]="Unknown" fi : Attempt to calculate available disk space print "$0()[$LINENO]($SECONDS): LC_ALL=C lqueryvg -Atp $name" >>$CLMGR_TMPLOG # Always log commands DISK_DATA=$(LC_ALL=C lqueryvg -Atp $name 2>$TMPDIR/KHgpva.lqueryvg.$$.$name) print "$0()[$LINENO]($SECONDS): lqueryVG RC: $?" >>$CLMGR_TMPLOG # Always log command result typeset FREE_PPS=${DISK_DATA##*Free PPs:*([[:space:]])} FREE_PPS=${FREE_PPS%%$NL*} typeset PP_SIZE=${DISK_DATA##*PP Size:*([[:space:]])} PP_SIZE=${PP_SIZE%%$NL*} if [[ $FREE_PPS == +([0-9]) && $PP_SIZE == +([0-9]) ]] then typeset -i idx=0 PP_SIZE_MB=1 : Calculate physical partition size: 2 to the $PP_SIZE power for (( idx=0; idx<$PP_SIZE; idx++ )); do (( PP_SIZE_MB *= 2 )) done : Convert PP Size to MB (( PP_SIZE_MB = PP_SIZE_MB / 1024 )) (( PP_SIZE_MB = PP_SIZE_MB /1024 )) (( properties[AVAILABLE$INDEX] = $FREE_PPS * $PP_SIZE_MB )) elif grep -qi "is not assigned" $TMPDIR/KHgpva.lqueryvg.$$.$name then : We could not determine available space. Return the bulk size. properties[AVAILABLE$INDEX]=${properties[SIZE$INDEX]} else : We could not determine available space even though : the disk is in a volume group. Return a null value. properties[AVAILABLE$INDEX]= fi if [[ -z ${properties[CONCURRENT$INDEX]} ]]; then # : The ones that LVM says are concurrent capable # print "$0()[$LINENO]($SECONDS): lquerypv -C $name" >>$CLMGR_TMPLOG # Always log commands if (( 1 == $(lquerypv -C $name 2>>$CLMGR_TMPLOG) )); then properties[CONCURRENT$INDEX]="true" properties[ENHANCED_CONCURRENT_MODE$INDEX]="false" # : Otherwise, if the group services CLVM daemon is present, : pretty much anything can be used in a concurrent : volume group # elif [[ -x gsclvmd ]]; then print "$0()[$LINENO]($SECONDS): gsclvmd exists, and is executable" >>$CLMGR_TMPLOG # Always log command result properties[CONCURRENT$INDEX]="true" properties[ENHANCED_CONCURRENT_MODE$INDEX]="true" # : Anything else cannot be used in a concurrent volume group # else properties[CONCURRENT$INDEX]="false" properties[ENHANCED_CONCURRENT_MODE$INDEX]="false" fi fi # # It is necessary to set ODMDIR here for the case where ODMDIR # has been redirected to a set of temporary ODMs restored from # a snapshot. If we do not do this, then lsdev will fail due to # not being able to find the PdDv ODM file. # print "$0()[$LINENO]($SECONDS): ODMDIR=/etc/objrepos lsdev -l $name -F \"type##description##status\"" >>$CLMGR_TMPLOG # Always log commands DEVDATA=$(ODMDIR=/etc/objrepos lsdev -l $name -F "type##description##status" 2>>$CLMGR_TMPLOG) print "$0()[$LINENO]($SECONDS): lsdev RC: $?; DEVDATA == \"$DEVDATA\"" >>$CLMGR_TMPLOG # Always log command result else : Process remotely retrieved data: $clcomd_contacts for node in $clcomd_contacts do if [[ -z ${CLGETPVID[${node%%\.*}]} ]] then : Get disks from $node print "$0()[$LINENO]($SECONDS): $CLRSH \"$node\" $HACSPOC/clgetpvid $ALL" >>$CLMGR_TMPLOG # Always log commands CLGETPVID[${node%%\.*}]=$($CLRSH "$node" "$HACSPOC/clgetpvid $ALL" 2>>$CLMGR_TMPLOG ) print "$0()[$LINENO]($SECONDS): $CLRSH \"$node\" $HACSPOC/clgetpvid RC: $?" >>$CLMGR_TMPLOG # Always log commands fi print -- "${CLGETPVID[${node%%\.*}]}" |\ while IFS=: read dname dpvid concurrent ecm size rem do if [[ _$dpvid == $pvid ]]; then properties[SIZE$INDEX]=$size properties[CONCURRENT$INDEX]=false if [[ $concurrent == "C" ]]; then properties[CONCURRENT$INDEX]=true fi properties[ENHANCED_CONCURRENT_MODE$INDEX]=false if [[ $ecm == "Y" ]]; then properties[ENHANCED_CONCURRENT_MODE$INDEX]=true fi break fi done print "$0()[$LINENO]($SECONDS): $CAA_CLRSH \"$node\" /usr/sbin/lquerypv -C $name" >>$CLMGR_TMPLOG # Always log commands querypv=$($CAA_CLRSH "$node" /usr/sbin/lquerypv -C $name 2>>$CLMGR_TMPLOG) print "$0()[$LINENO]($SECONDS): lquerypv RC: $?; querypv == \"$querypv\"" >>$CLMGR_TMPLOG # Always log command result if [[ $querypv != +([0-9]) ]]; then : If the first retrieval failed, try it one more time print "$0()[$LINENO]($SECONDS): $CLRSH \"$node\" /usr/sbin/lquerypv -C $name" >>$CLMGR_TMPLOG # Always log commands querypv=$($CLRSH "$node" /usr/sbin/lquerypv -C $name 2>>$CLMGR_TMPLOG) print "$0()[$LINENO]($SECONDS): lquerypv RC: $?; querypv == \"$querypv\"" >>$CLMGR_TMPLOG # Always log command result [[ $querypv != +([0-9]) ]] && querypv=0 fi print "$0()[$LINENO]($SECONDS): $CAA_CLRSH \"$node\" \"[[ -x /usr/sbin/gsclvmd ]]; echo \$?\"" >>$CLMGR_TMPLOG # Always log commands gsclvmd=$($CAA_CLRSH "$node" "[[ -x /usr/sbin/gsclvmd ]]; echo \$?" 2>>$CLMGR_TMPLOG) print "$0()[$LINENO]($SECONDS): gsclvmd exists, and is executable" >>$CLMGR_TMPLOG # Always log command result if [[ gsclvmd != +([0-9]) ]]; then : If the first retrieval failed, try it one more time print "$0()[$LINENO]($SECONDS): $CLRSH \"$node\" \"[[ -x /usr/sbin/gsclvmd ]]; echo \$?\"" >>$CLMGR_TMPLOG # Always log commands gsclvmd=$($CLRSH "$node" "[[ -x /usr/sbin/gsclvmd ]]; echo \$?" 2>>$CLMGR_TMPLOG) print "$0()[$LINENO]($SECONDS): gsclvmd exists, and is executable" >>$CLMGR_TMPLOG # Always log command result [[ gsclvmd != +([0-9]) ]] && gsclvmd=0 fi if [[ -z ${properties[CONCURRENT$INDEX]} ]]; then # : The ones that LVM says are concurrent capable # if (( 1 == querypv )); then properties[CONCURRENT$INDEX]="C" properties[ENHANCED_CONCURRENT_MODE$INDEX]="N" # : Otherwise, if the group services CLVM daemon is : present, pretty much anything can be used in a : concurrent volume group # elif (( 0 == gsclvmd )); then properties[CONCURRENT$INDEX]="C" properties[ENHANCED_CONCURRENT_MODE$INDEX]="Y" # : Anything else cannot be used : in a concurrent volume group # else properties[CONCURRENT$INDEX]="N" properties[ENHANCED_CONCURRENT_MODE$INDEX]="N" fi fi # : If the stack indicates we are only listing disks, and this is : not a full blown query, we already have the necessary data and : do not need to collect any more. This provides a performance : improvement. # if [[ $CLMGR_STACK == *KLIB_HACMP_list_physical_volume* ]] then (( INDEX++ )) [[ $INDEX == *0 ]] && (( INDEX++ )) continue fi : Find out if the disk is SCSI Persistent Reserve Type 7H capable clpr_verifycap $name 2>>$CLMGR_TMPLOG typeset -i rc_cap=$? if (( $rc_cap == 0 ));then properties[SCSIPR_CAPABLE$INDEX]="Yes" elif (( $rc_cap == 1 ));then properties[SCSIPR_CAPABLE$INDEX]="No" else properties[SCSIPR_CAPABLE$INDEX]="Unknown" fi # # It is necessary to set ODMDIR here for the case where # ODMDIR has been redirected to a set of temporary ODMs # restored from a snapshot. If we do not do this, then # lsdev will fail due to not being able to find the PdDv # ODM file. # [[ -z $dname ]] && dname=$name print -- "$0()[$LINENO]($SECONDS): $CLRSH \"$node\" ODMDIR=/etc/objrepos /usr/sbin/lsdev -l $dname -F \"type##description##status\"" >>$CLMGR_TMPLOG # Always log commands DEVDATA=$($CLRSH "$node" ODMDIR=/etc/objrepos /usr/sbin/lsdev -l $dname -F "type##description##status" 2>>$CLMGR_TMPLOG) print "$0()[$LINENO]($SECONDS): lsdev RC: $?; DEVDATA == \"$DEVDATA\"" >>$CLMGR_TMPLOG # Always log command result : Attempt to calculate available disk space print "$0()[$LINENO]($SECONDS): $CLRSH \"$node\" LC_ALL=C /usr/sbin/lqueryvg -Atp $name" >>$CLMGR_TMPLOG # Always log commands DISK_DATA=$($CLRSH "$node" LC_ALL=C /usr/sbin/lqueryvg -Atp $name 2>$TMPDIR/KHgpva.lqueryvg.$$.$name) print "$0()[$LINENO]($SECONDS): lqueryVG RC: $?" >>$CLMGR_TMPLOG # Always log command result typeset FREE_PPS=${DISK_DATA##*Free PPs:*([[:space:]])} FREE_PPS=${FREE_PPS%%$NL*} typeset PP_SIZE=${DISK_DATA##*PP Size:*([[:space:]])} PP_SIZE=${PP_SIZE%%$NL*} if [[ $FREE_PPS == +([0-9]) && $PP_SIZE == +([0-9]) ]] then typeset -i idx=0 PP_SIZE_MB=1 : Calculate physical partition size: 2 to the $PP_SIZE power for (( idx=0; idx<$PP_SIZE; idx++ )); do (( PP_SIZE_MB *= 2 )) done : Convert PP Size to MB (( PP_SIZE_MB = PP_SIZE_MB / 1024 )) (( PP_SIZE_MB = PP_SIZE_MB /1024 )) (( properties[AVAILABLE$INDEX] = $FREE_PPS * $PP_SIZE_MB )) elif grep -qi "is not assigned" $TMPDIR/KHgpva.lqueryvg.$$.$name then : We could not determine available size. Return the bulk size. properties[AVAILABLE$INDEX]=${properties[SIZE$INDEX]} else : We could not determine available size even though the : disk is in a volume group. Return a null value. properties[AVAILABLE$INDEX]= fi break done # End of the clcomd contacts loop fi if [[ -n $DEVDATA ]]; then properties[TYPE$INDEX]=${DEVDATA%%##*} DEVDATA=${DEVDATA#*##} properties[DESCRIPTION$INDEX]=${DEVDATA%%##*} DEVDATA=${DEVDATA#*##} properties[STATUS$INDEX]=${DEVDATA%%##*} fi (( INDEX++ )) [[ $INDEX == *0 ]] && (( INDEX++ )) done # End of the common disks loop : Remove the temporary files rm -f $TMPDIR/KHgpva.lqueryvg.$$.* fi #========================================================== : If any searches/filters were specified, handle them now #========================================================== if (( $rc == RC_SUCCESS && ${#queries[*]} > 0 )); then CL=$LINENO search_properties queries properties rc=$? fi (( $rc == RC_SUCCESS )) && CL=$LINENO prune_indexes properties #======================================================================= : 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' \ "query physical_volume -h" "PHYSICAL VOLUME:" "$CLMGR_PROGNAME" 1>&2 fi #=========================================================== : If execution gets this far with no detected errors, then : it was a success. Set the return code accordingly. #=========================================================== (( rc == RC_UNKNOWN )) && rc=$RC_SUCCESS log_return_msg "$rc" "$0()" "$LINENO" return $? } # End of "KLIB_HACMP_get_physical_volume_attributes()" #============================================================================ # # Name: list_tiebreakers # # Description: Lists any/all potential tiebreaker disks. Borrows the logic # from the pick list in the split/merge policy configuration # SMIT panel. # # Inputs: nodes Optional. One or more nodes to perform this # query on, defaulting to all cluster nodes. # desired_disks Optional. One or more disks to explicitly # look for and return. # common_disks Required. A reference to a hash variable # that is used to return the disks that are # found. # remote_node Required. A reference to a string variable # that is used to return the name of the node # used to query the disk information, if and # only if that node is not the local node. # # 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, above, for the standard return # code values/meanings for clmgr. # #============================================================================ function list_tiebreakers { . $HALIBROOT/log_entry "$0()" "$CL" : INPUTS: $* typeset nodes=$1 typeset desired_disks=$2 nameref common_disks=$3 nameref remote_node=$4 [[ $CLMGR_LOGGING == 'med' ]] && set +x # Only trace param values #=================================== # Declare and initialize variables #=================================== typeset PVDATA="" node="" hs_check="" nodelist="" last_good_disk="" typeset line="" skip="" pvid="" rest="" local_hdisk_name="" if [[ " $nodes " == *\ $LOCAL_NODE\ * ]]; then node=$LOCAL_NODE PVDATA=$(CL=$LINENO list_disks) else for node in $nodes; do PVDATA=$(CL=$LINENO list_disks "$node") if [[ -n $PVDATA ]]; then remote_node=$node break fi done fi # : Check for hyperswap present in the environment # if whence lspprc > /dev/null 2>&1 then hs_check=TRUE fi # : List free disks that can function as a tie breaker # cllspvids -P ${nodes// /,} |\ while read line; do [[ $line != *\(* ]] && break # : For each line from cllspvids, pick up the PVID # print "$line" | read skip pvid rest pvid=${pvid#\(} pvid=${pvid%\)} [[ -n ${common_disks[_$pvid]} ]] && continue # : Get the local disk name # # : Display a line if its the same disk as a previously displayed disk, : or its a new disk that supports a reserve policy of PR_exclusive # if [[ $last_good_disk == $pvid ]] then continue # same disk, different name else local_hdisk_name=$(clodmget -q "attribute = pvid and value like ${pvid}*" -f name -n CuAt) if [[ -n $hs_check ]] && \ lspprc -p $local_hdisk_name >/dev/null 2>&1 then # : Skip hyperswap enabled disks # continue else # : This one should be good # last_good_disk=$pvid typeset name="" cand_pvid="" vg="" uuid="" rest="" print -- "$PVDATA" |\ while read name cand_pvid vg uuid rest do [[ $pvid == $cand_pvid ]] && break done if [[ -n $desired_disks ]]; then typeset disk="" typeset -i KEEP_DISK=0 for disk in ${desired_disks//,/ }; do if [[ ":$pvid:$name:$uuid:" == *:$disk:* ]] then KEEP_DISK=1 break fi done if (( KEEP_DISK )); then common_disks[_$pvid]="$node:$name:$vg:$uuid" fi else common_disks[_$pvid]="$node:$name:$vg:$uuid" fi fi fi done log_return_msg "$rc" "$0()" "$LINENO" return $? } # End of "list_tiebreakers()" #============================================================================ # # 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_get_physical_volume_attributes.sh =head1 SYNOPSIS clmgr query physical_volume \ [ [,,...] ] \ [ NODES=[,,...] ] \ [ TYPE={available|all|tiebreaker} ] NOTE: "node" may be either a node name, or a network- resolvable name (i.e. hostname or IP address). NOTE: "disk" may be either a device name (e.g. "hdisk0") or a PVID (e.g. "00c3a28ed9aa3512"). NOTE: the alias for "physical_volumes" is "pv". =head1 DESCRIPTION This function examines the list of specified nodes (or IP addresses), and attempts to contact each node through clcomd to obtain an appropriate listing of the physical volumes on that system. Those lists are compared, and only the physical volumes that are common across all the specified nodes/hosts (all nodes in a cluster are used if a cluster is defined) are returned. =head1 ARGUMENTS 1. DISKS [OPTIONAL] [string] The label or PVID of one or more disks (comma or space separated) that are to be queried. 2. properties [REQUIRED] [hash ref] A properties/atributes return array. 3. nodes [OPTIONAL] [string] A list of nodes to query, defaulting to all. 4. TYPE [OPTIONAL] [set] The type of disks to list, from the set: available (only unused disks are listed) all (lists disks even if they are currently in use) tiebreaker (disks that are suitable for tiebreaker usage) =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 #==============================================================================