ctdb-tests: Be more efficient about starting/stopping local daemons
[samba.git] / ctdb / tests / simple / scripts / local_daemons.bash
index fc0e47d57620eff5123cb08c5616cec8de5dfb8a..04597e9f1b3bd1eba785fbd52802b0985ec9460e 100644 (file)
 # If we're not running on a real cluster then we need a local copy of
 # ctdb (and other stuff) in $PATH and we will use local daemons.
 
-export CTDB_NODES_SOCKETS=""
-for i in $(seq 0 $(($TEST_LOCAL_DAEMONS - 1))) ; do
-    CTDB_NODES_SOCKETS="${CTDB_NODES_SOCKETS}${CTDB_NODES_SOCKETS:+ }${TEST_VAR_DIR}/sock.${i}"
-done
-
-# Use in-tree binaries if running against local daemons.
-# Otherwise CTDB need to be installed on all nodes.
-if [ -n "$ctdb_dir" -a -d "${ctdb_dir}/bin" ] ; then
-       # ctdbd_wrapper is in config/ directory
-       PATH="${ctdb_dir}/bin:${ctdb_dir}/config:${PATH}"
-       hdir="${ctdb_dir}/bin"
-       export CTDB_LOCK_HELPER="${hdir}/ctdb_lock_helper"
-       export CTDB_EVENT_HELPER="${hdir}/ctdb_event_helper"
-       export CTDB_RECOVERY_HELPER="${hdir}/ctdb_recovery_helper"
-       export CTDB_CLUSTER_MUTEX_HELPER="${hdir}/ctdb_mutex_fcntl_helper"
+hdir="$CTDB_SCRIPTS_HELPER_BINDIR"
+export CTDB_EVENTD="${hdir}/ctdb-eventd"
+export CTDB_EVENT_HELPER="${hdir}/ctdb-event"
+export CTDB_LOCK_HELPER="${hdir}/ctdb_lock_helper"
+export CTDB_RECOVERY_HELPER="${hdir}/ctdb_recovery_helper"
+export CTDB_TAKEOVER_HELPER="${hdir}/ctdb_takeover_helper"
+export CTDB_CLUSTER_MUTEX_HELPER="${hdir}/ctdb_mutex_fcntl_helper"
+
+if [ -n "$TEST_SOCKET_WRAPPER_SO_PATH" ] ; then
+       export LD_PRELOAD="$TEST_SOCKET_WRAPPER_SO_PATH"
+       export SOCKET_WRAPPER_DIR="${SIMPLE_TESTS_VAR_DIR}/sw"
+       mkdir -p "$SOCKET_WRAPPER_DIR"
 fi
 
-export CTDB_NODES="${TEST_VAR_DIR}/nodes.txt"
+# onnode will execute this, which fakes ssh against local daemons
+export ONNODE_SSH="${TEST_SUBDIR}/scripts/ssh_local_daemons.sh"
 
 #######################################
 
-daemons_stop ()
+# If the given IP is hosted then print 2 items: maskbits and iface
+have_ip ()
 {
-    echo "Attempting to politely shutdown daemons..."
-    onnode -q all $CTDB shutdown || true
+       local addr="$1"
+       local bits t
 
-    echo "Sleeping for a while..."
-    sleep_for 1
+       case "$addr" in
+       *:*) bits=128 ;;
+       *)   bits=32  ;;
+       esac
 
-    local pat="ctdbd --sloppy-start --nopublicipcheck --nosetsched"
-    if pgrep -f "$pat" >/dev/null ; then
-       echo "Killing remaining daemons..."
-       pkill -f "$pat"
+       t=$(ip addr show to "${addr}/${bits}")
+       [ -n "$t" ]
+}
 
-       if pgrep -f "$pat" >/dev/null ; then
-           echo "Once more with feeling.."
-           pkill -9 -f "$pat"
-       fi
-    fi
+setup_nodes ()
+{
+       local have_all_ips=true
+       local i
+       for i in $(seq 1 $TEST_LOCAL_DAEMONS) ; do
+               if [ -n "$CTDB_USE_IPV6" ]; then
+                       local j=$(printf "%02x" $i)
+                       local node_ip="fd00::5357:5f${j}"
+                       if have_ip "$node_ip" ; then
+                               echo "$node_ip"
+                       else
+                               cat >&2 <<EOF
+ERROR: ${node_ip} not on an interface, please add it
+EOF
+                               have_all_ips=false
+                       fi
+               else
+                       local j=$((i + 10))
+                       echo "127.0.0.${j}"
+               fi
+       done
+
+       # Fail if we don't have all of the IPv6 addresses assigned
+       $have_all_ips
+}
 
-    rm -rf "${TEST_VAR_DIR}/test.db"
+setup_public_addresses ()
+{
+       local pnn_no_ips="$1"
+
+       local i
+       for i in $(seq 1 $TEST_LOCAL_DAEMONS) ; do
+               if  [ $((i - 1)) -eq $pnn_no_ips ] ; then
+                       continue
+               fi
+
+               # 2 public addresses on most nodes, just to make
+               # things interesting
+               local j=$((i + TEST_LOCAL_DAEMONS))
+               if [ -n "$CTDB_USE_IPV6" ]; then
+                       printf "fc00:10::1:%x/64 lo\n" "$i"
+                       printf "fc00:10::1:%x/64 lo\n" "$j"
+               else
+                       printf "192.168.234.%x/24 lo\n" "$i"
+                       printf "192.168.234.%x/24 lo\n" "$j"
+               fi
+       done
 }
 
 setup_ctdb ()
 {
-    mkdir -p "${TEST_VAR_DIR}/test.db/persistent"
-
-    local public_addresses_all="${TEST_VAR_DIR}/public_addresses_all"
-    local no_public_addresses="${TEST_VAR_DIR}/no_public_addresses.txt"
-    rm -f $CTDB_NODES $public_addresses_all $no_public_addresses
-
-    # If there are (strictly) greater than 2 nodes then we'll randomly
-    # choose a node to have no public addresses.
-    local no_public_ips=-1
-    [ $TEST_LOCAL_DAEMONS -gt 2 ] && no_public_ips=$(($RANDOM % $TEST_LOCAL_DAEMONS))
-    echo "$no_public_ips" >$no_public_addresses
-
-    # When running certain tests we add and remove eventscripts, so we
-    # need to be able to modify the events.d/ directory.  Therefore,
-    # we use a temporary events.d/ directory under $TEST_VAR_DIR.  We
-    # copy the actual test eventscript(s) in there from the original
-    # events.d/ directory that sits alongside $TEST_SCRIPT_DIR.
-    local top=$(dirname "$TEST_SCRIPTS_DIR")
-    local events_d="${top}/events.d"
-    mkdir -p "${TEST_VAR_DIR}/events.d"
-    cp -p "${events_d}/"* "${TEST_VAR_DIR}/events.d/"
-
-    local i
-    for i in $(seq 1 $TEST_LOCAL_DAEMONS) ; do
-       if [ "${CTDB_USE_IPV6}x" != "x" ]; then
-           j=$((printf "%02x" $i))
-           echo "fd00::5357:5f${j}" >>"$CTDB_NODES"
-           # FIXME: need to add addresses to lo as root before running :-(
-           # ip addr add "fc00:10::${i}/64" dev lo
-           # 2 public addresses on most nodes, just to make things interesting.
-           if [ $(($i - 1)) -ne $no_public_ips ] ; then
-               echo "fc00:10::1:${i}/64 lo" >>"$public_addresses_all"
-               echo "fc00:10::1:$(($i + $TEST_LOCAL_DAEMONS))/64 lo" >>"$public_addresses_all"
-           fi
-       else
-           j=$(( $i + 10))
-           echo 127.0.0.$j >>"$CTDB_NODES"
-           # 2 public addresses on most nodes, just to make things interesting.
-           if [ $(($i - 1)) -ne $no_public_ips ] ; then
-               echo "192.168.234.$i/24 lo" >>"$public_addresses_all"
-               echo "192.168.234.$(($i + $TEST_LOCAL_DAEMONS))/24 lo" >>"$public_addresses_all"
-           fi
+       local no_public_addresses=false
+       local no_event_scripts=false
+       local disable_failover=false
+       case "$1" in
+       --no-public-addresses) no_public_addresses=true ;;
+       --no-event-scripts)    no_event_scripts=true    ;;
+       --disable-failover)    disable_failover=true    ;;
+       esac
+
+       nodes_file="${SIMPLE_TESTS_VAR_DIR}/nodes"
+       setup_nodes >"$nodes_file" || return 1
+
+       # If there are (strictly) greater than 2 nodes then we'll
+       # randomly choose a node to have no public addresses
+       local pnn_no_ips=-1
+       if [ $TEST_LOCAL_DAEMONS -gt 2 ] ; then
+               pnn_no_ips=$((RANDOM % TEST_LOCAL_DAEMONS))
        fi
-    done
+
+       local public_addresses_all="${SIMPLE_TESTS_VAR_DIR}/public_addresses"
+       setup_public_addresses $pnn_no_ips >"$public_addresses_all"
+
+       local pnn
+       for pnn in $(seq 0 $(($TEST_LOCAL_DAEMONS - 1))) ; do
+               setup_ctdb_base "$SIMPLE_TESTS_VAR_DIR" "node.${pnn}" \
+                               functions notify.sh debug-hung-script.sh
+
+               cp "$nodes_file" "${CTDB_BASE}/nodes"
+
+               local public_addresses="${CTDB_BASE}/public_addresses"
+
+               if  $no_public_addresses || [ $pnn_no_ips -eq $pnn ] ; then
+                       echo "Node ${pnn} will have no public IPs."
+                       : >"$public_addresses"
+               else
+                       cp "$public_addresses_all" "$public_addresses"
+               fi
+
+               local node_ip=$(sed -n -e "$(($pnn + 1))p" "$nodes_file")
+
+               local db_dir="${CTDB_BASE}/db"
+               local d
+               for d in "volatile" "persistent" "state" ; do
+                       mkdir -p "${db_dir}/${d}"
+               done
+
+               if $no_event_scripts ; then
+                       rm -vf "${CTDB_BASE}/events/legacy/"*
+               fi
+
+               cat >"${CTDB_BASE}/ctdb.conf" <<EOF
+[logging]
+       location = file:${CTDB_BASE}/log.ctdb
+       log level = INFO
+
+[cluster]
+       recovery lock = ${SIMPLE_TESTS_VAR_DIR}/rec.lock
+       node address = ${node_ip}
+
+[database]
+       volatile database directory = ${db_dir}/volatile
+       persistent database directory = ${db_dir}/persistent
+       state database directory = ${db_dir}/state
+
+[failover]
+       disabled = ${disable_failover}
+
+[event]
+       debug script = debug-hung-script.sh
+EOF
+       done
 }
 
-daemons_start_1 ()
+start_ctdb_1 ()
 {
-    local pnn="$1"
-    shift # "$@" gets passed to ctdbd
-
-    local public_addresses_all="${TEST_VAR_DIR}/public_addresses_all"
-    local public_addresses_mine="${TEST_VAR_DIR}/public_addresses.${pnn}"
-    local no_public_addresses="${TEST_VAR_DIR}/no_public_addresses.txt"
-    local public_addresses
-
-    local no_public_ips=-1
-    [ -r $no_public_addresses ] && read no_public_ips <$no_public_addresses
-
-    if  [ "$no_public_ips" = $pnn ] ; then
-           echo "Node $no_public_ips will have no public IPs."
-           public_addresses="/dev/null"
-    else
-           cp "$public_addresses_all" "$public_addresses_mine"
-           public_addresses="$public_addresses_mine"
-    fi
-
-    local node_ip=$(sed -n -e "$(($pnn + 1))p" "$CTDB_NODES")
-
-    local pidfile="${TEST_VAR_DIR}/ctdbd.${pnn}.pid"
-    local conf="${TEST_VAR_DIR}/ctdbd.${pnn}.conf"
-    cat >"$conf" <<EOF
-CTDB_RECOVERY_LOCK="${TEST_VAR_DIR}/rec.lock"
-CTDB_NODES="$CTDB_NODES"
-CTDB_NODE_ADDRESS="${node_ip}"
-CTDB_EVENT_SCRIPT_DIR="${TEST_VAR_DIR}/events.d"
-CTDB_LOGGING="file:${TEST_VAR_DIR}/daemon.${pnn}.log"
-CTDB_DEBUGLEVEL=3
-CTDB_DBDIR="${TEST_VAR_DIR}/test.db"
-CTDB_DBDIR_PERSISTENT="${TEST_VAR_DIR}/test.db/persistent"
-CTDB_DBDIR_STATE="${TEST_VAR_DIR}/test.db/state"
-CTDB_PUBLIC_ADDRESSES="${public_addresses}"
-CTDB_SOCKET="${TEST_VAR_DIR}/sock.$pnn"
-EOF
+       local pnn="$1"
 
-    # Override from the environment.  This would be easier if env was
-    # guaranteed to quote its output so it could be reused.
-    env |
-    grep '^CTDB_' |
-    sed -e 's@=\([^"]\)@="\1@' -e 's@[^"]$@&"@' -e 's@="$@&"@' >>"$conf"
-
-    # We'll use "pkill -f" to kill the daemons with
-    # "ctdbd --sloppy-start --nopublicipcheck --nosetsched" as context.
-    CTDBD="${VALGRIND} ctdbd --sloppy-start --nopublicipcheck --nosetsched" \
-        CTDBD_CONF="$conf" \
-        ctdbd_wrapper "$pidfile" start
+       onnode "$pnn" $VALGRIND ctdbd
 }
 
-daemons_start ()
+ctdb_start_all ()
 {
-    # "$@" gets passed to ctdbd
+       echo "Starting $TEST_LOCAL_DAEMONS ctdb daemons..."
 
-    echo "Starting $TEST_LOCAL_DAEMONS ctdb daemons..."
+       onnode all $VALGRIND ctdbd
+}
+
+stop_ctdb_1 ()
+{
+       local pnn="$1"
 
-    for i in $(seq 0 $(($TEST_LOCAL_DAEMONS - 1))) ; do
-       daemons_start_1 $i "$@"
-    done
+       onnode "$pnn" $CTDB shutdown
 }
 
-maybe_stop_ctdb ()
+ctdb_stop_all ()
 {
-    if $TEST_CLEANUP ; then
-       daemons_stop
-    fi
+       echo "Stopping $TEST_LOCAL_DAEMONS ctdb daemons..."
+
+       onnode -p all $CTDB shutdown
 }
 
-_restart_ctdb_all ()
+restart_ctdb_1 ()
 {
-    daemons_stop
-    daemons_start "$@"
+       stop_ctdb_1 "$1"
+       start_ctdb_1 "$1"
 }
+
+# onnode will use CTDB_BASES to help the ctdb tool connection to each
+# daemon
+export CTDB_BASES=""
+for i in $(seq 0 $(($TEST_LOCAL_DAEMONS - 1))) ; do
+       b="${SIMPLE_TESTS_VAR_DIR}/node.${i}"
+       CTDB_BASES="${CTDB_BASES}${CTDB_BASES:+ }${b}"
+done
+
+# Need a default CTDB_BASE for onnode (to find the functions file).
+# Any node will do, so pick the 1st...
+export CTDB_BASE="${CTDB_BASES%% *}"