1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-10 01:18:15 +03:00

initscript: Simpify initscript and control CTDB via new ctdbd_wrapper

Currently the initscript is very complex.  This makes it hard to read
and hard to add support for new init systems, such as systemd.

Create a wrapper called ctdbd_wrapper to be installed alongside ctdbd.
This is called by the initscript to start and stop ctdbd.  It does the
ctdbd option construct and waits until ctdbd is properly initialised
before it exits.

Signed-off-by: Martin Schwenke <martin@meltin.net>
Pair-programmed-with: Amitay Isaacs <amitay@gmail.com>

(This used to be ctdb commit e3abc7eebab5cceddc4ce7817890dd5db9be3450)
This commit is contained in:
Martin Schwenke 2013-07-09 15:22:07 +10:00
parent a86f1f109a
commit adbee6ae4e
4 changed files with 339 additions and 234 deletions

View File

@ -357,6 +357,7 @@ install: all manpages $(PMDA_INSTALL)
${INSTALLCMD} -m 440 config/ctdb.sudoers $(DESTDIR)$(etcdir)/sudoers.d/ctdb
${INSTALLCMD} -m 644 config/functions $(DESTDIR)$(etcdir)/ctdb
${INSTALLCMD} -m 755 config/statd-callout $(DESTDIR)$(etcdir)/ctdb
${INSTALLCMD} -m 755 config/ctdbd_wrapper $(DESTDIR)$(sbindir)
${INSTALLCMD} -m 755 config/events.d/00.ctdb $(DESTDIR)$(etcdir)/ctdb/events.d
${INSTALLCMD} -m 755 config/events.d/01.reclock $(DESTDIR)$(etcdir)/ctdb/events.d
${INSTALLCMD} -m 755 config/events.d/10.interface $(DESTDIR)$(etcdir)/ctdb/events.d

View File

@ -1,294 +1,133 @@
#!/bin/sh
# Start and stop CTDB (Clustered TDB daemon)
#
##############################
# ctdb: Starts the clustered tdb daemon
#
# chkconfig: - 90 01
#
# description: Starts and stops the clustered tdb daemon
# pidfile: /var/run/ctdb/ctdbd.pid
# chkconfig: - 90 01
#
# description: Starts and stops CTDB
# pidfile: /var/run/ctdb/ctdbd.pid
# config: /etc/sysconfig/ctdb
### BEGIN INIT INFO
# Provides: ctdb
# Required-Start: $network
# Required-Stop: $network
# Default-Stop:
# Default-Start: 3 5
# Required-Start: $local_fs $syslog $network
# Required-Stop: $local_fs $syslog $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: start and stop ctdb service
# Description: initscript for the ctdb service
# Description: Start and stop CTDB (Clustered TDB daemon)
### END INIT INFO
# Source function library.
if [ -f /etc/init.d/functions ] ; then
# Red Hat
. /etc/init.d/functions
elif [ -f /etc/rc.d/init.d/functions ] ; then
# Red Hat
. /etc/rc.d/init.d/functions
fi
[ -f /etc/rc.status ] && {
elif [ -f /etc/rc.status ] ; then
# SUSE
. /etc/rc.status
rc_reset
LC_ALL=en_US.UTF-8
}
if [ -f /lib/lsb/init-functions ] ; then
elif [ -f /lib/lsb/init-functions ] ; then
# Debian
. /lib/lsb/init-functions
fi
# Avoid using root's TMPDIR
unset TMPDIR
[ -z "$CTDB_BASE" ] && {
export CTDB_BASE="/etc/ctdb"
}
[ -n "$CTDB_BASE" ] || export CTDB_BASE="/etc/ctdb"
. $CTDB_BASE/functions
loadconfig network
loadconfig ctdb
. "${CTDB_BASE}/functions"
loadconfig "network"
loadconfig "ctdb"
# check networking is up (for redhat)
[ "$NETWORKING" = "no" ] && exit 0
if [ "$NETWORKING" = "no" ] ; then
exit 0
fi
detect_init_style
export CTDB_INIT_STYLE
ctdbd=${CTDBD:-/usr/sbin/ctdbd}
pidfile="/var/run/ctdb/ctdbd.pid"
ctdbd="${CTDBD:-/usr/sbin/ctdbd}"
ctdbd_wrapper="${CTDBD_WRAPPER:-/usr/sbin/ctdbd_wrapper}"
pidfile="${CTDB_PIDFILE:-/var/run/ctdb/ctdbd.pid}"
if [ "$CTDB_VALGRIND" = "yes" ]; then
init_style="valgrind"
else
init_style="$CTDB_INIT_STYLE"
fi
############################################################
build_ctdb_options () {
maybe_set () {
# If the 2nd arg is null then return - don't set anything.
# Else if the 3rd arg is set and it doesn't match the 2nd arg
# then return
[ -z "$2" -o \( -n "$3" -a "$3" != "$2" \) ] && return
val="'$2'"
case "$1" in
--*) sep="=" ;;
-*) sep=" " ;;
esac
# For these options we're only passing a value-less flag.
[ -n "$3" ] && {
val=""
sep=""
}
CTDB_OPTIONS="${CTDB_OPTIONS}${CTDB_OPTIONS:+ }${1}${sep}${val}"
}
[ -z "$CTDB_RECOVERY_LOCK" ] && {
echo "No recovery lock specified. Starting CTDB without split brain prevention"
}
maybe_set "--reclock" "$CTDB_RECOVERY_LOCK"
mkdir -p $(dirname "$pidfile")
maybe_set "--pidfile" "$pidfile"
# build up CTDB_OPTIONS variable from optional parameters
maybe_set "--logfile" "$CTDB_LOGFILE"
maybe_set "--nlist" "$CTDB_NODES"
maybe_set "--socket" "$CTDB_SOCKET"
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 "--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 "--lvs --single-public-ip" "$CTDB_LVS_PUBLIC_IP"
maybe_set "--script-log-level" "$CTDB_SCRIPT_LOG_LEVEL"
maybe_set "--log-ringbuf-size" "$CTDB_LOG_RINGBUF_SIZE"
maybe_set "--syslog" "$CTDB_SYSLOG" "yes"
maybe_set "--max-persistent-check-errors" "$CTDB_MAX_PERSISTENT_CHECK_ERRORS"
}
export_debug_variables ()
start()
{
export CTDB_DEBUG_HUNG_SCRIPT CTDB_EXTERNAL_TRACE CTDB_DEBUG_LOCKS
}
echo -n "Starting ctdbd service: "
set_retval() {
return $1
}
wait_until_ready () {
_timeout="${1:-10}" # default is 10 seconds
_count=0
while ! ctdb runstate first_recovery startup running >/dev/null 2>&1 ; do
if [ $_count -ge $_timeout ] ; then
return 1
fi
sleep 1
_count=$(($_count + 1))
done
}
start() {
echo -n $"Starting ctdbd service: "
ctdb ping >/dev/null 2>&1 && {
echo $"CTDB is already running"
return 0
}
# About to start new $ctdbd. The ping above has failed and any
# new $ctdbd will destroy the Unix domain socket, so any processes
# that aren't yet completely useless soon will be... so kill
# them.
pkill -9 -f "$ctdbd"
build_ctdb_options
export_debug_variables
if [ "$CTDB_SUPPRESS_COREFILE" = "yes" ]; then
ulimit -c 0
else
ulimit -c unlimited
fi
case $init_style in
valgrind)
eval valgrind -q --log-file=/var/log/ctdb_valgrind \
$ctdbd --valgrinding "$CTDB_OPTIONS"
RETVAL=$?
echo
;;
case "$CTDB_INIT_STYLE" in
suse)
eval startproc $ctdbd "$CTDB_OPTIONS"
RETVAL=$?
startproc \
"$ctdbd_wrapper" "$pidfile" "start"
rc_status -v
;;
redhat)
eval $ctdbd "$CTDB_OPTIONS"
daemon --pidfile "$pidfile" \
"$ctdbd_wrapper" "$pidfile" "start"
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/ctdb || RETVAL=1
return $RETVAL
;;
debian)
eval start-stop-daemon --start --quiet --background \
--exec $ctdbd -- "$CTDB_OPTIONS"
eval start-stop-daemon --start --quiet --background --exec \
"$ctdbd_wrapper" "$pidfile" "start"
;;
esac
}
stop()
{
echo -n "Shutting down ctdbd service: "
case "$CTDB_INIT_STYLE" in
suse)
"$ctdbd_wrapper" "$pidfile" "stop"
rc_status -v
;;
redhat)
"$ctdbd_wrapper" "$pidfile" "stop"
RETVAL=$?
;;
esac
if [ $RETVAL -eq 0 ] ; then
if ! wait_until_ready ; then
RETVAL=1
echo "Timed out waiting for initialisation - killing CTDB"
pkill -9 -f $ctdbd >/dev/null 2>&1
fi
fi
case $init_style in
suse)
set_retval $RETVAL
rc_status -v
;;
redhat)
[ $RETVAL -eq 0 ] && success || failure
echo
;;
esac
return $RETVAL
}
stop() {
echo -n $"Shutting down ctdbd service: "
pkill -0 -f $ctdbd || {
echo -n " Warning: ctdbd not running ! "
case $init_style in
suse)
rc_status -v
;;
redhat)
echo ""
;;
esac
return 0
}
ctdb shutdown >/dev/null 2>&1
RETVAL=$?
count=0
while pkill -0 -f $ctdbd ; do
sleep 1
count=$(($count + 1))
[ $count -gt 30 ] && {
echo -n $"killing ctdbd "
pkill -9 -f $ctdbd
pkill -9 -f $CTDB_BASE/events.d/
}
done
# make sure all ips are dropped, pfkill -9 might leave them hanging around
drop_all_public_ips >/dev/null 2>&1
rm -f "$pidfile"
case $init_style in
suse)
# re-set the return code to the recorded RETVAL in order
# to print the correct status message
set_retval $RETVAL
rc_status -v
;;
redhat)
[ $RETVAL -eq 0 ] && success || failure
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ctdb
echo ""
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ctdb
return $RETVAL
;;
debian)
"$ctdbd_wrapper" "$pidfile" "stop"
log_end_msg $?
;;
esac
return $RETVAL
}
restart() {
restart()
{
stop
start
}
# Given that CTDB_VALGRIND is a debug option we don't support the pid
# file. We just do a quick and dirty hack instead. Otherwise we just
# end up re-implementing each distro's pidfile support...
check_status_valgrind ()
{
if pkill -0 -f "valgrind.*${ctdbd}" ; then
echo "ctdbd is running under valgrind..."
return 0
else
echo "ctdbd is not running"
return 1
fi
}
check_status ()
{
# Backward compatibility. When we arrange to pass --pidfile to
# ctdbd we also create the directory that will contain it. If
# that directory is missing then we don't use the pidfile to check
# status.
# status. Note that this probably won't work if
# $CTDB_VALGRIND="yes" but this doesn't need full backward
# compatibility because it is a debug option.
if [ -d $(dirname "$pidfile") ] ; then
_pf_opt="-p $pidfile"
else
_pf_opt=""
fi
case "$init_style" in
valgrind)
check_status_valgrind
;;
case "$CTDB_INIT_STYLE" in
suse)
checkproc $_pf_opt "$ctdbd"
rc_status -v
@ -302,8 +141,7 @@ check_status ()
esac
}
[ -x "$CTDB_BASE/rc.ctdb" ] && "$CTDB_BASE/rc.ctdb" $1
############################################################
case "$1" in
start)
@ -325,11 +163,9 @@ case "$1" in
;;
cron)
# used from cron to auto-restart ctdb
check_status >/dev/null || restart
check_status >/dev/null 2>&1 || restart
;;
*)
echo $"Usage: $0 {start|stop|restart|reload|force-reload|status|cron|condrestart|try-restart}"
echo "Usage: $0 {start|stop|restart|reload|force-reload|status|cron|condrestart|try-restart}"
exit 1
esac
exit $?

267
ctdb/config/ctdbd_wrapper Executable file
View File

@ -0,0 +1,267 @@
#!/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"
############################################################
[ -n "$CTDB_BASE" ] || export CTDB_BASE="/etc/ctdb"
. "${CTDB_BASE}/functions"
loadconfig "ctdb"
ctdbd="${CTDBD:-/usr/sbin/ctdbd}"
############################################################
# ctdbd_is_running()
# 1. Check if ctdbd is running.
# - If the PID file is being used then, if the PID file is present,
# ctdbd is only considered to running if the PID in the file is
# active.
# - If the PID file is not being used (i.e. we're upgrading from a
# version that doesn't support it) then the presence of any ctdbd
# processes is enough proof.
# 2. Print a comma-separated list of PIDs that can be
# used with "pkill -s".
# - If the PID file is being used then this is just the PID in that
# file. This also happens to be the session ID, so can be used
# to kill all CTDB processes.
# - If the PID file is not being used (i.e. upgrading) then this is
# just any ctdbd processes that are running. Hopefully one of
# them is the session ID so that it can be used to kill all CTDB
# processes.
# Combining these 2 checks is an optimisation to avoid potentially
# running too many pgrep/pkill processes on an already loaded system.
# Trawling through /proc/ can be very expensive.
ctdbd_is_running ()
{
# If the directory for the PID file exists then respect the
# existence of a PID file.
_pidfile_dir=$(dirname "$pidfile")
if [ -d "$_pidfile_dir" ] ; then
if read _pid 2>/dev/null <"$pidfile" ; then
echo "$_pid"
# Return value of kill is used
kill -0 $_pid 2>/dev/null
else
# Missing/empty PID file
return 1
fi
else
if _pid=$(pgrep -f "${ctdbd}\>") ; then
echo $_pid | sed -e 's@ @,@g'
return 0
else
return 1
fi
fi
}
############################################################
build_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 preventivon"
fi
maybe_set "--reclock" "$CTDB_RECOVERY_LOCK"
maybe_set "--pidfile" "$pidfile"
# build up CTDB_OPTIONS variable from optional parameters
maybe_set "--logfile" "$CTDB_LOGFILE"
maybe_set "--nlist" "$CTDB_NODES"
maybe_set "--socket" "$CTDB_SOCKET"
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 "--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 "--lvs --single-public-ip" "$CTDB_LVS_PUBLIC_IP"
maybe_set "--script-log-level" "$CTDB_SCRIPT_LOG_LEVEL"
maybe_set "--log-ringbuf-size" "$CTDB_LOG_RINGBUF_SIZE"
maybe_set "--syslog" "$CTDB_SYSLOG" "yes"
maybe_set "--max-persistent-check-errors" "$CTDB_MAX_PERSISTENT_CHECK_ERRORS"
}
export_debug_variables ()
{
export CTDB_DEBUG_HUNG_SCRIPT CTDB_EXTERNAL_TRACE CTDB_DEBUG_LOCKS
}
kill_ctdbd ()
{
_session="$1"
if [ -n "$_session" ] ; then
pkill -9 -s "$_session" 2>/dev/null
fi
rm -f "$pidfile"
}
############################################################
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.
# Note that starting ctdbd below will destroy the Unix domain
# socket, so any processes that aren't yet completely useless soon
# will be, so this can really do no harm.
kill_ctdbd "$_session"
build_ctdb_options
export_debug_variables
if [ "$CTDB_SUPPRESS_COREFILE" = "yes" ]; then
ulimit -c 0
else
ulimit -c unlimited
fi
mkdir -p $(dirname "$pidfile")
if [ -n "$CTDB_VALGRIND" -a "$CTDB_VALGRIND" != "no" ] ; then
if [ "$CTDB_VALGRIND" = "yes" ] ; then
ctdbd="valgrind -q --log-file=/var/log/ctdb_valgrind ${ctdbd}"
else
ctdbd="${CTDB_VALGRIND} ${ctdbd}"
fi
CTDB_OPTIONS="${CTDB_OPTIONS} --valgrinding"
fi
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 we don't have the PID then try to read it.
[ -n "$_pid" ] || read _pid 2>/dev/null <"$pidfile"
# If we got the PID but the PID file has gone or the process
# is no longer running then stop waiting... CTDB is dead.
if [ -n "$_pid" ] ; then
if [ ! -e "$pidfile" ] || ! kill -0 "$_pid" 2>/dev/null ; then
echo "CTDB exited during initialisation - check logs."
kill_ctdbd "$_pid"
drop_all_public_ips >/dev/null 2>&1
return 1
fi
if ctdb runstate first_recovery startup running >/dev/null 2>&1 ; then
return 0
fi
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
while [ $_count -lt $_timeout ] ; do
pkill -0 -s "$_session" 2>/dev/null || return 0
_count=$(($_count + 1))
sleep 1
done
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
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

View File

@ -174,6 +174,7 @@ rm -rf $RPM_BUILD_ROOT
%config(noreplace) %{_sysconfdir}/ctdb/nfs-rpc-checks.d/50.rquotad.check
%{_sysconfdir}/ctdb/statd-callout
%{_sbindir}/ctdbd
%{_sbindir}/ctdbd_wrapper
%{_bindir}/ctdb
%{_bindir}/ctdb_lock_helper
%{_bindir}/smnotify