#!/bin/ksh93
#  ALTRAN_PROLOG_BEGIN_TAG
#  This is an automatically generated prolog.
#
#  Copyright (C) Altran ACT S.A.S. 2017,2021.  All rights reserved.
#
#  ALTRAN_PROLOG_END_TAG
#
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r720 src/43haes/usr/sbin/cluster/events/utils/cl_activate_nfs.sh 1.19.4.2 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 1990,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/usr/sbin/cluster/events/utils/cl_activate_nfs.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM
#
#   COMPONENT_NAME: EVENTUTILS
#
#   FUNCTIONS: nfs_mount
#
#   ORIGINS: 27
#
#
#   (C) COPYRIGHT International Business Machines Corp. 1990,1994
#   All Rights Reserved
#   Licensed Materials - Property of IBM
#   US Government Users Restricted Rights - Use, duplication or
#   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
#
###############################################################################
#
#  Name:  cl_activate_nfs
#
#  This function will NFS mount the specified filesystems.
#
#  We background the mounts instead of specifying the bg option to the mount
#  command because the standard mount command will fail if the server host is
#  not ready (i.e. has not exported the filesystem). This command will retry
#  in the background.
#
#  Note that this route assumes the filesystem is already mounted if any 
#  mounted filesystem has a matching name.
#
#  Returns:
#        0 - All filesystems passed were either mounted or mounts
#            were scheduled in the background
#        1 - One or more filesystems failed to mount
#        2 - Zero arguments were passed
#
#  Argument: Number of retries, NFS_server_host, list of filesystems to activate
#
#  Environment: VERBOSE_LOGGING, PATH
#
###############################################################################
# Including Availability metrics library file
. /usr/es/lib/ksh93/availability/cl_amlib

PROGNAME=${0##*/}
[[ "$VERBOSE_LOGGING" == "high" ]] && set -x
[[ "$VERBOSE_LOGGING" == "high" ]] && version='1.19.4.2 $Source$'

. /usr/es/sbin/cluster/events/utils/cl_nfs_utils

set -u

###############################################################################
# Name: nfs_mount
# Usage: nfs_mount tries host fs mnt
# Description:
#        Try to NFS mount the specified filesystem. 
# Arguments:
#                TRIES            - number of attempts (sleep 30 seconds between retries)
#                 HOST            - NFS server host
#                FileSystem  - filesystem to mount
#               MountPoint  - mount point
# Returns:
#                0 - success
#                1 - hit max retry count without success
#                2 - bad arg count
#
# Environment:
#        NONE
#
###############################################################################
function nfs_mount
{

    typeset PS4_TIMER="true"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    if (( $# != 4 ))
    then
        cl_echo 17 "usage: $0 tries host filesystem mountpoint\n" $0
        return 2
    fi

    #
    #        Pick up passed parameters
    #
    integer LIMIT=$1
    HOST=$2
    FileSystem=$3
    MountPoint=$4

    #
    #        First, check to see if this one is already mounted
    #
    mount | \
        while read node node_fs lcl_mount rest 
            do
                if [[ $lcl_mount == $MountPoint ]]
                then
                    cl_echo 11 "$PROGNAME: Filesystem $MountPoint already mounted.\n" $PROGNAME $MountPoint
                    return 0
                fi
            done

    vers=
    if [[ $VERSION_SOURCE == "ODM" ]] ; then
        vers=3
        for export_v4 in $EXPORT_FILESYSTEM_V4 ; do
            if [[ "$filesystem" == "$export_v4" ]] ; then
                vers=4
                break
            fi
        done
    fi

    #
    #        Pick up and, if necessary modify the mount options so that they
    #        reflect the recovery_method processing intent
    #
    OPTIONS=$(lsfs -c -v nfs | grep "^${MountPoint}:" | cut -d: -f7)
    OPTIONS=$(echo $OPTIONS | sed 's/+/:/g')

    if [[ -z $OPTIONS ]]
    then
        #
        #   If there are no mount options specified for this filesystem in
        #   /etc/filesystems, do a hard, interruptable mount
        #
        OPTIONS="hard,intr"

    elif ! print $OPTIONS | grep -q intr
    then
        #
        #   If the given options didn't include 'interruptable', make it so
        #
        OPTIONS="$OPTIONS,intr"
        #
        #   Note that if someone explicitly specified 'nointr' in the
        #   /etc/filesystems entry, that's what they're going to get
        #
    fi

    # Add the version information at the beginning so that it will override
    # version information from lsfs (i.e., /etc/filesystems).
    # Note: If an option is given twice, mount uses the first occurrence and
    # ignores the second one.
    [[ -n "$vers" ]] && OPTIONS="vers=$vers,$OPTIONS"

    #
    #   If the user specified sequential processing, override any background
    #   option from /etc/filesystems, so that the processing is totally
    #   sequential.
    #
    if [[ $METHOD == sequential ]]
    then
        OPTIONS=$(print $OPTIONS | sed 's/bg/fg/g')
        let LIMIT+=4                        # allow a few extra tries
    fi

    #
    #        Keep trying until the mount succeeds or the retry limit is reached
    #
    typeset RC
    # Format for consumption by cl_am utility
    amlog_trace $AM_NFS_ACTIVATE_BEGIN "Activating NFS|$FileSystem"
    for (( TRIES=0 ; TRIES<LIMIT ; TRIES++ ))
    do
	#
	#	Mount actually (and finally) done here
	#
	: Attempt $TRIES/$LIMIT to NFS-mount at $(date "+%h %d %H:%M:%S.000")
	mount -o "$OPTIONS" $HOST:$FileSystem $MountPoint
	RC=$?

	if (( $RC == 0 ))			# return code from mount
	then
	    #
	    #	Return after successful mount
	    #
        # Format for consumption by cl_am utility
        amlog_trace $AM_NFS_ACTIVATE_END "Activating NFS|$FileSystem"
	    return 0
	else
	    #
	    #	Mount failed
	    #
            : mount returned exit code $RC
	    if (( TRIES+1<LIMIT ))		# retries left
	    then
		#
		#   Notify of pending retry.  Note sleep below
		#
		cl_echo 18 "$PROGNAME: mount of $HOST:$FileSystem failed again, still re-trying\n" $PROGNAME $HOST $FileSystem
		sleep 30
	    fi
	fi
    done
    
    #
    #        Get here if retry limit exhausted
    #
    cl_echo 19 "$PROGNAME: Failed mount of $HOST:$FileSystem.\n" $PROGNAME $HOST $FileSystem
    # Format for consumption by cl_am utility
    amlog_err $AM_NFS_ACTIVATE_FAILURE "Activating NFS|$FileSystem"
    return 1

}



###############################################################################
#
# main starts here
#
###############################################################################

# The environment variable MOUNT_WLMCNTRL_SELFMANAGE is referred inside "mount".
# If this variable is set, few calls to wlmcntrl are skipped inside mount, which
# offers performance benefits. Hence we will export this variable if it is set
# in /etc/environment.
export eval $(grep -w '^MOUNT_WLMCNTRL_SELFMANAGE' /etc/environment)

if (( $# < 3 ))
then
   cl_echo 20 "usage: $PROGNAME attempts hostname file_systems_to_activate\n" $PROGNAME
   exit 2
fi

#
#   Pick up the first two parameters, and remove them from the argument list
#
integer ATTEMPTS=$1
HOST=$2

shift 2

#
#   What remains is the list of file systems to be mounted
#
FILELIST=$*

#
#   Sort by mount point, so that nested mounts work correctly
#
if print $FILELIST | grep -q "\;/"
then
    #
    #        For crossmounts, sort by local mount point
    #
    CROSSMOUNTS=TRUE
    MOUNTLIST=$(print $* | tr ' ' '\n'  | /bin/sort -k 1,1 -t\;)
else
    CROSSMOUNTS=FALSE
    MOUNTLIST=$(print $* | tr ' ' '\n'  | /bin/sort)
fi

#
#   update resource manager
#
ALLNFS="All_nfs_mounts"
cl_RMupdate resource_acquiring $ALLNFS $PROGNAME

#
#   Determine if parallel mounts are allowed, or sequential mounts are
#   required
#
METHOD=$(odmget -q "name=RECOVERY_METHOD AND group=$GROUPNAME" HACMPresource |
    sed -n 's/^[ 	]*value = "\(.*\)"/\1/p')

EXPORT_FILESYSTEM=$(odmget -q "name=EXPORT_FILESYSTEM AND group=$GROUPNAME" HACMPresource | sed -n 's/^[ 	]*value = "\(.*\)"/\1/p')

EXPORT_FILESYSTEM_V4=$(odmget -q "name=EXPORT_FILESYSTEM_V4 AND group=$GROUPNAME" HACMPresource | sed -n 's/^[ 	]*value = "\(.*\)"/\1/p')


# 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.
EXPFILE="/usr/es/sbin/cluster/etc/exports"

if [[ -z "$EXPORT_FILESYSTEM_V4" ]] ; then
    if [[ -r $EXPFILE ]] ; then
        # Export versions will come from the HACMP exports file.
        # Mount versions will come from /etc/filesystems.
        VERSION_SOURCE="FILES"
    else
        # Everything will end up being version 3 (by default).
        VERSION_SOURCE="DEFAULT"
    fi
else
    # The versions come from the ODM as configured through smit.
    VERSION_SOURCE="ODM"
fi

# If we don't have NFSv4 exports configured then determine the protocol
# version(s) from the HACMP exports file.
if [[ $VERSION_SOURCE == "FILES" ]]
then
    export_v3=
    export_v4=

    for fs in $EXPORT_FILESYSTEM
    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  #getline_exports updates global variable 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 didn't find the vers option, then NFSv3 is the default.
        (( vers_missing )) && export_v3="$export_v3 $fs"
    done 

    EXPORT_FILESYSTEM=$export_v3
    EXPORT_FILESYSTEM_V4=$export_v4
fi


#
#   If required NFSv4 daemon is needed but not running, start it
#
if [[ -x /usr/sbin/nfsrgyd ]] &&
    ( [[ -n "$EXPORT_FILESYSTEM_V4" ]] ||
      grep -q 'vers=4' /etc/filesystems ) &&
    ! LC_ALL=C lssrc -s nfsrgyd | grep -qw active
then
    startsrc -s nfsrgyd
fi

#
#   Process each file system to be mounted
#
for MOUNTSPEC in $MOUNTLIST
do
    #
    #        Special handling for NFS cross mounts, wherein a shared file system is
    #        accessed through NFS whether locally or remotely accessable.
    #
    if [[ $CROSSMOUNTS == TRUE ]]
    then
        #
        #   If NFS cross mounts are used, the shared file system is always NFS
        #   mounted on top of some other local filesystem, even if the shared
        #   disk is owned by this node.  That allows moving the underlying
        #   shared file system between nodes without disrupting using
        #   applications
        #
        #   In that case, the specification is of the form
        #   
        #        /local/mount/point;/exported/file/system
        #
        #   and we'll ultimately do somethin like
        #
        #        mount this_host:/exported/file/system /local/mount/point
        #
        filesystem=${MOUNTSPEC#*";"}
        mountpoint=${MOUNTSPEC%";"*}
    else
        #
        #   If crossmounts are not used, it is assumed that the file system
        #   and mount point are the same.  E.g., we'll ultimately do something
        #   like
        #
        #        mount other_host:/common/file/system /common/file/system
        #
        filesystem=$MOUNTSPEC
        mountpoint=$MOUNTSPEC
    fi

    #
    #   Based on the recovery method - sequential or parallel - mounts are
    #   either done in the forground or the background
    #
    PS4_LOOP="$MOUNTSPEC"
    if [[ $METHOD == "sequential" ]]
    then
      nfs_mount $ATTEMPTS $HOST $filesystem $mountpoint
    else
      nfs_mount $ATTEMPTS $HOST $filesystem $mountpoint &
    fi
done

