#!/bin/sh
#
# Copyright (c) 2013-2014 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
#
# Support: www.windriver.com
#
# Purpose: This resource agent manages File System Service
#
# RA Spec:
#
# http://www.opencf.org/cgi-bin/viewcvs.cgi/specs/ra/resource-agent-api.txt?rev=HEAD
#
#######################################################################
# Initialization:

: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs

#######################################################################

#######################################################################

usage() {
    cat <<UEND

usage: $0 (start|stop|status|reload|monitor|validate-all|meta-data)

$0 manages the File System as an HA resource

   The 'start'......  operation starts the service.
   The 'stop'.......  operation stops the service.
   The 'reload'.....  operation stops and then starts the service.
   The 'status'.....  operation checks the status of the service.
   The 'monitor'....  operation indicates the in-service status of the service.
   The 'validate-all' operation reports whether the parameters are valid.
   The 'meta-data'... operation reports the meta-data information.

UEND
}

#######################################################################

meta_data() {

cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="nfsserver-mgmt">
<version>1.0</version>

<longdesc lang="en">
 This OCF Compliant Resource Agent makes sure the nfs server is in the
 correct state.
</longdesc>

<shortdesc lang="en">
Makes sure the NFS Server is in the correct state.
</shortdesc>

<parameters>
<parameter name="exports" required="1">
<longdesc lang="en">List of exports that should not be exported anymore</longdesc>
<shortdesc lang="en">List of exports</shortdesc>
<content type="string" default=""/>
</parameter>

<parameter name="mounts" required="1">
<longdesc lang="en">List of mounts that should not be mounted anymore</longdesc>
<shortdesc lang="en">List of mounts</shortdesc>
<content type="string" default=""/>
</parameter>
</parameters>

<actions>
<action name="start"        timeout="10s" />
<action name="stop"         timeout="130s" />
<action name="monitor"      timeout="10s" interval="30s" />
<action name="meta-data"    timeout="10s" />
<action name="validate-all" timeout="10s" />
</actions>
</resource-agent>
END
   return ${OCF_SUCCESS}
}

nfs_server_mgmt_validate() {
    check_binary service
    check_binary grep
    check_binary cat
    check_binary exportfs
    check_binary fuser
    check_binary mount
    check_binary umount
    check_binary logger
    return ${OCF_SUCCESS}
}

nfs_server_mgmt_status() {
    return ${OCF_NOT_RUNNING}
}

nfs_server_mgmt_monitor () {
    return ${OCF_NOT_RUNNING}
}

check_exportfs () {
    local CLIENTSPEC_DIR=$1
    local rc

    OLD_IFS="${IFS}"
    IFS=":"
    STR_ARRAY=( $CLIENTSPEC_DIR )
    IFS="${OLD_IFS}"

    CLIENTSPEC=${STR_ARRAY[0]}
    DIR=${STR_ARRAY[1]}

    cat /proc/fs/nfsd/exports | grep "${CLIENTSPEC}" | grep "${DIR}" > /dev/null 2>&1 
    rc=$?
    if [ ${rc} -eq 0 ]
    then
        return 1
    fi

    exportfs | grep "${CLIENTSPEC}" | grep "${DIR}" > /dev/null 2>&1
    rc=$?
    if [ ${rc} -eq 0 ]
    then
        return 1
    fi

    return 0
}

do_nfs_restart () {
    while true
    do
        ocf_log info "NFS Server restart"
        service nfsserver restart
        ocf_log info "NFS Server restart complete"

        service nfsserver status | grep stopped > /dev/null 2>&1 || {
            ocf_log info "NFS Server is now running"
            return ${OCF_SUCCESS}
        }

        ocf_log error "NFS Server still not running"
        sleep 5
    done
}

do_umount () {
    local DEV_DIR=$1

    OLD_IFS="${IFS}"
    IFS=":"
    STR_ARRAY=( $DEV_DIR )
    IFS="${OLD_IFS}"

    DEV=${STR_ARRAY[0]}
    DIR=${STR_ARRAY[1]}

    mount | grep "${DEV}" | grep "${DIR}" > /dev/null 2>&1 || {
        ocf_log info "${DEV} ${DIR} not mounted"
        return ${OCF_SUCCESS}
    }

    ocf_log info "umount on ${DEV} ${DIR}"
    umount ${DEV} ${DIR} > /dev/null 2>&1

    while true
    do
        mount | grep "${DEV}" | grep "${DIR}" > /dev/null 2>&1 || {
            ocf_log info "unmounted ${DEV} ${DIR} successfully"
            return ${OCF_SUCCESS}
        }
        
        if fuser -KILL -m -k ${DIR}
        then
            ocf_log info "Processes killed using ${DEV} ${DIR}"
        else
            ocf_log info "No processes using ${DEV} ${DIR}"
        fi

        ocf_log info "umount force on ${DEV} ${DIR}"
        umount -f ${DEV} ${DIR} > /dev/null 2>&1

        sleep 2

        mount | grep "${DEV}" | grep "${DIR}" > /dev/null 2>&1 || {
            ocf_log info "unmounted ${DEV} ${DIR} successfully"
            return ${OCF_SUCCESS}
        }
        
        do_nfs_restart
    done

    return ${OCF_SUCCESS}
}

nfs_server_mgmt_start () {
    service nfsserver status | grep stopped > /dev/null 2>&1 || {
        ocf_log info "NFS Server is running"
        return ${OCF_SUCCESS}
    }

    ocf_log error "NFS Server not running, restarting"
    do_nfs_restart
    return $?
}

nfs_server_mgmt_stop () {
    local need_nfs_restart=0
    local rc

    # Make sure exports are stopped...
    while IFS=',' read -ra CLIENTSPEC_DIRS
    do
        for CLIENTSPEC_DIR in "${CLIENTSPEC_DIRS[@]}"
        do
            check_exportfs ${CLIENTSPEC_DIR}
            rc=$?
            if [ ${rc} -eq 1 ]
            then
                ocf_log info "export ${CLIENTSPEC_DIR} found"
                let need_nfs_restart=1
            fi
        done
    done <<< "${OCF_RESKEY_exports}"

    if [ ${need_nfs_restart} -ne 0 ]
    then
        do_nfs_restart
        rc=$?
        if [ ${rc} -ne ${OCF_SUCCESS} ]
        then
            return ${rc}
        fi
    fi

    # Make sure mounts are not mounted.
    while IFS=',' read -ra MOUNTS
    do
        for MOUNT in "${MOUNTS[@]}"
        do
            do_umount ${MOUNT}
        done
    done <<< "${OCF_RESKEY_mounts}"

    return ${OCF_SUCCESS}
}

nfs_server_mgmt_reload () {
    local rc

    nfs_server_mgmt_stop
    rc=$?
    if [ $rc -eq ${OCF_SUCCESS} ] 
    then
        nfs_server_mgmt_start
        rc=$?
        if [ $rc -eq ${OCF_SUCCESS} ] 
        then
            ocf_log info "NFS Server Managment reloaded"
        fi
    fi

    if [ ${rc} -ne ${OCF_SUCCESS} ] 
    then
        ocf_log info "NFS Server Managment reload failed (rc=${rc})"
    fi

    return ${rc}
}

case ${__OCF_ACTION} in
    meta-data)   meta_data
                 exit ${OCF_SUCCESS}
                 ;;
    usage|help)  usage
                 exit ${OCF_SUCCESS}
                 ;;
esac

# Anything except meta-data and help must pass validation
nfs_server_mgmt_validate || exit $?

case ${__OCF_ACTION} in
    start)        nfs_server_mgmt_start
                  ;;
    stop)         nfs_server_mgmt_stop
                  ;;
    status)       nfs_server_mgmt_status
                  ;;
    reload)       nfs_server_mgmt_reload
                  ;;
    monitor)      nfs_server_mgmt_monitor
                  ;;
    validate-all) nfs_server_mgmt_validate
                  ;;
    *)            usage
                  exit ${OCF_ERR_UNIMPLEMENTED}
                  ;;
esac