#!/bin/ksh93 # ALTRAN_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # Copyright (C) Altran ACT S.A.S. 2017,2018,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/events/utils/cl_export_fs.sh 1.1.6.5 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 1990,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 # @(#) 8153ed6 43haes/usr/sbin/cluster/events/utils/cl_export_fs.sh, 726, 2147A_aha726, Nov 23 2021 10:21 AM #================================================ # The following, commented line enforces coding # standards when this file is edited via vim. #================================================ # vim:tabstop=4:shiftwidth=4:expandtab:smarttab #================================================ # # COMPONENT_NAME: EVENTUTILS # # FUNCTIONS: none # # ORIGINS: 27 # ############################################################################### # # Name: primary # # Return the first entry in a list. # # Returns: # 0 - Success # # Arguments: list of strings # # Environment: None # ############################################################################### primary( ) { echo ${1:-} } ############################################################################### # # Name: secondary # # Returns all entries in a list except for the first. # # Returns: # 0 - Success # # Arguments: list of strings # # Environment: None # ############################################################################### secondary( ) { [[ -n "${1:-}" ]] && shift echo "${@:-}" } ############################################################################### # # Name: cl_export_fs # # Given a list of filesystems, NFS export them so NFS clients can # continue to work. # # Returns: # 0 - Success # 1 - Any runtime errors (unable to export, startsrc failures) # 2 - Incorrect number of arguments was passed. # # Arguments: hostname of host given root access, # list of filesystems to export via nfsv3, # list of filesystems to export via nfsv4 # # Environment: PATH, VERBOSE_LOGGING # ############################################################################### typeset PROGNAME=${0##*/} export PATH="$(/usr/es/sbin/cluster/utilities/cl_get_path all)" if [[ $VERBOSE_LOGGING == "high" ]]; then set -x version='%I%' fi . /usr/es/sbin/cluster/events/utils/cl_nfs_utils HOST="$1" EXPORT_V3="$2" EXPORT_V4="$3" STATUS=0 integer LIMIT=60 WAIT=1 TRY=0 PROC_RES=false # : If JOB_TYPE is set, and it does not equal to "GROUP", then : we are processing for process_resources # if [[ ${JOB_TYPE:-0} != 0 && $JOB_TYPE != "GROUP" ]]; then PROC_RES=true fi set -u EXPFILE="/usr/es/sbin/cluster/etc/exports" if (( $# < 2 || $# > 3 )) then cl_echo 10103 "Usage: $PROGNAME 'hostname_given_root_access' 'v3_exports' [ 'v4_exports' ]\n" $PROGNAME exit 2 fi # The following code handles migration. In 5.4.0 and earlier the nfs export # version was specified in the HACMP exports file. Starting in 5.4.1 it # became a property of the resource group. In order to make these two # methods coexist in a backwards compatible manner, if the resource group has # no NFSv4 exports configured, then get the version information from the # HACMP exports file. DARE_EVENT=reconfig_resource_acquire # : Check memory to see if NFSv4 exports have been configured. # export_v4=${EXPORT_V4:-${EXPORT_FILESYSTEM_V4:-}} if [[ -z $export_v4 && ${EVENT_NAME:-$DARE_EVENT} == $DARE_EVENT ]] then # : During DARE operations, these variables only represent the exports : that are changing. So look it up from the ODM to make sure. # export_v4=$(clodmget -q "name=EXPORT_FILESYSTEM_V4 AND group=$GROUPNAME" -f value -n HACMPresource) fi # : If we do not have NFSv4 exports configured, then determine : the protocol versions from the HACMP exports file. # if [[ -z $export_v4 && -r $EXPFILE ]] then export_v3= for fs in $EXPORT_V3 do # : Get the export file for the filesystem from the exports file. : Only look at the part of the line preceding comments. # getline_exports $fs export_line=$cl_exports_data # : The line is of the format: filesystem -option1,option2,... : This will give "option1 option2 ..." # options=$(echo $export_line | awk '{ for (i=2; i<=NF; i++) printf $i " "; print "" }' | \ cut -d- -f2- | tr ',' ' ') # : Each option can be of the format name=value, or just name. : We only care about the vers option. # # : Have we seen the vers option? # vers_missing=1 # : Loop through all of the export options for this export. # for option in $options do case $option in vers=*) vers_missing=0 # : Merge in the vers option. # case $option in *2*) export_v3="$export_v3 $fs" ;; *3*) export_v3="$export_v3 $fs" ;; esac case $option in *4*) export_v4="$export_v4 $fs" ;; esac ;; esac done # : If we did not find the vers option, then NFSv3 is the default. # (( vers_missing )) && export_v3="$export_v3 $fs" done EXPORT_V3=$export_v3 EXPORT_V4=$export_v4 fi KERNEL_BITS=$(/usr/sbin/bootinfo -K) subsystems="nfsd rpc.mountd" [[ -n $EXPORT_V4 ]] && subsystems="nfsrgyd $subsystems" # : Special processing for cross mounts of EFS keys : The overmount of /var/efs must be removed prior : to stopping or restarting NFS, since the SRC : operations will attempt to check the EFS enablement. # mounted_info=$(mount | grep -w /var/efs) if [[ -n $mounted_info ]] then # : Check to see if /var/efs is overmounted # print -- "$mounted_info" | read IP_label mounted mounted_over rest if [[ $mounted_over == "/var/efs" ]] then # : Yes, /var/efs is overmounted. Check to see if we did it - if : there is a resource group that does this. # rg_name=$(clodmget -q "name like 'EXPORT_FILESYSTEM*' and value = '$mounted'" -f group -n HACMPresource) if [[ -n $rg_name ]] && [[ -n $(clodmget -q "group = '$rg_name' and name = 'MOUNT_FILESYSTEM' and value = '/var/efs;${mounted}'" HACMPresource) ]] && [[ -n $(clodmget -q "group = '$rg_name' and name = 'SERVICE_LABEL' and value = '$IP_label'" HACMPresource) ]] then # : Yes, there is a resource group that overmounts /var/efs. : Check to see if its served by a different node. # LC_ALL=C host $IP_label | read skip skip IP_addr rest if [[ -n $IP_addr ]] && ifconfig -a | ! grep -qw ${IP_addr%,} then # : At this point, we know that currently /var/efs is : overmounted by an NFS mount not served from this : node. So, forcably unmount the NFS overmount on : /var/efs. # unmount -f /var/efs if [[ -d ${mounted} ]] then # : Under normal processing, the file system ${mounted} : is already present on this node, ready for the local : overmount to replace the remotely served overmount : Copy its contents to /var/efs, so that there is : something useful there until that local overmount : can take place. # cp -pR ${mounted}/* /var/efs # # The knowledgable & experienced reader will realize # at this point that there is still a window between # the umount and the copy. However, without this step, # any further NFS or SRC operations will hang. # fi fi fi fi fi # : Kill and restart everything in \"$subsystems\" # for subsystem in $subsystems ; do # : Kill $subsystem, and restart it below # #check for nfsd subsystem.if it is in inoperative state,start the nfsd subsystem. #nfs4smctl administers revocation of NFS version 4 State and /etc/xtab file contains #entries for directories that are currently exported. if [[ $subsystem == "nfsd" ]] && [[ $KERNEL_BITS == "64" && -x /usr/sbin/nfs4smctl ]] && [[ ! -s /etc/xtab ]] then if clcheck_server $subsystem then startsrc -s $subsystem rc=$? if (( $rc == 0 )) then sleep 3 subsys_state=$(LC_ALL=C lssrc -s $subsystem | tail +2) fi if (( $rc != 0 )) || ! print -- "$subsys_state" | grep -qw "active" then cl_log 10100 "$PROGNAME: Unable to start $subsystem via SRC.\n" $PROGNAME $subsystem STATUS=1 exit $STATUS fi fi # : nfsv4 daemon not stopped due to existing mounts : Turn on NFSv4 grace periods and ignore any errors. # ODMDIR=/etc/objrepos chnfs -I -g on -x 1 else # : Friendly stop of $subsystem # LC_ALL=C lssrc -s $subsystem | tail +2 | grep -qw 'active' && stopsrc -s $subsystem # : Now, wait for $subsystem to die # for (( TRY=0 ; $TRY < $LIMIT ; TRY++ )) do subsys_state=$(LC_ALL=C lssrc -s $subsystem | tail +2) if print -- "$subsys_state" | grep -qw "inoperative" then [[ $VERBOSE_LOGGING == "high" ]] && set -x subsys_state="inoperative" break else sleep $WAIT fi set +x # don't fill up trace log with loop passes done [[ $VERBOSE_LOGGING == "high" ]] && set -x if [[ $subsys_state != "inoperative" ]] then # : Friendly stop of $subsystem has not worked. : Trying a more forceful method. # stopsrc -cs $subsystem for (( TRY=0 ; $TRY < $LIMIT ; TRY++ )) do subsys_state=$(LC_ALL=C lssrc -s $subsystem | tail +2) if print -- "$subsys_state" | grep -qw "inoperative" then [[ $VERBOSE_LOGGING == "high" ]] && set -x subsys_state="inoperative" break else sleep $WAIT fi set +x # don't fill up trace log with loop passes done [[ $VERBOSE_LOGGING == "high" ]] && set -x fi # : If stopsrc has failed to stop $subsystem, : use a real kill on the daemon # ps -eo comm,pid | grep -w "$subsystem" | grep -vw grep | read skip subsys_pid rest [[ $subsys_pid == +([0-9]) ]] && kill $subsys_pid # : If $subsystem has been stopped, : start it back up again. # if clcheck_server $subsystem then if [[ $subsystem == "nfsd" ]] && [[ $KERNEL_BITS == "64" && -x /usr/sbin/nfs4smctl ]] then # : Turn on NFSv4 grace periods and ignore any errors. # ODMDIR=/etc/objrepos chnfs -I -g on -x 1 fi # : Start $subsystem back up again # startsrc -s $subsystem rc=$? if (( $rc == 0 )) then sleep 3 subsys_state=$(LC_ALL=C lssrc -s $subsystem | tail +2) fi if (( $rc != 0 )) || ! print -- "$subsys_state" | grep -qw "active" then cl_log 10100 "$PROGNAME: Unable to start $subsystem via SRC.\n" $PROGNAME $subsystem STATUS=1 exit $STATUS fi else # : $subsystem refuses to die. This will probably leave NFS unusable # cl_log 10631 "$PROGNAME: Unable to stop and restart $subsystem\n" $PROGNAME $subsystem STATUS=1 exit $STATUS fi fi done # : Set the NFSv4 "nfsroot" parameter. This must be set prior to any : NFS exports that use the "exname" option, and cannot be set to a new : value if any "exname" exports already exist. This is normally done : at IPL, but rc.nfs is not run at boot when HACMP is installed. # [[ -n "$EXPORT_V4" ]] && eval "$(sed -ne '/^# Begin data management/,/^# End data management/p' /etc/rc.nfs)" hasrv= if [[ -z "${STABLE_STORAGE_PATH:-}" ]] then query="name=STABLE_STORAGE_PATH AND group=$GROUPNAME" STABLE_STORAGE_PATH=$(odmget -q "$query" HACMPresource | sed -n 's/^[ ]*value = "\(.*\)"/\1/p') fi if [[ -z "$STABLE_STORAGE_PATH" ]] then STABLE_STORAGE_PATH=/var/adm/nfsv4.hacmp/$GROUPNAME fi if [[ -z "${STABLE_STORAGE_COOKIE:-}" ]] then query="name=STABLE_STORAGE_COOKIE AND group=$GROUPNAME" STABLE_STORAGE_COOKIE=$(odmget -q "$query" HACMPresource | sed -n 's/^[ ]*value = "\(.*\)"/\1/p') fi if [[ -n $GROUPNAME ]] then SERVICE_LABEL=$(odmget -q "name = SERVICE_LABEL and group = $GROUPNAME" HACMPresource | sed -n '/value =/s/^.*"\(.*\)".*/\1/p') fi primary=$(primary $SERVICE_LABEL) secondary=$(secondary $SERVICE_LABEL) nfs_node_state= # : Determine if grace periods are enabled # if ps -eo 'args' | grep -w nfsd | grep -qw -- '-gp on' ; then gp=on else gp=off fi # : We can use an NFSv4 node if grace periods are enabled, we are running a : 64-bit kernel, and the nfs4smctl command exists. # if [[ $gp == "on" && $KERNEL_BITS == "64" && -x /usr/sbin/nfs4smctl ]] then hasrv=$primary else rm -f $STABLE_STORAGE_PATH/* 2> /dev/null fi # : If we have NFSv4 exports, then we need to configure our NFS node so that : we can use stable storage. Note, NFS only supports this functionality in : its 64-bit kernels. # if [[ -n $EXPORT_V4 && -n $hasrv ]] then # : Get the stable storage cookie that is stored in the stable storage and : see if it matches. # stable_storage_cookie=$(cat $STABLE_STORAGE_PATH/hacmp/stable_storage_cookie 2> /dev/null) # : Are we using temporary stable storage? or is the stable storage stale? # if [[ "$STABLE_STORAGE_PATH" == "/var/adm/nfsv4.hacmp/$GROUPNAME" || "$STABLE_STORAGE_COOKIE" != "$stable_storage_cookie" ]] then # : Remove the temporary or stale stable storage if it is : not already in use. # cl_nfs4smctl -Q -N $GROUPNAME case $? in 1) # Runtime error (ENOENT) # The NFS node is not registered, so we should delete this # temporary stable storage since it could be stale. rm -f $STABLE_STORAGE_PATH/* 2> /dev/null # Update the stable storage cookie file mkdir -p $STABLE_STORAGE_PATH/hacmp echo $STABLE_STORAGE_COOKIE > $STABLE_STORAGE_PATH/hacmp/stable_storage_cookie ;; 0) # SUCCESS # The NFS node is already registered, continue using the # temporary stable storage (i.e., do nothing). ;; esac fi cl_RMupdate resource_acquiring NFSv4_Node $PROGNAME nfs_node_state=acquiring # : Register an nfs node for this resource group with the stable storage. # if ! cl_nfs4smctl -R -N $GROUPNAME -P $STABLE_STORAGE_PATH -s $primary then # : Unable to register NFSv4 node. This error can be caused by the following : The stable storage is corrupt. : use lsfs -q to verify block size is printed : nfso -H enable_ha needs to be run. : This should be performed by harc.net during boot. : harc.net should have a run level 2 entry in inittab # cl_log 10101 "$PROGNAME: Unable to register NFSv4 node instance $GROUPNAME.\n" $PROGNAME $GROUPNAME cl_RMupdate resource_error NFSv4_Node $PROGNAME nfs_node_state=error STATUS=1 hasrv= EXPORT_V4= EXPORT_V3= fi # : Register additional network addresses. # for addr in $secondary do if ! cl_nfs4smctl -A -N $GROUPNAME -n $addr then cl_log 10102 "$PROGNAME: Unable to register service label $addr with NFSv4 node instance $GROUPNAME.\n" $PROGNAME $addr $GROUPNAME if (( STATUS == 0 )) then cl_RMupdate resource_error NFSv4_Node $PROGNAME nfs_node_state=error STATUS=1 fi hasrv= EXPORT_V4= EXPORT_V3= fi done fi if [[ $nfs_node_state == acquiring ]] then cl_RMupdate resource_up NFSv4_Node $PROGNAME fi ALLEXPORTS="All_exports" # : update resource manager with this action # cl_RMupdate resource_acquiring $ALLEXPORTS $PROGNAME # : Build a list of all filesystems that need to be exported, irrespective of : the protocol version. Since some filesystems may be exported with multiple : versions, remove any duplicates. # FILESYSTEM_LIST=$(echo $EXPORT_V3 $EXPORT_V4 | tr " " "\n" | sort -u) # : Loop through all of the filesystems we need to export ... # for fs in $FILESYSTEM_LIST do v3= v4= root=$HOST new_options= export_file_line= USING_EXPORTS_FILE=0 export_lines= otheroption= # : Get the export line from exportfs for this export # export_line=$(exportfs | grep "^[[:space:]]*${fs}[[:space:]]") if [[ -r $EXPFILE ]] then # : Get the export file for the filesystem from the exports file. : Only look at the part of the line preceding comments. # getline_exports $fs export_file_line=$cl_exports_data # : If the administrator provides an entry for the filesystem in the : exports file then ignore the root option that was passed in on the : command line. # [[ -n $export_file_line ]] && root= fi # : If the filesystem currently is not exported, then get the options from : the exports file. We will merge these options with options specified : through resource group attributes to produce the actual options we will : provide to exportfs. # if [[ -z $export_line ]] then export_line="$export_file_line" USING_EXPORTS_FILE=1 fi # : In case of multiple exports for same filesystem : Process them line by line # set +u oldifs="$IFS" IFS=$'\n'; export_lines=($export_line) IFS="$oldifs" if [ -n "$export_lines" ]; then for exportline in "${export_lines[@]}" do # : The line is of the format: filesystem -option1,option2,... : This will give "option1 option2 ..." # old_options=$(echo $exportline | awk '{ for (i=2; i<=NF; i++) printf $i " "; print "" }' | \ cut -d- -f2- | tr ',' ' ') # : Each option can be of the format name=value, or just name. : We care about the hasrv, vers, and root options. # # : Loop through all of the export options for this export. # for option in $old_options do case $option in hasrv=*) # : Squash the hasrv option. We will provide our own later. # ;; vers=*) # : Merge in the vers option. # case $option in *2*) v3=":2:3" ;; *3*) v3=":2:3" ;; *4*) v4=":4" ;; esac ;; root=*) # : Merge in the root option. # root=$(echo $option | cut -d= -f2-) ;; *) if [[ $option == "-"* ]]; then # : Removeing the prefix - in option # option=$(echo $option | cut -d- -f 2) fi if [[ $option == $fs ]]; then # : Ignore the option contains fs. # continue fi otheroption=$(echo $option | cut -d= -f 1) if [[ $new_options == *"$otheroption"* ]]; then # : Ignore the repeated option # else # : Merge in all remaining options. # new_options="$new_options,$option" fi ;; esac done done fi set -u # : At this point, v3 and v4 are set based on what is actually exported : or what is configured to be exported in the exports file. # # Ignore version information coming from the exports file. if (( USING_EXPORTS_FILE )) then v3= v4= fi # : At this point, v3 and v4 are set based on what is actually exported. : Now add additional versions if the resource group has them configured. # for fs3 in $EXPORT_V3 do [[ "$fs" == "$fs3" ]] && v3=":2:3" && break done for fs4 in $EXPORT_V4 do [[ "$fs" == "$fs4" ]] && v4=":4" && break done # : Versions 2 and 3 are the default versions. Some versions of AIX do : not support the vers export option, so only use the option if we are : exporting a non-default value such as '4' # if [[ -n $v4 ]] then # : Strip off the leading colon # vers=$(echo "$v3$v4" | cut -d: -f2-) # : '$vers' has the versions that we want to export. Add it to our : export options. # new_options="$new_options,vers=$vers" fi if [[ -n $root ]] then # : If we have root priveliged clients, : then add them to the option list. # new_options="$new_options,root=$root" fi if [[ -n $v4 && -n $hasrv ]] then # : If this is an NFSv4 export and grace periods are enabled, : then add the hasrv option to the list. # new_options="$new_options,hasrv=$hasrv" fi # : Strip off the leading comma # new_options=$(echo "$new_options" | cut -d, -f2-) if [[ -z $new_options ]] then # : Exporting filesystem $fs with no options # exportfs -i $fs RC=$? else # : Exporting filesystem $fs with options $new_options # exportfs -i -o $new_options $fs RC=$? fi if (( $RC != 0 )) then cl_log 43 "$PROGNAME: Unable to export $fs.\n" $PROGNAME $fs if [[ $PROC_RES == true ]]; then STATUS=11 else STATUS=1 # note error and keep going fi # : update resource manager with results # cl_RMupdate resource_error $fs $PROGNAME fi done ALLNOERREXPORT="All_nonerror_exports" # : update resource manager with results # cl_RMupdate resource_up $ALLNOERREXPORT $PROGNAME exit $STATUS