mirror of
https://github.com/samba-team/samba.git
synced 2025-01-11 05:18:09 +03:00
4b652c1527
This is an optimisation that can cause incorrect results. If ctdbd was killed and there is a stale PID file then this will often cause "CTDB exited during initialisation". The wrapper reads the old PID from the PID file, finds the PID gone, complains and exits. It is better to drop this code and finally get this right. If ctdbd does exit early then it will take CTDB_STARTUP_TIMEOUT (default 10) seconds before the wrapper fails. That's not too bad... Signed-off-by: Martin Schwenke <martin@meltin.net> Reviewed-by: Amitay Isaacs <amitay@gmail.com>
300 lines
7.7 KiB
Bash
Executable File
300 lines
7.7 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# ctdbd wrapper - start or stop CTDB
|
|
|
|
usage ()
|
|
{
|
|
echo "usage: ctdbd_wrapper <pidfile> { start | stop }"
|
|
exit 1
|
|
}
|
|
|
|
[ $# -eq 2 ] || usage
|
|
|
|
pidfile="$1"
|
|
action="$2"
|
|
|
|
############################################################
|
|
|
|
if [ -z "$CTDB_BASE" ] ; then
|
|
export CTDB_BASE="/usr/local/etc/ctdb"
|
|
fi
|
|
|
|
. "${CTDB_BASE}/functions"
|
|
loadconfig "ctdb"
|
|
|
|
[ -n "$CTDB_SOCKET" ] && export CTDB_SOCKET
|
|
|
|
ctdbd="${CTDBD:-/usr/local/sbin/ctdbd}"
|
|
|
|
############################################################
|
|
|
|
# ctdbd_is_running()
|
|
|
|
# Check if ctdbd is running. ctdbd is only considered to running if
|
|
# the PID in the PID file is active and is called "ctdbd". Return
|
|
# true if this is the case. Print the PID regardless, since it can be
|
|
# used to kill stale processes in the session.
|
|
|
|
ctdbd_is_running ()
|
|
{
|
|
if read _pid 2>/dev/null <"$pidfile" ; then
|
|
echo "$_pid"
|
|
|
|
# This could be optimised with ps options -q and -h.
|
|
# However, -q is not generally available because it is
|
|
# fairly new and -h is not in some older distros. The
|
|
# options below are portable.
|
|
_cmd=$(ps -p "$_pid" -o comm | tail -n +2)
|
|
[ "$_cmd" = "ctdbd" ]
|
|
else
|
|
# Missing/empty PID file
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
############################################################
|
|
|
|
# If necessary, mount volatile database directory on tmpfs
|
|
dbdir_tmpfs_start ()
|
|
{
|
|
if [ -z "$CTDB_DBDIR_TMPFS_OPTIONS" ] ; then
|
|
return
|
|
fi
|
|
|
|
# Shortcut for readability
|
|
_opts="$CTDB_DBDIR_TMPFS_OPTIONS"
|
|
|
|
mkdir -p "$CTDB_DBDIR" || exit $?
|
|
|
|
# If already mounted then remount, otherwise mount
|
|
if findmnt -t tmpfs "$CTDB_DBDIR" >/dev/null ; then
|
|
mount -t tmpfs -o "remount,$_opts" none "$CTDB_DBDIR" || \
|
|
exit $?
|
|
else
|
|
mount -t tmpfs -o "$_opts" none "$CTDB_DBDIR" || exit $?
|
|
fi
|
|
}
|
|
|
|
# If necessary, unmount volatile database tmpfs directory on exit
|
|
dbdir_tmpfs_stop ()
|
|
{
|
|
if [ -z "$CTDB_DBDIR_TMPFS_OPTIONS" ] ; then
|
|
return
|
|
fi
|
|
|
|
if [ -d "$CTDB_DBDIR" ] && findmnt -t tmpfs "$CTDB_DBDIR" >/dev/null ; then
|
|
umount "$CTDB_DBDIR"
|
|
fi
|
|
}
|
|
|
|
# Only the nested function references its arguments
|
|
# shellcheck disable=SC2120
|
|
build_ctdb_options ()
|
|
{
|
|
ctdb_options=""
|
|
|
|
maybe_set ()
|
|
{
|
|
# If the given variable isn't set then do nothing
|
|
[ -n "$2" ] || return
|
|
# If a required value for the variable and it doesn't match,
|
|
# then do nothing
|
|
[ -z "$3" -o "$3" = "$2" ] || return
|
|
|
|
val="'$2'"
|
|
case "$1" in
|
|
--*) sep="=" ;;
|
|
-*) sep=" " ;;
|
|
esac
|
|
# For these options we're only passing a value-less flag.
|
|
if [ -n "$3" ] ; then
|
|
val=""
|
|
sep=""
|
|
fi
|
|
|
|
ctdb_options="${ctdb_options}${ctdb_options:+ }${1}${sep}${val}"
|
|
}
|
|
|
|
if [ -z "$CTDB_RECOVERY_LOCK" ] ; then
|
|
echo "No recovery lock specified. Starting CTDB without split brain prevention."
|
|
fi
|
|
maybe_set "--reclock" "$CTDB_RECOVERY_LOCK"
|
|
|
|
maybe_set "--pidfile" "$pidfile"
|
|
|
|
# build up ctdb_options variable from optional parameters
|
|
maybe_set "--logging" "$CTDB_LOGGING"
|
|
maybe_set "--nlist" "$CTDB_NODES"
|
|
maybe_set "--socket" "$CTDB_SOCKET"
|
|
maybe_set "--listen" "$CTDB_NODE_ADDRESS"
|
|
maybe_set "--public-addresses" "$CTDB_PUBLIC_ADDRESSES"
|
|
maybe_set "--public-interface" "$CTDB_PUBLIC_INTERFACE"
|
|
maybe_set "--dbdir" "$CTDB_DBDIR"
|
|
maybe_set "--dbdir-persistent" "$CTDB_DBDIR_PERSISTENT"
|
|
maybe_set "--dbdir-state" "$CTDB_DBDIR_STATE"
|
|
maybe_set "--event-script-dir" "$CTDB_EVENT_SCRIPT_DIR"
|
|
maybe_set "--transport" "$CTDB_TRANSPORT"
|
|
maybe_set "-d" "$CTDB_DEBUGLEVEL"
|
|
maybe_set "--notification-script" "$CTDB_NOTIFY_SCRIPT"
|
|
maybe_set "--start-as-disabled" "$CTDB_START_AS_DISABLED" "yes"
|
|
maybe_set "--start-as-stopped " "$CTDB_START_AS_STOPPED" "yes"
|
|
maybe_set "--no-recmaster" "$CTDB_CAPABILITY_RECMASTER" "no"
|
|
maybe_set "--no-lmaster" "$CTDB_CAPABILITY_LMASTER" "no"
|
|
maybe_set "--nosetsched" "$CTDB_NOSETSCHED" "yes"
|
|
maybe_set "--script-log-level" "$CTDB_SCRIPT_LOG_LEVEL"
|
|
maybe_set "--max-persistent-check-errors" "$CTDB_MAX_PERSISTENT_CHECK_ERRORS"
|
|
}
|
|
|
|
export_debug_variables ()
|
|
{
|
|
[ -n "$CTDB_DEBUG_HUNG_SCRIPT" ] && export CTDB_DEBUG_HUNG_SCRIPT
|
|
[ -n "$CTDB_EXTERNAL_TRACE" ] && export CTDB_EXTERNAL_TRACE
|
|
[ -n "$CTDB_DEBUG_LOCKS" ] && export CTDB_DEBUG_LOCKS
|
|
}
|
|
|
|
kill_ctdbd ()
|
|
{
|
|
_session="$1"
|
|
|
|
if [ -n "$_session" ] ; then
|
|
pkill -9 -s "$_session" 2>/dev/null
|
|
fi
|
|
}
|
|
|
|
############################################################
|
|
|
|
start()
|
|
{
|
|
if _session=$(ctdbd_is_running) ; then
|
|
echo "CTDB is already running"
|
|
return 0
|
|
fi
|
|
|
|
# About to start new $ctdbd. The main daemon is not running but
|
|
# there may still be other processes around, so do some cleanup.
|
|
kill_ctdbd "$_session"
|
|
|
|
dbdir_tmpfs_start
|
|
|
|
# build_ctdb_options() takes no arguments
|
|
# shellcheck disable=SC2119
|
|
build_ctdb_options
|
|
|
|
export_debug_variables
|
|
|
|
# Explicitly trying to disable core files, no other way
|
|
# shellcheck disable=SC2039
|
|
if [ "$CTDB_SUPPRESS_COREFILE" = "yes" ]; then
|
|
ulimit -c 0
|
|
else
|
|
ulimit -c unlimited
|
|
fi
|
|
|
|
# Unsupported option easily avoided by not using configuration variable
|
|
# shellcheck disable=SC2039
|
|
if [ -n "$CTDB_MAX_OPEN_FILES" ]; then
|
|
ulimit -n "$CTDB_MAX_OPEN_FILES"
|
|
fi
|
|
|
|
_d=$(dirname "$pidfile")
|
|
mkdir -p "$_d"
|
|
|
|
if [ -n "$CTDB_VALGRIND" -a "$CTDB_VALGRIND" != "no" ] ; then
|
|
if [ "$CTDB_VALGRIND" = "yes" ] ; then
|
|
ctdbd="valgrind -q --log-file=/usr/local/var/log/ctdb_valgrind ${ctdbd}"
|
|
else
|
|
ctdbd="${CTDB_VALGRIND} ${ctdbd}"
|
|
fi
|
|
ctdb_options="${ctdb_options} --valgrinding"
|
|
fi
|
|
|
|
case "$CTDB_LOGGING" in
|
|
syslog:udp|syslog:udp-rfc5424)
|
|
logger -t ctdbd "CTDB is being run with ${CTDB_LOGGING}. If nothing is logged then check your syslogd configuration"
|
|
;;
|
|
syslog|syslog:*) : ;;
|
|
file:*)
|
|
logger -t ctdbd "CTDB is being run without syslog enabled. Logs will be in ${CTDB_LOGGING#file:}"
|
|
;;
|
|
*)
|
|
logger -t ctdbd "CTDB is being run without syslog enabled. Logs will be in log.ctdb"
|
|
esac
|
|
|
|
eval "$ctdbd" "$ctdb_options" || return 1
|
|
|
|
# Wait until ctdbd has started and is ready to respond to clients.
|
|
_pid=""
|
|
_timeout="${CTDB_STARTUP_TIMEOUT:-10}"
|
|
_count=0
|
|
while [ "$_count" -lt "$_timeout" ] ; do
|
|
if $CTDB runstate first_recovery startup running >/dev/null 2>&1 ; then
|
|
return 0
|
|
fi
|
|
|
|
_count=$((_count + 1))
|
|
sleep 1
|
|
done
|
|
|
|
echo "Timed out waiting for initialisation - check logs - killing CTDB"
|
|
kill_ctdbd "$_pid"
|
|
drop_all_public_ips >/dev/null 2>&1
|
|
return 1
|
|
}
|
|
|
|
stop()
|
|
{
|
|
if ! _session=$(ctdbd_is_running) ; then
|
|
echo "CTDB is not running"
|
|
return 0
|
|
fi
|
|
|
|
$CTDB shutdown
|
|
|
|
# Wait for remaining CTDB processes to exit...
|
|
_timeout=${CTDB_SHUTDOWN_TIMEOUT:-30}
|
|
_count=0
|
|
_terminated=false
|
|
while [ "$_count" -lt "$_timeout" ] ; do
|
|
if ! pkill -0 -s "$_session" 2>/dev/null ; then
|
|
_terminated=true
|
|
break
|
|
fi
|
|
|
|
_count=$((_count + 1))
|
|
sleep 1
|
|
done
|
|
|
|
if ! $_terminated ; then
|
|
echo "Timed out waiting for CTDB to shutdown. Killing CTDB processes."
|
|
kill_ctdbd "$_session"
|
|
drop_all_public_ips >/dev/null 2>&1
|
|
|
|
sleep 1
|
|
|
|
if pkill -0 -s "$_session" ; then
|
|
# If SIGKILL didn't work then things are bad...
|
|
echo "Failed to kill all CTDB processes. Giving up."
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
dbdir_tmpfs_stop
|
|
|
|
return 0
|
|
}
|
|
|
|
############################################################
|
|
|
|
# Allow notifications for start/stop.
|
|
if [ -x "$CTDB_BASE/rc.ctdb" ] ; then
|
|
"$CTDB_BASE/rc.ctdb" "$action"
|
|
fi
|
|
|
|
case "$action" in
|
|
start) start ;;
|
|
stop) stop ;;
|
|
*)
|
|
echo "usage: $0 {start|stop}"
|
|
exit 1
|
|
esac
|