diff options
| author | Martin Schwenke <martin@meltin.net> | 2013-07-09 15:22:07 +1000 |
|---|---|---|
| committer | Martin Schwenke <martin@meltin.net> | 2013-07-10 15:19:27 +1000 |
| commit | adbee6ae4ea948276e73f4580930f36671bb314c (patch) | |
| tree | 8a0d5e6c3e28b2bffb08f03305be9991210a0420 | |
| parent | a86f1f109aa2900508ec779f33600f7eacee2a48 (diff) | |
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)
| -rwxr-xr-x | ctdb/Makefile.in | 1 | ||||
| -rwxr-xr-x | ctdb/config/ctdb.init | 288 | ||||
| -rwxr-xr-x | ctdb/config/ctdbd_wrapper | 267 | ||||
| -rw-r--r-- | ctdb/packaging/RPM/ctdb.spec.in | 1 |
4 files changed, 331 insertions, 226 deletions
diff --git a/ctdb/Makefile.in b/ctdb/Makefile.in index 60302411f4..0d9d433f70 100755 --- a/ctdb/Makefile.in +++ b/ctdb/Makefile.in @@ -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 diff --git a/ctdb/config/ctdb.init b/ctdb/config/ctdb.init index a313731294..e761fec2e4 100755 --- a/ctdb/config/ctdb.init +++ b/ctdb/config/ctdb.init @@ -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 -} - -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 - } + echo -n "Starting ctdbd service: " - # 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" - RETVAL=$? + eval start-stop-daemon --start --quiet --background --exec \ + "$ctdbd_wrapper" "$pidfile" "start" ;; 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" +stop() +{ + echo -n "Shutting down ctdbd service: " - case $init_style in + case "$CTDB_INIT_STYLE" in suse) - # re-set the return code to the recorded RETVAL in order - # to print the correct status message - set_retval $RETVAL + "$ctdbd_wrapper" "$pidfile" "stop" rc_status -v ;; redhat) + "$ctdbd_wrapper" "$pidfile" "stop" + RETVAL=$? [ $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 $? diff --git a/ctdb/config/ctdbd_wrapper b/ctdb/config/ctdbd_wrapper new file mode 100755 index 0000000000..3acc7ee2ed --- /dev/null +++ b/ctdb/config/ctdbd_wrapper @@ -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 diff --git a/ctdb/packaging/RPM/ctdb.spec.in b/ctdb/packaging/RPM/ctdb.spec.in index 5fc6459cda..a503ce8155 100644 --- a/ctdb/packaging/RPM/ctdb.spec.in +++ b/ctdb/packaging/RPM/ctdb.spec.in @@ -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 |
