summaryrefslogtreecommitdiffstats
path: root/rgmanager/src/resources/nfsserver.sh.in
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 07:52:36 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 07:52:36 +0000
commit7de03e4e519705301265c0415b3c0af85263a7ac (patch)
tree29d819c5227e3619d18a67d2a5dde963b3229dbe /rgmanager/src/resources/nfsserver.sh.in
parentInitial commit. (diff)
downloadresource-agents-7de03e4e519705301265c0415b3c0af85263a7ac.tar.xz
resource-agents-7de03e4e519705301265c0415b3c0af85263a7ac.zip
Adding upstream version 1:4.13.0.upstream/1%4.13.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'rgmanager/src/resources/nfsserver.sh.in')
-rw-r--r--rgmanager/src/resources/nfsserver.sh.in611
1 files changed, 611 insertions, 0 deletions
diff --git a/rgmanager/src/resources/nfsserver.sh.in b/rgmanager/src/resources/nfsserver.sh.in
new file mode 100644
index 0000000..e7130f0
--- /dev/null
+++ b/rgmanager/src/resources/nfsserver.sh.in
@@ -0,0 +1,611 @@
+#!@BASH_SHELL@
+
+#
+# NFS Server Script. Handles starting/stopping Servand doing
+# the strange NFS stuff to get it to fail over properly.
+#
+
+LC_ALL=C
+LANG=C
+PATH=/bin:/sbin:/usr/bin:/usr/sbin
+
+V4RECOVERY="/var/lib/nfs/v4recovery"
+PROC_V4RECOVERY="/proc/fs/nfsd/nfsv4recoverydir"
+
+export LC_ALL LANG PATH
+
+. $(dirname $0)/ocf-shellfuncs
+
+# SELinux information
+which restorecon &> /dev/null && selinuxenabled &> /dev/null
+export SELINUX_ENABLED=$?
+if [ $SELINUX_ENABLED ]; then
+ export SELINUX_LABEL="$(ls -ldZ /var/lib/nfs/statd | cut -f4 -d' ')"
+fi
+
+# strip trailing / off so pattern matching will work consistently.
+while [ "${OCF_RESKEY_path#${OCF_RESKEY_path%?}}" = "/" ]
+do
+ OCF_RESKEY_path="${OCF_RESKEY_path%/}"
+done
+
+log_do()
+{
+ ocf_log debug $*
+ $* &> /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ ocf_log debug "Failed: $*"
+ fi
+ return $ret
+}
+
+
+meta_data()
+{
+ cat <<EOT
+<?xml version="1.0" ?>
+<!DOCTYPE resource-agent SYSTEM "ra-api-1-modified.dtd">
+<resource-agent name="nfsserver" version="rgmanager 2.0">
+ <version>1.0</version>
+
+ <longdesc lang="en">
+ This defines an NFS server resource. The NFS server
+ resource is useful for exporting NFSv4 file systems
+ to clients. Because of the way NFSv4 works, only
+ one NFSv4 resource may exist on a server at a
+ time. Additionally, it is not possible to use
+ the nfsserver resource when also using local instances
+ of NFS on each cluster node.
+ </longdesc>
+
+ <shortdesc lang="en">
+ This defines an NFS server resource.
+ </shortdesc>
+
+ <parameters>
+ <parameter name="name" primary="1">
+ <longdesc lang="en">
+ Descriptive name for this server. Generally, only
+ one server is ever defined per service.
+ </longdesc>
+ <shortdesc lang="en">
+ Name
+ </shortdesc>
+ <content type="string"/>
+ </parameter>
+
+ <parameter name="path" inherit="mountpoint">
+ <longdesc lang="en">
+ This is the path you intend to export. Usually, this is
+ left blank, and the mountpoint of the parent file system
+ is used. This path is passed to nfsclient resources as
+ the export path when exportfs is called.
+ </longdesc>
+ <shortdesc lang="en">
+ This is the path you intend to export.
+ </shortdesc>
+ <content type="string"/>
+ </parameter>
+
+ <parameter name="nfspath">
+ <longdesc lang="en">
+ This is the path containing shared NFS information which
+ is used for NFS recovery after a failover. This
+ is relative to the export path, and defaults to
+ ".clumanager/nfs".
+ </longdesc>
+ <shortdesc lang="en">
+ This is the path containing shared NFS recovery
+ information, relative to the path parameter.
+ </shortdesc>
+ <content type="string" default=".clumanager/nfs"/>
+ </parameter>
+
+ <parameter name="statdport">
+ <longdesc lang="en">
+ Specifies the port number used for RPC listener sockets. If
+ this option is not specified, rpc.statd chooses a random
+ ephemeral port for each listener socket. This option can be
+ used to fix the port value of its listeners when SM_NOTIFY
+ requests must traverse a firewall between
+ clients and servers.
+ </longdesc>
+ <shortdesc lang="en">
+ This is the port where rpc.statd should listen on.
+ </shortdesc>
+ <content type="integer" default=""/>
+ </parameter>
+
+ <parameter name="krbhost">
+ <longdesc lang="en">
+ This is the Kerberos hostname, which should be set according
+ to the floating IP.
+ </longdesc>
+ <shortdesc lang="en">
+ This is the Kerberos hostname.
+ </shortdesc>
+ <content type="string"/>
+ </parameter>
+
+ </parameters>
+
+ <actions>
+ <action name="start" timeout="5"/>
+ <action name="stop" timeout="5"/>
+ <action name="recover" timeout="5"/>
+
+ <action name="status" timeout="5" interval="30"/>
+ <action name="monitor" timeout="5" interval="30"/>
+
+ <action name="meta-data" timeout="5"/>
+ <action name="validate-all" timeout="30"/>
+ </actions>
+
+ <special tag="rgmanager">
+ <attributes maxinstances="1"/>
+ <child type="nfsexport" forbid="1"/>
+ <child type="nfsserver" forbid="1"/>
+ <child type="nfsclient" start="1" stop="2"/>
+ <child type="ip" start="2" stop="1"/>
+ </special>
+
+</resource-agent>
+EOT
+}
+
+
+verify_path()
+{
+ if [ -z "$OCF_RESKEY_path" ]; then
+ ocf_log err "No server path specified."
+ return $OCF_ERR_ARGS
+ fi
+
+ [ -d "$OCF_RESKEY_path" ] && return 0
+
+ ocf_log err "$OCF_RESKEY_path is not a directory"
+
+ return $OCF_ERR_ARGS
+}
+
+
+verify_nfspath()
+{
+ if [ -z "$OCF_RESKEY_nfspath" ]; then
+ echo No NFS data path specified.
+ return 1
+ fi
+
+ [ -d "$OCF_RESKEY_path" ] && return 0
+
+ # xxx do nothing for now.
+ return 0
+}
+
+
+verify_statdport()
+{
+ if [ -z "$OCF_RESKEY_statdport" ]; then
+ # this is fine, statdport is optional
+ return 0
+ fi
+
+ [ $OCF_RESKEY_statdport -gt 0 && $OCF_RESKEY_statdport -le 65535 ] && return 0
+
+ ocf_log err "$OCF_RESKEY_statdport is not a valid port number"
+
+ return $OCF_ERR_ARGS
+}
+
+
+verify_all()
+{
+ verify_path || return 1
+ verify_nfspath || return 1
+ verify_statdport || return 1
+
+ return 0
+}
+
+
+nfs_daemons()
+{
+ declare oper
+ declare val
+
+ case $1 in
+ start)
+ ocf_log info "Starting NFS daemons"
+ if [ -z "$OCF_RESKEY_krbhost" ]; then
+ /etc/init.d/nfs start
+ rv=$?
+ else
+ unshare -u @BASH_SHELL@ -c "hostname $OCF_RESKEY_krbhost; /etc/init.d/nfs start"
+ rv=$?
+ unshare -u @BASH_SHELL@ -c "hostname $OCF_RESKEY_krbhost; /etc/init.d/rpcgssd start"
+ if [ $rv -ne 0 ]; then
+ ocf_log err "Failed to start rpcgssd"
+ return $OCF_ERR_GENERIC
+ fi
+ unshare -u @BASH_SHELL@ -c "hostname $OCF_RESKEY_krbhost; /etc/init.d/rpcidmapd start"
+ if [ $rv -ne 0 ]; then
+ ocf_log err "Failed to start rpcidmapd"
+ return $OCF_ERR_GENERIC
+ fi
+ fi
+
+ if [ $rv -ne 0 ]; then
+ ocf_log err "Failed to start NFS daemons"
+ return $OCF_ERR_GENERIC
+ fi
+
+ ocf_log debug "NFS daemons are running"
+ return $OCF_SUCCESS
+ ;;
+ stop)
+ ocf_log info "Stopping NFS daemons"
+ if [ -n "$OCF_RESKEY_krbhost"]; then
+ if ! /etc/init.d/rpcidmapd stop; then
+ ocf_log err "Failed to stop rpcidmapd"
+ return $OCF_ERR_GENERIC
+ fi
+ if ! /etc/init.d/rpcgssd stop; then
+ ocf_log err "Failed to stop rpcgssd"
+ return $OCF_ERR_GENERIC
+ fi
+ fi
+
+ if ! /etc/init.d/nfs stop; then
+ ocf_log err "Failed to stop NFS daemons"
+ return $OCF_ERR_GENERIC
+ fi
+
+ ocf_log debug "NFS daemons are stopped"
+
+ return $OCF_SUCCESS
+ ;;
+ status|monitor)
+ declare recoverydir="$OCF_RESKEY_path/$OCF_RESKEY_nfspath/v4recovery"
+ val=$(cat $PROC_V4RECOVERY)
+
+ [ "$val" = "$recoverydir" ] || ocf_log warning \
+ "NFSv4 recovery directory is $val instead of $recoverydir"
+ /etc/init.d/nfs status
+ if [ $? -ne 0 ]; then
+ ocf_log err "NFS is not running"
+ return $OCF_NOT_RUNNING
+ fi
+ /etc/init.d/rpcgssd status
+ if [ $? -ne 0 ]; then
+ ocf_log err "rpcgssd is not running"
+ return $OCF_NOT_RUNNING
+ fi
+ /etc/init.d/rpcidmapd status
+ if [ $? -ne 0 ]; then
+ ocf_log err "rpcidmapd is not running"
+ return $OCF_NOT_RUNNING
+ fi
+
+ ocf_log debug "NFS daemons are running"
+ return $OCF_SUCCESS
+ ;;
+ esac
+}
+
+
+create_tree()
+{
+ declare fp="$OCF_RESKEY_path/$OCF_RESKEY_nfspath"
+
+ [ -d "$fp" ] || mkdir -p "$fp"
+
+ [ -d "$fp/statd" ] || mkdir -p "$fp/statd"
+ [ -d "$fp/v4recovery" ] || mkdir -p "$fp/v4recovery"
+
+ #
+ # Create our own private copy which we use for notifies.
+ # This way, we can be sure to advertise on possibly multiple
+ # IP addresses.
+ #
+ [ -d "$fp/statd/sm" ] || mkdir -p "$fp/statd/sm"
+ [ -d "$fp/statd/sm.bak" ] || mkdir -p "$fp/statd/sm.bak"
+ [ -d "$fp/statd/sm-ha" ] || mkdir -p "$fp/statd/sm-ha"
+ [ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown -R rpcuser.rpcuser "$fp/statd"
+
+ # Create if they don't exist
+ [ -f "$fp/etab" ] || touch "$fp/etab"
+ [ -f "$fp/xtab" ] || touch "$fp/xtab"
+ [ -f "$fp/rmtab" ] || touch "$fp/rmtab"
+
+ [ $SELINUX_ENABLED ] && chcon -R "$SELINUX_LABEL" "$fp"
+
+ #
+ # Generate a random state file. If this ends up being what a client
+ # already has in its list, that's bad, but the chances of this
+ # are small - and relocations should be rare.
+ #
+ dd if=/dev/urandom of=$fp/state bs=1 count=4 &> /dev/null
+ [ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown rpcuser.rpcuser "$fp/state"
+}
+
+setup_v4recovery()
+{
+ declare recoverydir="$OCF_RESKEY_path/$OCF_RESKEY_nfspath/v4recovery"
+
+ # mounts /proc/fs/nfsd for us
+ lsmod | grep -q nfsd
+ if [ $? -ne 0 ]; then
+ modprobe nfsd
+ fi
+
+ val=$(cat "$PROC_V4RECOVERY")
+
+ # Ensure start-after-start works
+ if [ "$val" = "$recoverydir" ]; then
+ return 0
+ fi
+
+ #
+ # If the value is not default, there may be another
+ # cluster service here already which has replaced
+ # the v4 recovery directory. In that case,
+ # we must refuse to go any further.
+ #
+ if [ "$val" != "$V4RECOVERY" ]; then
+ ocf_log err "NFSv4 recovery directory has an unexpected value: $val"
+ return 1
+ fi
+
+ #
+ # Redirect nfs v4 recovery dir to shared storage
+ #
+ echo "$recoverydir" > "$PROC_V4RECOVERY"
+ if [ $? -ne 0 ]; then
+ echo "Uh oh... echo failed!?"
+ fi
+
+ val="$(cat $PROC_V4RECOVERY)"
+ if [ "$val" != "$recoverydir" ]; then
+ ocf_log err "Failed to change NFSv4 recovery path"
+ ocf_log err "Wanted: $recoverydir; got $val"
+ return 1
+ fi
+
+ return 0
+}
+
+
+cleanup_v4recovery()
+{
+ #
+ # Restore nfsv4 recovery directory to default
+ #
+ echo "$V4RECOVERY" > "$PROC_V4RECOVERY"
+ return $?
+}
+
+
+is_bound()
+{
+ mount | grep -q "$1 on $2 type none (.*bind.*)"
+ return $?
+}
+
+
+setup_tree()
+{
+ declare fp="$OCF_RESKEY_path/$OCF_RESKEY_nfspath"
+
+ if is_bound $fp/statd /var/lib/nfs/statd; then
+ ocf_log debug "$fp is already bound to /var/lib/nfs/statd"
+ return 0
+ fi
+
+ mount -o bind "$fp/statd" /var/lib/nfs/statd
+ cp -a "$fp"/*tab /var/lib/nfs
+ [ $SELINUX_ENABLED ] && restorecon /var/lib/nfs
+}
+
+
+cleanup_tree()
+{
+ declare fp="$OCF_RESKEY_path/$OCF_RESKEY_nfspath"
+
+ if is_bound "$fp/statd" /var/lib/nfs/statd; then
+ log_do umount /var/lib/nfs/statd || return 1
+ else
+ ocf_log debug "$fp is not bound to /var/lib/nfs/statd"
+ fi
+
+ cp -a /var/lib/nfs/*tab "$fp"
+
+ return 0
+}
+
+start_locking()
+{
+ declare ret
+ declare statdport=""
+ [ -x /sbin/rpc.statd ] || return 1
+
+ #
+ # Synchronize these before starting statd
+ #
+ cp -f /var/lib/nfs/statd/sm-ha/* /var/lib/nfs/statd/sm 2> /dev/null
+ cp -f /var/lib/nfs/statd/sm/* /var/lib/nfs/statd/sm-ha 2> /dev/null
+
+ if pidof rpc.statd &> /dev/null; then
+ ocf_log debug "rpc.statd is already running"
+ return 0
+ fi
+
+ if [ -n "$OCF_RESKEY_statdport" ]; then
+ statdport="-p $OCF_RESKEY_statdport"
+ fi
+
+ #
+ # Set this resrouce script as the callout program. We are evil.
+ # In cases where we want to preserve lock information, this is needed
+ # because we can't do the "copy" that we do on the down-state...
+ #
+ ocf_log info "Starting rpc.statd"
+ rm -f /var/run/sm-notify.pid
+ rpc.statd -H $0 -d $statdport
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ ocf_log err "Failed to start rpc.statd"
+ return $ret
+ fi
+ touch /var/lock/subsys/nfslock
+ return $ret
+}
+
+
+terminate()
+{
+ declare pids
+ declare i=0
+
+ while : ; do
+ pids=$(pidof $1)
+ [ -z "$pids" ] && return 0
+ kill $pids
+ sleep 1
+ ((i++))
+ [ $i -gt 3 ] && return 1
+ done
+}
+
+
+killkill()
+{
+ declare pids
+ declare i=0
+
+ while : ; do
+ pids=$(pidof $1)
+ [ -z "$pids" ] && return 0
+ kill -9 $pids
+ sleep 1
+ ((i++))
+ [ $i -gt 3 ] && return 1
+ done
+}
+
+stop_process()
+{
+ declare process=$1
+
+ ocf_log info "Stopping $process"
+ if terminate $process; then
+ ocf_log debug "$process is stopped"
+ else
+ if killkill $process; then
+ ocf_log debug "$process is stopped"
+ else
+ ocf_log debug "Failed to stop $process"
+ return 1
+ fi
+ fi
+ return 0
+}
+
+stop_locking()
+{
+ ret=0
+
+ # sm-notify can prevent umount of /var/lib/nfs/statd if
+ # it is still trying to notify unresponsive clients.
+ stop_process sm-notify
+ if [ $? -ne 0 ]; then
+ ret=1
+ fi
+
+ stop_process rpc.statd
+ if [ $? -ne 0 ]; then
+ ret=1
+ fi
+
+ return $ret
+}
+
+
+case $1 in
+start)
+ # Check for and source configuration file
+ ocf_log info "Starting NFS Server $OCF_RESKEY_name"
+ create_tree || exit 1
+ setup_tree || exit 1
+ setup_v4recovery || exit 1
+
+ start_locking
+ nfs_daemons start
+ rv=$?
+ if [ $rv -eq 0 ]; then
+ ocf_log info "Started NFS Server $OCF_RESKEY_name"
+ exit 0
+ fi
+
+ ocf_log err "Failed to start NFS Server $OCF_RESKEY_name"
+ exit $rv
+ ;;
+
+status|monitor)
+ nfs_daemons status
+ exit $?
+ ;;
+
+stop)
+ if ! nfs_daemons stop; then
+ ocf_log err "Failed to stop NFS Server $OCF_RESKEY_name"
+ exit $OCF_ERR_GENERIC
+ fi
+
+ # Copy the current notify list into our private area
+ ocf_log debug "Copying sm files for future notification..."
+ rm -f /var/lib/nfs/statd/sm-ha/* &> /dev/null
+ cp -f /var/lib/nfs/statd/sm/* /var/lib/nfs/statd/sm-ha &> /dev/null
+
+ stop_locking || exit 1
+ cleanup_v4recovery
+ cleanup_tree || exit 1
+ exit 0
+ ;;
+
+add-client)
+ ocf_log debug "$0 $1 $2 $3"
+ touch /var/lib/nfs/statd/sm/$2
+ touch /var/lib/nfs/statd/sm-ha/$2
+ exit 0
+ ;;
+
+del-client)
+ ocf_log debug "$0 $1 $2 $3"
+ touch /var/lib/nfs/statd/sm/$2
+ rm -f /var/lib/nfs/statd/sm-ha/$2
+ exit 0
+ ;;
+
+recover|restart)
+ $0 stop || exit $OCF_ERR_GENERIC
+ $0 start || exit $OCF_ERR_GENERIC
+ exit 0
+ ;;
+
+meta-data)
+ meta_data
+ exit 0
+ ;;
+
+validate-all)
+ verify_all
+ exit $?
+ ;;
+*)
+ echo "usage: $0 {start|stop|status|monitor|restart|recover|add-client|del-client|meta-data|validate-all}"
+ exit $OCF_ERR_UNIMPLEMENTED
+ ;;
+esac
+
+exit 0