diff --git a/utils/fenced/local-force-unmount b/utils/fenced/local-force-unmount new file mode 100755 index 00000000..9d97a79b --- /dev/null +++ b/utils/fenced/local-force-unmount @@ -0,0 +1,35 @@ +#!/usr/bin/bash + +echo_fail() { + echo "$@" > /dev/stderr + exit 1 +} + +rid="$SCOUTFS_FENCED_REQ_RID" + +# +# Look for a local mount with the rid to fence. Typically we'll at +# least find the mount with the server that requested the fence that +# we're processing. But it's possible that mounts are unmounted +# before, or while, we're running. +# +mnts=$(findmnt -l -n -t scoutfs -o TARGET) || \ + echo_fail "findmnt -t scoutfs failed" > /dev/stderr + +for mnt in $mnts; do + mnt_rid=$(scoutfs statfs -p "$mnt" -s rid) || \ + echo_fail "scoutfs statfs $mnt failed" + + if [ "$mnt_rid" == "$rid" ]; then + umount -f "$mnt" || \ + echo_fail "umout -f $mnt" + + exit 0 + fi +done + +# +# If the mount doesn't exist on this host then it can't access the +# devices by definition and can be considered fenced. +# +exit 0 diff --git a/utils/fenced/scoutfs-fenced b/utils/fenced/scoutfs-fenced new file mode 100755 index 00000000..2037de38 --- /dev/null +++ b/utils/fenced/scoutfs-fenced @@ -0,0 +1,94 @@ +#!/usr/bin/bash + +message_output() +{ + printf "[%s] %s\n" "$(date '+%F %T.%N')" "$@" +} + +error_message() +{ + message_output "$@" >> /dev/stderr +} + +error_exit() +{ + error_message "$@, exiting" + exit 1 +} + +log_message() +{ + message_output "$@" >> /dev/stdout +} + +# restart if we catch hup to re-read the config +hup_restart() +{ + log_message "caught SIGHUP, restarting" + exec "$@" +} +trap hup_restart SIGHUP + +# defaults +SCOUTFS_FENCED_CONFIG_FILE=${SCOUTFS_FENCED_CONFIG_FILE:-/etc/scoutfs/scoutfs-fenced.conf} +SCOUTFS_FENCED_DELAY=2 +#SCOUTFS_FENCED_RUN +#SCOUTFS_FENCED_RUN_ARGS + +test -n "$SCOUTFS_FENCED_CONFIG_FILE" || \ + error_exit "SCOUTFS_FENCED_CONFIG_FILE isn't set" +test -r "$SCOUTFS_FENCED_CONFIG_FILE" || \ + error_exit "SCOUTFS_FENCED_CONFIG_FILE isn't readable file" + +log_message "reading config file $SCOUTFS_FENCED_CONFIG_FILE" + +. "$SCOUTFS_FENCED_CONFIG_FILE" || \ + error_exit "error sourcing $SCOUTFS_FENCED_CONFIG_FILE as bash script" + +for conf in "${!SCOUTFS_FENCED_@}"; do + log_message " config var $conf=${!conf}" +done + +test -n "$SCOUTFS_FENCED_RUN" || \ + error_exit "SCOUTFS_FENCED_RUN must be set" +test -x "$SCOUTFS_FENCED_RUN" || \ + error_exit "SCOUTFS_FENCED_RUN '$SCOUTFS_FENCED_RUN' isn't executable" + +# +# main loop watching for fence request across all filesystems +# + +while sleep $SCOUTFS_FENCED_DELAY; do + for fence in /sys/fs/scoutfs/*/fence/*; do + # catches unmatched regex when no dirs + if [ ! -d "$fence" ]; then + continue + fi + + # skip requests that have been handled + if [ $(cat "$fence/fenced") == 1 -o $(cat "$fence/error") == 1 ]; then + continue + fi + + srv=$(basename $(dirname $(dirname $fence))) + rid="$(cat $fence/rid)" + ip="$(cat $fence/ipv4_addr)" + reason="$(cat $fence/reason)" + + log_message "server $srv fencing rid $rid at IP $ip for $reason" + + # export _REQ_ vars for run to use + export SCOUTFS_FENCED_REQ_RID="$rid" + export SCOUTFS_FENCED_REQ_IP="$ip" + + $run $SCOUTFS_FENCED_RUN_ARGS + rc=$? + if [ "$rc" != 0 ]; then + log_message "server $srv fencing rid $rid saw error status $rc from $run" + echo 1 > "$fence/error" + continue + fi + + echo 1 > "$fence/fenced" + done +done