2015-07-01 11:32:35 +03:00
#!/bin/sh
# This is an example CTDB NFS callout script for Ganesha. It is based
# on the last version of 60.ganesha shipped with CTDB. As such, it
# does not try to monitor RPC services that were not monitored by
# 60.ganesha - this might be a useful improvement. It has also not
# been properly tested.
# You should check your version of NFS Ganesha to see if it ships with
# a newer callout.
# To use this:
#
2017-02-22 12:37:14 +03:00
# * Set CTDB_NFS_CALLOUT in your CTDB configuration to point to (a
# copy of) this script, making sure it is executable.
2015-07-01 11:32:35 +03:00
#
2017-02-22 12:37:14 +03:00
# * Create a new directory alongside the nfs-checks.d directory, for
2024-03-04 06:28:11 +03:00
# example nfs-checks-ganesha.d. Install 20.nfs_ganesha.check and
# 21.nfs.check in this directory. Symlink to any other check files
# from nfs-checks.d that should still be used, such as
2017-02-22 12:37:14 +03:00
# 00.portmapper.check. Set CTDB_NFS_CHECKS_DIR to point to this new
# directory of check files.
2016-05-04 21:03:29 +03:00
#
# * It is recommended, but not required, to install the grace_period
# script (usually shipped in a utils package for NFS-Ganesha) to
# /usr/bin/grace_period
2015-07-01 11:32:35 +03:00
# I (Martin Schwenke) hereby relicense all of my contributions to this
# callout (and, previously, to 60.ganesha) to a license compatible
# with NFS Ganesha (right now this is LGPLv3, but I'm flexible).
# There may be other contributions to be considered for relicensing,
# particularly those in commit 28cbe527d47822f870e8252495ab2a1c8fddd12f.
######################################################################
# Exit on 1st error
set -e
2023-07-06 01:20:37 +03:00
die()
{
echo "$1"
exit 1
}
# Shared directory, typically on a cluster filesystem, that will
# contain the NFS-Ganesha state
if [ -z "$CTDB_NFS_SHARED_STATE_DIR" ]; then
die "$0: CTDB_NFS_SHARED_STATE_DIR is not set"
fi
if [ ! -d "$CTDB_NFS_SHARED_STATE_DIR" ]; then
t="$CTDB_NFS_SHARED_STATE_DIR" # Readability, below
die "$0: CTDB_NFS_SHARED_STATE_DIR=${t} not found"
fi
state_fs=$(findmnt -n --target "$CTDB_NFS_SHARED_STATE_DIR" -o FSTYPE)
case "$state_fs" in
glusterfs | gpfs)
:
;;
fuse.glusterfs)
state_fs="glusterfs"
;;
*)
d="$CTDB_NFS_SHARED_STATE_DIR"
die "$0: filesystem type \"${state_fs}\" is not supported for ${d}"
;;
esac
# Always put NFS-Ganesha state in its own subdirectory
state_dir="${CTDB_NFS_SHARED_STATE_DIR}/ganesha"
2016-04-29 05:18:05 +03:00
2024-03-27 06:24:09 +03:00
# Location of exports file
nfs_exports_file="${CTDB_NFS_EXPORTS_FILE:-/etc/ganesha/ganesha.conf}"
2016-05-10 17:50:10 +03:00
# To change the following, edit the default values below. Do not set
# these - they aren't configuration variables, just hooks for testing.
nfs_service="${CTDB_NFS_SERVICE:-nfs-ganesha}"
procfs=${PROCFS_PATH:-/proc}
2017-02-22 06:38:45 +03:00
case "$state_fs" in
2017-02-22 06:25:55 +03:00
gpfs)
GANRECDIR="/var/lib/nfs/ganesha"
;;
glusterfs)
2017-02-22 06:38:45 +03:00
host=$(hostname)
2023-07-06 01:20:37 +03:00
NODESTATEDIR="${state_dir}/${host}"
GANSTATEDIR="${state_dir}/.noderefs"
2017-02-22 06:25:55 +03:00
NODESTATELN="$GANSTATEDIR/$host"
;;
2016-05-03 09:53:07 +03:00
esac
2015-07-01 11:32:35 +03:00
##################################################
2024-03-05 06:26:19 +03:00
usage()
2015-07-01 11:32:35 +03:00
{
2017-02-22 06:38:45 +03:00
_c=$(basename "$0")
2017-02-22 06:25:55 +03:00
cat <<EOF
2015-07-01 11:32:35 +03:00
usage: $_c { shutdown | startup }
2024-03-04 05:52:10 +03:00
$_c { stop | start | check | stats } nfs
2023-07-06 06:37:03 +03:00
$_c { releaseip | takeip } <iface> <ip> <maskbits>
2015-07-01 11:32:35 +03:00
$_c { monitor-list-shares }
EOF
2024-03-05 06:26:19 +03:00
exit 1
2015-07-01 11:32:35 +03:00
}
##################################################
# Basic service stop and start
2024-03-05 06:26:19 +03:00
basic_stop()
2015-07-01 11:32:35 +03:00
{
2017-02-22 06:25:55 +03:00
case "$1" in
2015-07-01 11:32:35 +03:00
nfs)
2017-02-22 06:25:55 +03:00
service "$nfs_service" stop
;;
2015-07-01 11:32:35 +03:00
*)
2017-02-22 06:25:55 +03:00
usage
2024-03-05 06:26:19 +03:00
;;
2017-02-22 06:25:55 +03:00
esac
2015-07-01 11:32:35 +03:00
}
2024-03-05 06:26:19 +03:00
basic_start()
2015-07-01 11:32:35 +03:00
{
2017-02-22 06:25:55 +03:00
case "$1" in
2015-07-01 11:32:35 +03:00
nfs)
2017-02-22 06:25:55 +03:00
service "$nfs_service" start
;;
2015-07-01 11:32:35 +03:00
*)
2017-02-22 06:25:55 +03:00
usage
2024-03-05 06:26:19 +03:00
;;
2017-02-22 06:25:55 +03:00
esac
2015-07-01 11:32:35 +03:00
}
##################################################
# "stop" and "start" options for restarting
2024-03-05 06:26:19 +03:00
service_stop()
2015-07-01 11:32:35 +03:00
{
2024-03-05 06:26:19 +03:00
case "$1" in
2015-07-01 11:32:35 +03:00
nfs)
2024-03-05 06:26:19 +03:00
basic_stop "nfs"
;;
2015-07-01 11:32:35 +03:00
nlockmgr)
2024-03-05 06:26:19 +03:00
# Do nothing - used by statd-callout
:
;;
2015-07-01 11:32:35 +03:00
*)
2024-03-05 06:26:19 +03:00
usage
;;
esac
2015-07-01 11:32:35 +03:00
}
2024-03-05 06:26:19 +03:00
service_start()
2015-07-01 11:32:35 +03:00
{
2017-02-22 06:25:55 +03:00
case "$1" in
2015-07-01 11:32:35 +03:00
nfs)
2017-02-22 06:25:55 +03:00
basic_start "nfs"
;;
2015-07-01 11:32:35 +03:00
nlockmgr)
2017-02-22 06:25:55 +03:00
# Do nothing - used by statd-callout
:
;;
2015-07-01 11:32:35 +03:00
*)
2017-02-22 06:25:55 +03:00
usage
2024-03-05 06:26:19 +03:00
;;
2017-02-22 06:25:55 +03:00
esac
2015-07-01 11:32:35 +03:00
}
##################################################
# Nitty gritty - monitoring and IP handling
2016-05-04 22:16:27 +03:00
# Check that a symlink exists, create it otherwise.
# Usage: check_ln <TARGET> <LINK>
2024-03-05 06:26:19 +03:00
check_ln()
2016-05-04 22:16:27 +03:00
{
2024-03-05 06:26:19 +03:00
if [ ! -L "${2}" ]; then
2017-02-22 06:25:55 +03:00
rm -vrf "${2}"
else
_t=$(readlink "${2}")
2024-03-05 06:26:19 +03:00
if [ "$_t" != "${1}" ]; then
2017-02-22 06:25:55 +03:00
rm -v "${2}"
fi
fi
# This is not an "else". It also re-creates the link if it was
# removed above!
if [ ! -e "${2}" ]; then
ln -sfv "${1}" "${2}"
fi
2016-05-04 22:16:27 +03:00
}
2016-04-29 04:58:30 +03:00
# Return 'active' if the shared filesystem is accessible.
2024-03-05 06:26:19 +03:00
get_cluster_fs_state()
2015-07-01 11:32:35 +03:00
{
2024-03-05 06:44:32 +03:00
case "$state_fs" in
2017-02-22 06:25:55 +03:00
gpfs)
/usr/lpp/mmfs/bin/mmgetstate | awk 'NR == 4 { print $3 }'
;;
glusterfs)
# Since we're past create_ganesha_recdirs(), we're active.
echo "active"
;;
*)
echo "File system $state_fs not supported"
exit 1
;;
esac
2015-07-01 11:32:35 +03:00
}
2024-03-05 06:26:19 +03:00
create_ganesha_recdirs()
2015-07-01 11:32:35 +03:00
{
2024-03-05 06:44:32 +03:00
case "$state_fs" in
2017-02-22 06:25:55 +03:00
gpfs)
2023-07-06 01:20:37 +03:00
mkdir -vp "$state_dir"
check_ln "$state_dir" "$GANRECDIR"
2017-02-22 06:25:55 +03:00
;;
glusterfs)
2024-03-05 06:26:19 +03:00
[ -d /var/lib/nfs.backup ] ||
2017-02-22 06:25:55 +03:00
mv /var/lib/nfs /var/lib/nfs.backup
2017-02-22 06:38:45 +03:00
check_ln "$NODESTATEDIR" /var/lib/nfs
2017-02-22 06:25:55 +03:00
2017-02-22 06:38:45 +03:00
mkdir -p "${NODESTATEDIR}/ganesha/v4recov"
mkdir -p "${NODESTATEDIR}/ganesha/v4old"
mkdir -p "${NODESTATEDIR}/statd/sm"
mkdir -p "${NODESTATEDIR}/statd/sm.bak"
touch "${NODESTATEDIR}/state"
touch "${NODESTATEDIR}/statd/state"
2017-02-22 06:25:55 +03:00
2017-02-22 06:38:45 +03:00
mkdir -p "$GANSTATEDIR"
check_ln "$NODESTATEDIR" "$NODESTATELN"
2024-03-05 06:26:19 +03:00
for _dir in "${GANSTATEDIR}/"*; do
2017-02-22 06:44:09 +03:00
# Handle no directories case
2024-03-05 06:26:19 +03:00
if [ ! -d "$_dir" ]; then
2017-02-22 06:44:09 +03:00
break
fi
_node="${_dir##*/}" # basename
if [ "${_node}" != "${host}" ]; then
check_ln "${GANSTATEDIR}/${_node}/ganesha" \
2024-03-05 06:26:19 +03:00
"${NODESTATEDIR}/ganesha/${_node}"
2017-02-22 06:44:09 +03:00
check_ln "${GANSTATEDIR}/${_node}/statd" \
2024-03-05 06:26:19 +03:00
"${NODESTATEDIR}/statd/${_node}"
2017-02-22 06:25:55 +03:00
fi
done
;;
esac
2015-07-01 11:32:35 +03:00
}
2024-05-10 10:46:58 +03:00
is_ganesha_running()
{
# Check that NFS Ganesha is running, according to PID file
_pidfile="/var/run/ganesha/ganesha.pid"
_ganesha="ganesha.nfsd"
if ! {
read -r _pid <"$_pidfile" &&
[ "$(ps -p "$_pid" -o comm=)" = "$_ganesha" ]
} >/dev/null 2>&1; then
return 1
fi
return 0
}
2024-03-05 06:26:19 +03:00
service_check()
2015-07-01 11:32:35 +03:00
{
2017-02-22 06:25:55 +03:00
create_ganesha_recdirs
# Always succeed if cluster filesystem is not active
_cluster_fs_state=$(get_cluster_fs_state)
2024-03-05 06:26:19 +03:00
if [ "$_cluster_fs_state" != "active" ]; then
2017-02-22 06:25:55 +03:00
return 0
fi
2024-05-10 10:46:58 +03:00
if ! is_ganesha_running; then
2017-02-22 06:25:55 +03:00
echo "ERROR: NFS Ganesha not running according to PID file"
return 1
fi
2015-07-01 11:32:35 +03:00
2016-04-29 04:58:30 +03:00
return 0
2015-07-01 11:32:35 +03:00
}
2024-03-04 05:52:10 +03:00
nfs_stats()
{
_service="$1"
case "$_service" in
nfs)
timeout -v 5 ganesha_stats | grep '^Total NFSv.* ops:'
;;
*)
# This will never change, so is intentionally
# unhelpful for avoiding an unhealthy service
echo "Not implemented" >&2
exit 1
2023-07-06 01:20:37 +03:00
;;
2024-03-04 05:52:10 +03:00
esac
}
2015-07-01 11:32:35 +03:00
#-------------------------------------------------
2023-10-27 09:03:01 +03:00
grace_period()
2015-07-01 11:32:35 +03:00
{
2023-10-27 09:03:01 +03:00
_arg="$1"
2024-05-10 11:00:18 +03:00
_gp_status=0
2017-02-22 06:25:55 +03:00
if [ -x "/usr/bin/grace_period" ]; then
2024-05-10 11:00:18 +03:00
_out=$(/usr/bin/grace_period "$_arg" 2>&1) ||
_gp_status=$?
_down_msg="Error: Can't talk to ganesha service on d-bus"
2017-02-22 06:25:55 +03:00
else
2024-05-10 11:00:18 +03:00
_out=$(dbus-send \
--print-reply --system --dest=org.ganesha.nfsd \
2023-10-27 09:03:01 +03:00
/org/ganesha/nfsd/admin org.ganesha.nfsd.admin.grace \
2024-05-10 11:00:18 +03:00
string:"$_arg" 2>&1) ||
_gp_status=$?
_down_msg="Error org.freedesktop.DBus.Error.ServiceUnknown"
2017-02-22 06:25:55 +03:00
fi
2024-05-10 11:00:18 +03:00
if [ -n "$_out" ]; then
echo "$_out"
fi
if [ $_gp_status -ne 0 ]; then
# If $_out contains $_down_msg then NFS-Ganesha is
# either down or is starting, so will be in grace
# anyway.
if [ "${_out#*"${_down_msg}"}" != "$_out" ]; then
return 3 # ESRCH - No such process
fi
fi
return $_gp_status
2015-07-01 11:32:35 +03:00
}
2024-05-10 10:51:18 +03:00
grace_period_if_running()
{
_arg="$1"
if ! is_ganesha_running; then
echo "WARNING: NFS Ganesha not running according to PID file"
return 0
fi
2024-05-10 11:00:18 +03:00
_status=0
grace_period "$_arg" || _status=$?
case $_status in
3)
# Convert to success
return 0
;;
*)
return $_status
;;
esac
2024-05-10 10:51:18 +03:00
}
2023-10-27 09:07:47 +03:00
nfs_startipreallocate()
{
2024-05-10 10:51:18 +03:00
grace_period_if_running "0:"
2023-10-27 09:07:47 +03:00
}
2023-10-27 09:03:01 +03:00
nfs_releaseip()
{
_ip="$2"
# NFS-Ganesha recovery code only processes items matching $_ip
2024-05-10 10:51:18 +03:00
grace_period_if_running "2:${_ip}"
2023-10-27 09:03:01 +03:00
}
2024-03-05 06:26:19 +03:00
nfs_takeip()
2015-07-01 11:32:35 +03:00
{
2023-10-27 09:03:01 +03:00
_ip="$2"
2024-03-05 06:44:32 +03:00
case "$state_fs" in
2017-02-22 06:25:55 +03:00
glusterfs)
2023-10-27 09:03:01 +03:00
check_ln "$NODESTATEDIR" "${GANSTATEDIR}/${_ip}"
2017-02-22 06:25:55 +03:00
;;
esac
2023-10-27 09:03:01 +03:00
grace_period "5:${_ip}"
2015-07-01 11:32:35 +03:00
}
##################################################
# service init startup and final shutdown
2024-03-05 06:26:19 +03:00
nfs_shutdown()
2015-07-01 11:32:35 +03:00
{
2017-02-22 06:25:55 +03:00
basic_stop "nfs"
2015-07-01 11:32:35 +03:00
}
2024-03-05 06:26:19 +03:00
nfs_startup()
2015-07-01 11:32:35 +03:00
{
2017-02-22 06:25:55 +03:00
basic_stop "nfs" || true
2016-04-29 04:58:30 +03:00
2017-02-22 06:25:55 +03:00
create_ganesha_recdirs
2015-07-01 11:32:35 +03:00
2017-02-22 06:25:55 +03:00
basic_start "nfs"
_f="${procfs}/sys/net/ipv4/tcp_tw_recycle"
2024-03-05 06:26:19 +03:00
if [ -f "$_f" ]; then
2017-02-22 06:25:55 +03:00
echo 1 >"$_f"
fi
2015-07-01 11:32:35 +03:00
}
##################################################
# list share directories
2024-03-05 06:26:19 +03:00
nfs_monitor_list_shares()
2015-07-01 11:32:35 +03:00
{
2024-04-30 08:00:34 +03:00
# The 1st sed command prints anything after "Path = ", where
# Path is matched case-insensitively, and must be on a word
# boundary. This also deletes any semicolon-terminated items
# before Path. Each output line now starts with a value for
# Path, but may have other settings after a semicolon.
_s1='s/.*;*[[:space:]]*\<path\>[[:space:]]*=[[:space:]]*//ip'
# The 2nd sed command has 2 steps:
#
# a. Attempt to match an unquoted value not containing
# semicolon or double-quote, followed by an optional
# line-terminating semicolon or a semicolon followed by
# anything else. Keep the value and double-quote it. If
# the value was already quoted then the line will be
# unchanged. The pattern space now starts with a
# double-quoted value.
_s2a='s/^\([^";][^";]*\)[[:space:]]*\(;*[[:space:]]*$\|;.*\)/"\1"/'
# b. Finally, print the contents of double-quotes at the
# beginning of the pattern space, discarding anything
# that follows.
_s2b='s/^"\([^"][^"]*\)".*/\1/p'
sed -n -e "$_s1" "$nfs_exports_file" | sed -n -e "$_s2a" -e "$_s2b"
2015-07-01 11:32:35 +03:00
}
##################################################
2024-03-05 06:26:19 +03:00
nfs_register()
2016-04-29 05:12:33 +03:00
{
2017-02-22 06:25:55 +03:00
cat <<EOF
2016-04-29 05:12:33 +03:00
shutdown
startup
stop
start
2018-01-31 09:07:46 +03:00
check
2024-03-04 05:52:10 +03:00
stats
2023-10-27 09:07:47 +03:00
startipreallocate
2016-04-29 05:12:33 +03:00
releaseip
takeip
monitor-list-shares
EOF
}
##################################################
2015-07-01 11:32:35 +03:00
action="$1"
shift
case "$action" in
2024-03-05 06:26:19 +03:00
shutdown) nfs_shutdown ;;
startup) nfs_startup ;;
stop) service_stop "$1" ;;
start) service_start "$1" ;;
check) service_check "$1" ;;
2024-03-04 05:52:10 +03:00
stats) nfs_stats "$1" ;;
2024-03-05 06:26:19 +03:00
startipreallocate) nfs_startipreallocate ;;
releaseip) nfs_releaseip "$@" ;;
takeip) nfs_takeip "$@" ;;
2017-02-22 06:25:55 +03:00
monitor-list-shares) nfs_monitor_list_shares ;;
2024-03-05 06:26:19 +03:00
register) nfs_register ;;
monitor-pre | monitor-post)
2015-07-01 11:32:35 +03:00
# Not required/implemented
:
;;
2017-02-22 06:25:55 +03:00
*)
2015-07-01 11:32:35 +03:00
usage
2024-03-05 06:26:19 +03:00
;;
2015-07-01 11:32:35 +03:00
esac