diff options
author | Ronnie Sahlberg <ronniesahlberg@gmail.com> | 2011-08-10 15:18:16 +1000 |
---|---|---|
committer | Ronnie Sahlberg <ronniesahlberg@gmail.com> | 2011-08-10 15:18:16 +1000 |
commit | 3c7fb84774f8538bab8b3b73913acb04a91f143b (patch) | |
tree | 96cb6e27540a1640fa86a85e8924a43e35fa9943 | |
parent | 5b4b0a5e8c74607abfd4c584b2299046bbcbf260 (diff) | |
parent | d8e342d71a71c1c0132e3a412f15072c155043b6 (diff) | |
download | samba-3c7fb84774f8538bab8b3b73913acb04a91f143b.tar.gz samba-3c7fb84774f8538bab8b3b73913acb04a91f143b.tar.xz samba-3c7fb84774f8538bab8b3b73913acb04a91f143b.zip |
Merge remote branch 'martins/eventscript_tests'
(This used to be ctdb commit ac164a0d731fc5d46ab7d05112484c45ecb21100)
82 files changed, 2425 insertions, 8 deletions
diff --git a/ctdb/.gitignore b/ctdb/.gitignore index 063e1ed02e..ef8ae6ad3c 100644 --- a/ctdb/.gitignore +++ b/ctdb/.gitignore @@ -25,3 +25,4 @@ tests/bin tests/events.d/00.ctdb_test_trigger tests/var tests/takeover/ctdb_takeover.pyc +tests/eventscripts/var diff --git a/ctdb/config/events.d/10.interface b/ctdb/config/events.d/10.interface index 7f79a08949..b912ab3dc8 100755 --- a/ctdb/config/events.d/10.interface +++ b/ctdb/config/events.d/10.interface @@ -18,7 +18,7 @@ loadconfig monitor_interfaces() { - local INTERFACES=`cat $CTDB_PUBLIC_ADDRESSES | + INTERFACES=`cat $CTDB_PUBLIC_ADDRESSES | sed -e "s/^[^\t ]*[\t ]*//" -e "s/,/ /g" -e "s/[\t ]*$//"` [ "$CTDB_PUBLIC_INTERFACE" ] && INTERFACES="$CTDB_PUBLIC_INTERFACE $INTERFACES" @@ -27,14 +27,12 @@ monitor_interfaces() # For all but the 1st line, get the 2nd last field with commas # changes to spaces. - local IFACES=`ctdb -Y ip -v | sed -e '1d' -e 's/:[^:]*:$//' -e 's/^.*://' -e 's/,/ /g'` - - local IFACE + IFACES=`ctdb -Y ip -v | sed -e '1d' -e 's/:[^:]*:$//' -e 's/^.*://' -e 's/,/ /g'` INTERFACES=`for IFACE in $INTERFACES $IFACES ; do echo $IFACE ; done | sort | uniq` - local fail=0 - local ok=0 + fail=0 + ok=0 for IFACE in $INTERFACES ; do ip addr show $IFACE 2>/dev/null >/dev/null || { @@ -45,7 +43,7 @@ monitor_interfaces() # These interfaces are sometimes bond devices # When we use VLANs for bond interfaces, there will only # be an entry in /proc for the underlying real interface - local REALIFACE=`echo $IFACE |sed -e 's/\..*$//'` + REALIFACE=`echo $IFACE |sed -e 's/\..*$//'` bi=$(get_proc "net/bonding/$REALIFACE") 2>/dev/null && { echo "$bi" | grep -q 'Currently Active Slave: None' && { echo "ERROR: No active slaves for bond device $REALIFACE" @@ -91,7 +89,7 @@ monitor_interfaces() # cable is plugged but the interface has not been # brought up previously. Bring the interface up and # try again... - /sbin/ip link set $IFACE up + ip link set $IFACE up ethtool $IFACE | grep -q 'Link detected: yes' || { echo "ERROR: No link on the public network interface $IFACE" fail=1 diff --git a/ctdb/config/functions b/ctdb/config/functions index 02c111ad43..312234546e 100755 --- a/ctdb/config/functions +++ b/ctdb/config/functions @@ -841,6 +841,10 @@ update_tickles () # load a site local config file ######################################################## +[ -n "$CTDB_RC_LOCAL" -a -x "$CTDB_RC_LOCAL" ] && { + . "$CTDB_RC_LOCAL" +} + [ -x $CTDB_BASE/rc.local ] && { . $CTDB_BASE/rc.local } diff --git a/ctdb/tests/eventscripts/README b/ctdb/tests/eventscripts/README new file mode 100644 index 0000000000..33bea9edb6 --- /dev/null +++ b/ctdb/tests/eventscripts/README @@ -0,0 +1,43 @@ +eventscript unit tests +====================== + +This directory contains some eventscript unit tests for CTDB. These +tests can be run as a non-privileged user. There are a lot of stub +implementations of commands (located in bin/) used to make the +eventscripts think they're running against a real system. + +Examples: + +* ./run_tests.sh + + Run all tests, displaying minimal output. + +* ./run_tests.sh -s + + Run all tests, displaying minimal output and a summary. + +* ./run_tests.sh -s simple/*.sh + + Run all the tests in the simple/ subdirectory. + +* ./run_tests.sh -v -s + + Run all tests, displaying extra output and a summary. + +* ./run_tests.sh -sq + + Run all tests, displaying only a summary. + +* EVENTSCRIPTS_TESTS_TRACE="sh -x" \ + ./run_tests.sh simple/10.interface.startup.002.sh + + Run a test and have the eventscript itself run with "sh -x". This + will usually make a test fail because the (undesirable) trace output + will be included with the output of the eventscript. However, this + is useful for finding out why a test might be failing. You can just + drop the "-x" (minimal command-line editing) to see if changes have + made a test pass. + +The simple/ subdirectory contains tests that exercise only a single +eventscript. Another directory containing tests that exercise +interactions between eventscripts is coming soon... :-) diff --git a/ctdb/tests/eventscripts/common.sh b/ctdb/tests/eventscripts/common.sh new file mode 100644 index 0000000000..ab7abb9fac --- /dev/null +++ b/ctdb/tests/eventscripts/common.sh @@ -0,0 +1,779 @@ +# Hey Emacs, this is a -*- shell-script -*- !!! :-) + +# Augment PATH with relevant stubs/ directories. We do this by actually +# setting PATH, and also by setting $EVENTSCRIPTS_PATH and then +# prepending that to $PATH in rc.local to avoid the PATH reset in +# functions. + +EVENTSCRIPTS_PATH="" + +if [ -d "${EVENTSCRIPTS_TESTS_DIR}/stubs" ] ; then + EVENTSCRIPTS_PATH="${EVENTSCRIPTS_TESTS_DIR}/stubs" +fi + +export EVENTSCRIPTS_TESTCASE_DIR=$(dirname "$0") +if [ $(basename "$EVENTSCRIPTS_TESTCASE_DIR") = "eventscripts" ] ; then + # Just a test script, no testcase subdirectory. + EVENTSCRIPTS_TESTCASE_DIR="$EVENTSCRIPTS_TESTS_DIR" +else + if [ -d "${EVENTSCRIPTS_TESTCASE_DIR}/stubs" ] ; then + EVENTSCRIPTS_PATH="${EVENTSCRIPTS_TESTCASE_DIR}/stubs:${EVENTSCRIPTS_PATH}" + fi +fi + +export EVENTSCRIPTS_PATH + +PATH="${EVENTSCRIPTS_PATH}:${PATH}" + +if [ -d "${EVENTSCRIPTS_TESTCASE_DIR}/etc" ] ; then + CTDB_ETCDIR="${EVENTSCRIPTS_TESTCASE_DIR}/etc" +elif [ -d "${EVENTSCRIPTS_TESTS_DIR}/etc" ] ; then + CTDB_ETCDIR="${EVENTSCRIPTS_TESTS_DIR}/etc" +else + echo "Unable to set \$CTDB_ETCDIR" >&2 + exit 1 +fi +export CTDB_ETCDIR + +if [ -d "${EVENTSCRIPTS_TESTCASE_DIR}/etc-ctdb" ] ; then + CTDB_BASE="${EVENTSCRIPTS_TESTCASE_DIR}/etc-ctdb" +elif [ -d "${EVENTSCRIPTS_TESTCASE_DIR}/etc/ctdb" ] ; then + CTDB_BASE="${EVENTSCRIPTS_TESTCASE_DIR}/etc/ctdb" +elif [ -d "${EVENTSCRIPTS_TESTS_DIR}/etc-ctdb" ] ; then + CTDB_BASE="${EVENTSCRIPTS_TESTS_DIR}/etc-ctdb" +else + echo "Unable to set \$CTDB_BASE" >&2 + exit 1 +fi +export CTDB_BASE + +export EVENTSCRIPTS_TESTS_VAR_DIR="${EVENTSCRIPTS_TESTS_DIR}/var" +if [ "$EVENTSCRIPTS_TESTS_VAR_DIR" != "/var" ] ; then + rm -r "$EVENTSCRIPTS_TESTS_VAR_DIR" +fi +mkdir -p "$EVENTSCRIPTS_TESTS_VAR_DIR" +export CTDB_VARDIR="$EVENTSCRIPTS_TESTS_VAR_DIR/ctdb" + +###################################################################### + +if [ "$EVENTSCRIPT_TESTS_VERBOSE" = "yes" ] ; then + debug () { echo "$@" ; } +else + debug () { : ; } +fi + +eventscripts_tests_cleanup_hooks="" + +# This loses quoting! +eventscripts_test_add_cleanup () +{ + eventscripts_tests_cleanup_hooks="${eventscripts_tests_cleanup_hooks}${eventscripts_tests_cleanup_hooks:+ ; }$*" +} + +trap 'eval $eventscripts_tests_cleanup_hooks' 0 + + +###################################################################### + +# General setup fakery + +setup_generic () +{ + debug "Setting up shares (3 existing shares)" + # Create 3 fake shares/exports. + export FAKE_SHARES="" + for i in $(seq 1 3) ; do + _s="${EVENTSCRIPTS_TESTS_VAR_DIR}/shares/${i}_existing" + mkdir -p "$_s" + FAKE_SHARES="${FAKE_SHARES}${FAKE_SHARES:+ }${_s}" + done + + export FAKE_PROC_NET_BONDING="$EVENTSCRIPTS_TESTS_VAR_DIR/proc-net-bonding" + mkdir -p "$FAKE_PROC_NET_BONDING" + rm -f "$FAKE_PROC_NET_BONDING"/* + + export FAKE_ETHTOOL_LINK_DOWN="$EVENTSCRIPTS_TESTS_VAR_DIR/ethtool-link-down" + mkdir -p "$FAKE_ETHTOOL_LINK_DOWN" + rm -f "$FAKE_ETHTOOL_LINK_DOWN"/* + + # This can only have 2 levels. We don't want to resort to usings + # something dangerous like "rm -r" setup time. + export FAKE_IP_STATE="$EVENTSCRIPTS_TESTS_VAR_DIR/fake-ip-state" + mkdir -p "$FAKE_IP_STATE" + rm -f "$FAKE_IP_STATE"/*/* + rm -f "$FAKE_IP_STATE"/* 2>/dev/null || true + rmdir "$FAKE_IP_STATE"/* 2>/dev/null || true +} + +tcp_port_down () +{ + for _i ; do + debug "Marking TCP port \"${_i}\" as not listening" + FAKE_NETSTAT_TCP_LISTEN=$(echo "$FAKE_NETSTAT_TCP_LISTEN" | sed -r -e "s@[[:space:]]*[\.0-9]+:${_i}@@g") + done +} + +shares_missing () +{ + _fmt="$1" ; shift + + # Replace some shares with non-existent ones. + _t="" + _n=1 + _nl=" +" + export MISSING_SHARES_TEXT="" + for _i in $FAKE_SHARES ; do + if [ $_n = "$1" ] ; then + shift + _i="${_i%_existing}_missing" + debug "Replacing share $_n with missing share \"$_i\"" + rmdir "$_i" 2>/dev/null || true + MISSING_SHARES_TEXT="${MISSING_SHARES_TEXT}${MISSING_SHARES_TEXT:+${_nl}}"$(printf "$_fmt" "${_i}") + fi + _t="${_t}${_t:+ }${_i}" + _n=$(($_n + 1)) + done + FAKE_SHARES="$_t" +} + +# Setup some fake /proc/net/bonding files with just enough info for +# the eventscripts. + +# arg1 is interface name, arg2 is currently active slave (use "None" +# if none), arg3 is MII status ("up" or "down"). +setup_bond () +{ + _iface="$1" + _slave="${2:-${_iface}_sl_0}" + _mii_s="${3:-up}" + _mii_subs="${4:-${_mii_s:-up}}" + echo "Setting $_iface to be a bond with active slave $_slave and MII status $_mii_s" + cat >"${FAKE_PROC_NET_BONDING}/$_iface" <<EOF +Bonding Mode: IEEE 802.3ad Dynamic link aggregation +Currently Active Slave: $_slave +# Status of the bond +MII Status: $_mii_s +# Status of 1st pretend adapter +MII Status: $_mii_subs +# Status of 2nd pretend adapter +MII Status: $_mii_subs +EOF +} + +ethtool_interfaces_down () +{ + for _i ; do + echo "Marking interface $_i DOWN for ethtool" + touch "${FAKE_ETHTOOL_LINK_DOWN}/${_i}" + done +} + +ethtool_interfaces_up () +{ + for _i ; do + echo "Marking interface $_i UP for ethtool" + rm -f "${FAKE_ETHTOOL_LINK_DOWN}/${_i}" + done +} + +###################################################################### + +# CTDB fakery + +# Evaluate an expression that probably calls functions or uses +# variables from the CTDB functions file. This is used for test +# initialisation. +eventscript_call () +{ + ( + . "$CTDB_BASE/functions" + "$@" + ) +} + +# Set output for ctdb command. Option 1st argument is return code. +ctdb_set_output () +{ + _out="$EVENTSCRIPTS_TESTS_VAR_DIR/ctdb.out" + cat >"$_out" + + _rc="$EVENTSCRIPTS_TESTS_VAR_DIR/ctdb.rc" + echo "${1:-0}" >"$_rc" + + eventscripts_test_add_cleanup "rm -f $_out $_rc" +} + +setup_ctdb () +{ + setup_generic + + export FAKE_CTDB_NUMNODES="${1:-3}" + echo "Setting up CTDB with ${FAKE_CTDB_NUMNODES} fake nodes" + + export FAKE_CTDB_PNN="${2:-0}" + echo "Setting up CTDB with PNN ${FAKE_CTDB_PNN}" + + if [ -n "$3" ] ; then + echo "Setting up CTDB_PUBLIC_ADDRESSES: $3" + export CTDB_PUBLIC_ADDRESSES=$(mktemp) + for _i in $3 ; do + _ip="${_i%@*}" + _ifaces="${_i#*@}" + echo "${_ip} ${_ifaces}" >>"$CTDB_PUBLIC_ADDRESSES" + done + eventscripts_test_add_cleanup "rm -f $CTDB_PUBLIC_ADDRESSES" + fi + + export FAKE_CTDB_IFACES_DOWN="$EVENTSCRIPTS_TESTS_VAR_DIR/fake-ctdb/ifaces-down" + mkdir -p "$FAKE_CTDB_IFACES_DOWN" + rm -f "$FAKE_CTDB_IFACES_DOWN"/* + + export FAKE_CTDB_NODES_DOWN="$EVENTSCRIPTS_TESTS_VAR_DIR/nodes-down" + mkdir -p "$FAKE_CTDB_NODES_DOWN" + rm -f "$FAKE_CTDB_NODES_DOWN"/* +} + + + +ctdb_nodes_up () +{ + for _i ; do + rm -f "${FAKE_CTDB_NODES_DOWN}/${_i}" + done +} + +ctdb_nodes_down () +{ + for _i ; do + touch "${FAKE_CTDB_NODES_DOWN}/${_i}" + done +} + +ctdb_get_interfaces () +{ + # The echo/subshell forces all the output onto 1 line. + echo $(ctdb ifaces -Y | awk -F: 'FNR > 1 {print $2}') +} + +ctdb_get_1_interface () +{ + _t=$(ctdb_get_interfaces) + echo ${_t%% *} +} + +ctdb_get_public_addresses () +{ + _f="${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}" + echo $(if [ -r "$_f" ] ; then + while read _ip _iface ; do + echo "${_ip}@${_iface}" + done <"$_f" + fi) +} + +# Prints the 1st public address as: interface IP maskbits +# This is suitable for passing to 10.interfaces takeip/releaseip +ctdb_get_1_public_address () +{ + _addrs=$(ctdb_get_public_addresses) + echo "${_addrs%% *}" | sed -r -e 's#(.*)/(.*)@(.*)#\3 \1 \2#g' +} + +###################################################################### + +# Samba fakery + +setup_samba () +{ + setup_ctdb + + if [ "$1" != "down" ] ; then + + debug "Marking Samba services as up, listening and managed by CTDB" + # Get into known state. + for i in "samba" "winbind" ; do + eventscript_call ctdb_service_managed "$i" + done + # All possible service names for all known distros. + for i in "smb" "nmb" "winbind" "samba" ; do + service "$i" force-started + done + + export CTDB_SAMBA_SKIP_SHARE_CHECK="no" + export CTDB_MANAGED_SERVICES="foo samba winbind bar" + + export FAKE_NETSTAT_TCP_LISTEN="0.0.0.0:445 0.0.0.0:139" + export FAKE_WBINFO_FAIL="no" + else + debug "Marking Samba services as down, not listening and not managed by CTDB" + # Get into known state. + for i in "samba" "winbind" ; do + eventscript_call ctdb_service_unmanaged "$i" + done + # All possible service names for all known distros. + for i in "smb" "nmb" "winbind" "samba" ; do + service "$i" force-stopped + done + + export CTDB_SAMBA_SKIP_SHARE_CHECK="no" + export CTDB_MANAGED_SERVICES="foo bar" + unset CTDB_MANAGES_SAMBA + unset CTDB_MANAGES_WINBIND + + export FAKE_NETSTAT_TCP_LISTEN="" + export FAKE_WBINFO_FAIL="yes" + fi + + # This is ugly but if this file isn't removed before each test + # then configuration changes between tests don't stick. + rm -f "$CTDB_VARDIR/state/samba/smb.conf.cache" +} + +wbinfo_down () +{ + debug "Making wbinfo commands fail" + FAKE_WBINFO_FAIL="yes" +} + +###################################################################### + +# NFS fakery + +setup_nfs () +{ + setup_ctdb + + export FAKE_RPCINFO_SERVICES="" + + export CTDB_NFS_SKIP_SHARE_CHECK="no" + export CTDB_NFS_SKIP_KNFSD_ALIVE_CHECK="no" + + # Reset the failcounts for nfs services. + eventscript_call eval rm -f '$ctdb_fail_dir/nfs_*' + + rpc_fail_limits_file="${EVENTSCRIPTS_TESTS_VAR_DIR}/rpc_fail_limits" + + # Force this file to exist so tests can be individually run. + if [ ! -f "$rpc_fail_limits_file" ] ; then + # This is gross... but is needed to fake through the nfs monitor event. + eventscript_call ctdb_service_managed "nfs" + service "nfs" force-started # might not be enough + CTDB_RC_LOCAL="$CTDB_BASE/rc.local.nfs.monitor.get-limits" \ + CTDB_MANAGES_NFS="yes" \ + "${CTDB_BASE}/events.d/60.nfs" "monitor" >"$rpc_fail_limits_file" + fi + + if [ "$1" != "down" ] ; then + debug "Setting up NFS environment: all RPC services up, NFS managed by CTDB" + + eventscript_call ctdb_service_managed "nfs" + service "nfs" force-started # might not be enough + + export CTDB_MANAGED_SERVICES="foo nfs bar" + + rpc_services_up "nfs" "mountd" "rquotad" "nlockmgr" "status" + else + debug "Setting up NFS environment: all RPC services down, NFS not managed by CTDB" + + eventscript_call ctdb_service_unmanaged "nfs" + service "nfs" force-stopped # might not be enough + eventscript_call startstop_nfs stop + + export CTDB_MANAGED_SERVICES="foo bar" + unset CTDB_MANAGES_NFS + fi +} + +rpc_services_down () +{ + for _i ; do + debug "Marking RPC service \"${_i}\" as unavailable" + FAKE_RPCINFO_SERVICES=$(echo "$FAKE_RPCINFO_SERVICES" | sed -r -e "s@[[:space:]]*${_i}:[0-9]+:[0-9]+@@g") + done +} + +rpc_services_up () +{ + for _i ; do + debug "Marking RPC service \"${_i}\" as available" + case "$_i" in + nfs) _t="2:3" ;; + mountd) _t="1:3" ;; + rquotad) _t="1:2" ;; + nlockmgr) _t="3:4" ;; + status) _t="1:1" ;; + *) + echo "Internal error - unsupported RPC service \"${_i}\"" + exit 1 + esac + + FAKE_RPCINFO_SERVICES="${FAKE_RPCINFO_SERVICES}${FAKE_RPCINFO_SERVICES:+ }${_i}:${_t}" + done +} + +# Set the required result for a particular RPC program having failed +# for a certain number of iterations. This is probably still a work +# in progress. Note that we could hook aggressively +# nfs_check_rpc_service() to try to implement this but we're better +# off testing nfs_check_rpc_service() using independent code... even +# if it is incomplete and hacky. So, if the 60.nfs eventscript +# changes and the tests start to fail then it may be due to this +# function being incomplete. +rpc_set_service_failure_response () +{ + _progname="$1" + # The number of failures defaults to the iteration number. This + # will be true when we fail from the 1st iteration... but we need + # the flexibility to set the number of failures. + _numfails="${2:-${iteration}}" + + _c="${CTDB_ETCDIR}/sysconfig/nfs" + if [ -r "$_c" ] ; then + . "$_c" + fi + + # A handy newline. :-) + _nl=" +" + + # Default + ok_null + + _ts=$(sed -n -e "s@^${_progname} @@p" "$rpc_fail_limits_file") + + while [ -n "$_ts" ] ; do + # Get the triple: operator, fail limit and actions. + _op="${_ts%% *}" ; _ts="${_ts#* }" + _li="${_ts%% *}" ; _ts="${_ts#* }" + # We've lost some of the quoting but we can simulate + # because we know an operator is always the first in a + # triple. + _actions="" + while [ -n "$_ts" ] ; do + # If this is an operator then we've got all of the + # actions. + case "$_ts" in + -*) break ;; + esac + + _actions="${_actions}${_actions:+ }${_ts%% *}" + # Special case for end of list. + if [ "$_ts" != "${_ts#* }" ] ; then + _ts="${_ts#* }" + else + _ts="" + fi + done + + if [ "$_numfails" "$_op" "$_li" ] ; then + _out="" + _rc=0 + for _action in $_actions ; do + case "$_action" in + verbose) + _ver=1 + _pn="$_progname" + case "$_progname" in + knfsd) _ver=3 ; _pn="nfs" ;; + lockd) _ver=4 ; _pn="nlockmgr" ;; + statd) _pn="status" ;; + esac + _out="\ +ERROR: $_pn failed RPC check: +rpcinfo: RPC: Program not registered +program $_pn version $_ver is not available" + ;; + restart|restart:*) + _opts="" + _p="rpc.${_progname}" + case "$_progname" in + statd) + _opts="${STATD_HOSTNAME:+ -n }${STATD_HOSTNAME}" + ;; + esac + case "${_progname}${_action#restart}" in + knfsd) + _t="\ +Trying to restart NFS service +Starting nfslock: OK +Starting nfs: OK" + ;; + knfsd:bs) + _t="Trying to restart NFS service" + ;; + lockd) + _t="\ +Trying to restart lock manager service +Stopping nfslock: OK +Starting nfslock: OK" + ;; + lockd:*) + _t="Trying to restart lock manager service" + ;; + *) + _t="Trying to restart $_progname [${_p}${_opts}]" + esac + _out="${_out}${_out:+${_nl}}${_t}" + ;; + unhealthy) + _rc=1 + esac + done + required_result $_rc "$_out" + return + fi + done +} + +###################################################################### + +# VSFTPD fakery + +setup_vsftpd () +{ + if [ "$1" != "down" ] ; then + echo "setup_vsftpd up not implemented!!!" + exit 1 + else + debug "Setting up VSFTPD environment: service down, not managed by CTDB" + + eventscript_call ctdb_service_unmanaged vsftpd + service vsftpd force-stopped + + export CTDB_MANAGED_SERVICES="foo" + unset CTDB_MANAGES_VSFTPD + fi +} + +###################################################################### + +# HTTPD fakery + +setup_httpd () +{ + if [ "$1" != "down" ] ; then + echo "setup_httpd up not implemented!!!" + exit 1 + else + debug "Setting up HTTPD environment: service down, not managed by CTDB" + + for i in "apache2" "httpd" ; do + eventscript_call ctdb_service_unmanaged "$i" + service "$i" force-stopped + done + + export CTDB_MANAGED_SERVICES="foo" + unset CTDB_MANAGES_HTTPD + fi +} + +###################################################################### + +# Result and test functions + +# Set some globals and print the summary. +define_test () +{ + desc="$1" + + _f="$0" + _f="${_f#./}" # strip leading ./ + _f="${_f#simple/}" # strip leading simple/ + _f="${_f%%/*}" # if subdir, strip off file + _f="${_f%.sh}" # strip off .sh suffix if any + + # Remaining format should be NN.service.event.NNN: + _num="${_f##*.}" + _f="${_f%.*}" + event="${_f##*.}" + script="${_f%.*}" + + printf "%-14s %-10s %-4s - %s\n\n" "$script" "$event" "$_num" "$desc" +} + +# Set the required result for a test. +# - Argument 1 is exit code. +# - Argument 2, if present is the required test output but "--" +# indicates empty output. +# If argument 2 is not present or null then read required test output +# from stdin. +required_result () +{ + required_rc="${1:-0}" + if [ -n "$2" ] ; then + if [ "$2" = "--" ] ; then + required_output="" + else + required_output="$2" + fi + else + if ! tty -s ; then + required_output=$(cat) + else + required_output="" + fi + fi +} + +ok () +{ + required_result 0 "$@" +} + +ok_null () +{ + ok -- +} + +result_print () +{ + _passed="$1" + _out="$2" + _rc="$3" + _iteration="$4" + + if [ "$EVENTSCRIPT_TESTS_VERBOSE" = "yes" ] || ! $_passed ; then + if [ -n "$_iteration" ] ; then + cat <<EOF + +################################################## +################################################## +Iteration $_iteration +EOF + fi + +cat <<EOF +################################################## +Output (Exit status: ${_rc}): +################################################## +$_out +EOF + fi + + if ! $_passed ; then + cat <<EOF +################################################## +Required output (Exit status: ${required_rc}): +################################################## +$required_output +EOF + fi +} + +result_footer () +{ + _passed="$1" + + if [ "$EVENTSCRIPT_TESTS_VERBOSE" = "yes" ] || ! $_passed ; then + + cat <<EOF +################################################## +CTDB_BASE="$CTDB_BASE" +CTDB_ETCDIR="$CTDB_ETCDIR" +ctdb client is "$(which ctdb)" +################################################## +EOF + fi + + echo + + if $_passed ; then + echo "PASSED" + return 0 + else + echo "FAILED" + return 1 + fi +} + +# Run an eventscript once. The test passes if the return code and +# output match those required. + +# Any args are passed to the eventscript. + +# Eventscript tracing can be done by setting: +# EVENTSCRIPTS_TESTS_TRACE="sh -x" + +# or similar. This will almost certainly make a test fail but is +# useful for debugging. +simple_test () +{ + echo "Running \"${CTDB_BASE}/events.d/$script $event\"" + _out=$($EVENTSCRIPTS_TESTS_TRACE "${CTDB_BASE}/events.d/$script" "$event" "$@" 2>&1) + _rc=$? + + if [ "$_out" = "$required_output" -a $_rc = $required_rc ] ; then + _passed=true + else + _passed=false + fi + + result_print "$_passed" "$_out" "$_rc" + result_footer "$_passed" +} + +# Run an eventscript iteratively. +# - 1st argument is the number of iterations. +# - 2nd argument is something to eval to do setup for every iteration. +# The easiest thing to do here is to define a function and pass it +# here. +# - Subsequent arguments come in pairs: an iteration number and +# something to eval for that iteration. Each time an iteration +# number is matched the associated argument is given to eval after +# the default setup is done. The iteration numbers need to be given +# in ascending order. +# +# Some optional args can be given *before* these, surrounded by extra +# "--" args. These args are passed to the eventscript. Quoting is +# lost. +# +# One use of the 2nd and further arguments is to call +# required_result() to change what is expected of a particular +# iteration. +iterate_test () +{ + args="" + if [ "$1" = "--" ] ; then + shift + while [ "$1" != "--" ] ; do + args="${args}${args:+ }$1" + shift + done + shift + fi + + _repeats="$1" + _setup_default="$2" + shift 2 + + echo "Running $_repeats iterations of \"${CTDB_BASE}/events.d/$script $event\" $args" + + _result=true + + for iteration in $(seq 1 $_repeats) ; do + # This is inefficient because the iteration-specific setup + # might completely replace the default one. However, running + # the default is good because it allows you to revert to a + # particular result without needing to specify it explicitly. + eval $_setup_default + if [ $iteration = "$1" ] ; then + eval $2 + shift 2 + fi + + _out=$($EVENTSCRIPTS_TESTS_TRACE "${CTDB_BASE}/events.d/$script" "$event" $args 2>&1) + _rc=$? + + if [ "$_out" = "$required_output" -a $_rc = $required_rc ] ; then + _passed=true + else + _passed=false + _result=false + fi + + result_print "$_passed" "$_out" "$_rc" "$iteration" + done + + result_footer "$_result" +} diff --git a/ctdb/tests/eventscripts/etc-ctdb/events.d b/ctdb/tests/eventscripts/etc-ctdb/events.d new file mode 120000 index 0000000000..69d2396b33 --- /dev/null +++ b/ctdb/tests/eventscripts/etc-ctdb/events.d @@ -0,0 +1 @@ +../../../config/events.d
\ No newline at end of file diff --git a/ctdb/tests/eventscripts/etc-ctdb/functions b/ctdb/tests/eventscripts/etc-ctdb/functions new file mode 120000 index 0000000000..86ba904ac4 --- /dev/null +++ b/ctdb/tests/eventscripts/etc-ctdb/functions @@ -0,0 +1 @@ +../../../config/functions
\ No newline at end of file diff --git a/ctdb/tests/eventscripts/etc-ctdb/interface_modify.sh b/ctdb/tests/eventscripts/etc-ctdb/interface_modify.sh new file mode 120000 index 0000000000..94f555c30d --- /dev/null +++ b/ctdb/tests/eventscripts/etc-ctdb/interface_modify.sh @@ -0,0 +1 @@ +../../../config/interface_modify.sh
\ No newline at end of file diff --git a/ctdb/tests/eventscripts/etc-ctdb/public_addresses b/ctdb/tests/eventscripts/etc-ctdb/public_addresses new file mode 100644 index 0000000000..5421cd781d --- /dev/null +++ b/ctdb/tests/eventscripts/etc-ctdb/public_addresses @@ -0,0 +1,4 @@ +10.0.0.1/24 dev123 +10.0.0.2/24 dev123 +10.0.1.1/24 dev456 +10.0.1.2/24 dev456 diff --git a/ctdb/tests/eventscripts/etc-ctdb/rc.local b/ctdb/tests/eventscripts/etc-ctdb/rc.local new file mode 100755 index 0000000000..ae93ae53e7 --- /dev/null +++ b/ctdb/tests/eventscripts/etc-ctdb/rc.local @@ -0,0 +1,46 @@ +# Hey Emacs, this is a -*- shell-script -*- !!! :-) + +# Use a "service" command in $PATH if one exists. +service () +{ + if _t=$(which "service" 2>/dev/null) ; then + "$_t" "$@" + else + _nice="" + _service "$@" + fi +} + +nice_service () +{ + if _t=$(which "service" 2>/dev/null) ; then + nice "$_t" "$@" + else + _nice="nice" + _service "$@" + fi +} + +# Always succeeds +set_proc () { : ; } + +get_proc () +{ + case "$1" in + net/bonding/*) + cat "$FAKE_PROC_NET_BONDING/${1##*/}" + ;; + sys/net/ipv4/conf/all/arp_filter) + echo 1 + ;; + *) + echo "get_proc: \"$1\" not implemented" + exit 1 + esac +} + +# Always succeeds +iptables () { : ; } + +CTDB_INIT_STYLE="redhat" +PATH="${EVENTSCRIPTS_PATH}:$PATH" diff --git a/ctdb/tests/eventscripts/etc-ctdb/rc.local.nfs.monitor.get-limits b/ctdb/tests/eventscripts/etc-ctdb/rc.local.nfs.monitor.get-limits new file mode 100755 index 0000000000..96e4cff52d --- /dev/null +++ b/ctdb/tests/eventscripts/etc-ctdb/rc.local.nfs.monitor.get-limits @@ -0,0 +1,25 @@ +# Hey Emacs, this is a -*- shell-script -*- !!! :-) + +# This scripts nobble the 60.nfs monitor event so that it prints out +# the service fail limits for each RPC service. + +CTDB_INIT_STYLE="redhat" +PATH="${EVENTSCRIPTS_PATH}:$PATH" + +service () { : ; } + +update_tickles () { : ; } + +ctdb_setup_service_state_dir "nfs" + +CTDB_NFS_SKIP_KNFSD_ALIVE_CHECK="no" +CTDB_NFS_SKIP_SHARE_CHECK="yes" + +# Ugly but necessary - if this file was touched less then 60 seconds +# ago then this skips some code. +touch "$service_state_dir/update-trigger" + +nfs_check_rpc_service () +{ + echo "$*" +} diff --git a/ctdb/tests/eventscripts/etc-ctdb/statd-callout b/ctdb/tests/eventscripts/etc-ctdb/statd-callout new file mode 100755 index 0000000000..51779bd7ba --- /dev/null +++ b/ctdb/tests/eventscripts/etc-ctdb/statd-callout @@ -0,0 +1,5 @@ +#!/bin/sh + +# For now, always succeed. + +exit 0 diff --git a/ctdb/tests/eventscripts/etc/init.d/nfs b/ctdb/tests/eventscripts/etc/init.d/nfs new file mode 100755 index 0000000000..43eb308e34 --- /dev/null +++ b/ctdb/tests/eventscripts/etc/init.d/nfs @@ -0,0 +1,7 @@ +#!/bin/sh + +# This is not used. The fake "service" script is used instead. This +# is only needed to shut up functions like startstop_nfs(), which look +# for this script. + +exit 0 diff --git a/ctdb/tests/eventscripts/etc/init.d/nfslock b/ctdb/tests/eventscripts/etc/init.d/nfslock new file mode 100755 index 0000000000..43eb308e34 --- /dev/null +++ b/ctdb/tests/eventscripts/etc/init.d/nfslock @@ -0,0 +1,7 @@ +#!/bin/sh + +# This is not used. The fake "service" script is used instead. This +# is only needed to shut up functions like startstop_nfs(), which look +# for this script. + +exit 0 diff --git a/ctdb/tests/eventscripts/etc/samba/smb.conf b/ctdb/tests/eventscripts/etc/samba/smb.conf new file mode 100644 index 0000000000..da89db2b81 --- /dev/null +++ b/ctdb/tests/eventscripts/etc/samba/smb.conf @@ -0,0 +1,42 @@ +[global] + # enable clustering + clustering=yes + ctdb:registry.tdb=yes + + security = ADS + auth methods = guest sam winbind + + netbios name = cluster1 + workgroup = CLUSTER1 + realm = CLUSTER1.COM + server string = "Clustered Samba" + disable netbios = yes + disable spoolss = yes + fileid:mapping = fsname + use mmap = yes + gpfs:sharemodes = yes + gpfs:leases = yes + passdb backend = tdbsam + preferred master = no + kernel oplocks = yes + syslog = 1 + host msdfs = no + notify:inotify = no + vfs objects = shadow_copy2 syncops gpfs fileid + shadow:snapdir = .snapshots + shadow:fixinodes = yes + wide links = no + smbd:backgroundqueue = False + read only = no + use sendfile = yes + strict locking = yes + posix locking = yes + large readwrite = yes + force unknown acl user = yes + nfs4:mode = special + nfs4:chown = yes + nfs4:acedup = merge + nfs4:sidmap = /etc/samba/sidmap.tdb + map readonly = no + ea support = yes + dmapi support = no diff --git a/ctdb/tests/eventscripts/etc/sysconfig/nfs b/ctdb/tests/eventscripts/etc/sysconfig/nfs new file mode 100644 index 0000000000..090d786ea6 --- /dev/null +++ b/ctdb/tests/eventscripts/etc/sysconfig/nfs @@ -0,0 +1,2 @@ +NFS_HOSTNAME="cluster1" +STATD_HOSTNAME="$NFS_HOSTNAME -H /etc/ctdb/statd-callout " diff --git a/ctdb/tests/eventscripts/run_tests.sh b/ctdb/tests/eventscripts/run_tests.sh new file mode 100755 index 0000000000..cb2c8f2950 --- /dev/null +++ b/ctdb/tests/eventscripts/run_tests.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +# Eventscript unit test harness. + +cd $(dirname "$0") +export EVENTSCRIPTS_TESTS_DIR=$(pwd) + +test_dir=$(dirname "$EVENTSCRIPTS_TESTS_DIR") + +opts="-d" + +for i ; do + case "$i" in + -v) + export EVENTSCRIPT_TESTS_VERBOSE="yes" + shift + ;; + -*) + opts="$opts $i" + shift + ;; + *) + break + esac +done + +tests="" +if [ -z "$*" ] ; then + tests=$(ls simple/[0-9][0-9].*.*.[0-9][0-9][0-9].sh simple/[0-9][0-9].*.*.[0-9][0-9][0-9]/run_test.sh 2>/dev/null) +fi + +"$test_dir/scripts/run_tests" $opts "$@" $tests || exit 1 + +exit 0 diff --git a/ctdb/tests/eventscripts/simple/10.interface.init.001.sh b/ctdb/tests/eventscripts/simple/10.interface.init.001.sh new file mode 100755 index 0000000000..411355f105 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.init.001.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "no public addresses" + +setup_ctdb + +export CTDB_PUBLIC_ADDRESSES="$CTDB_ETC/does/not/exist" + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.init.002.sh b/ctdb/tests/eventscripts/simple/10.interface.init.002.sh new file mode 100755 index 0000000000..43bacd5231 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.init.002.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "all interfaces up" + +setup_ctdb + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.001.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.001.sh new file mode 100755 index 0000000000..411355f105 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.001.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "no public addresses" + +setup_ctdb + +export CTDB_PUBLIC_ADDRESSES="$CTDB_ETC/does/not/exist" + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.002.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.002.sh new file mode 100755 index 0000000000..43bacd5231 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.002.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "all interfaces up" + +setup_ctdb + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.003.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.003.sh new file mode 100755 index 0000000000..5dd432816b --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.003.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "1 interface down" + +setup_ctdb + +iface=$(ctdb_get_1_interface) + +ethtool_interfaces_down $iface + +required_result 1 "ERROR: No link on the public network interface $iface" + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.004.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.004.sh new file mode 100755 index 0000000000..d215c40019 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.004.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "all interfaces up, 1 is a bond" + +setup_ctdb + +iface=$(ctdb_get_1_interface) + +setup_bond $iface + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.005.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.005.sh new file mode 100755 index 0000000000..00db01fe63 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.005.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "1 bond, no active slaves" + +setup_ctdb + +iface=$(ctdb_get_1_interface) + +setup_bond $iface "None" + +required_result 1 "ERROR: No active slaves for bond device $iface" + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.006.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.006.sh new file mode 100755 index 0000000000..862a972373 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.006.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "1 bond, active slaves, link down" + +setup_ctdb + +iface=$(ctdb_get_1_interface) + +setup_bond $iface "" "down" + +required_result 1 "ERROR: public network interface $iface is down" + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.007.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.007.sh new file mode 100755 index 0000000000..004247ef67 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.007.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "unknown interface, up" + +setup_ctdb + +export CTDB_PUBLIC_INTERFACE="dev999" + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.008.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.008.sh new file mode 100755 index 0000000000..aa59151c2a --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.008.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "unknown interface, down, up" + +setup_ctdb + +iface="dev999" +export CTDB_PUBLIC_INTERFACE="$iface" + +#EVENTSCRIPTS_TESTS_TRACE="sh -x" +iterate_test 3 "ok_null" \ + 1 'ethtool_interfaces_down "$iface" ; required_result 1 "ERROR: No link on the public network interface $iface"' \ + 2 'ethtool_interfaces_up "$iface"' diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.009.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.009.sh new file mode 100755 index 0000000000..ab890f3442 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.009.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "CTDB_PARTIALLY_ONLINE_INTERFACES, 1 down" + +setup_ctdb + +iface=$(ctdb_get_1_interface) + +export CTDB_PARTIALLY_ONLINE_INTERFACES="yes" + +ethtool_interfaces_down "$iface" + +ok "ERROR: No link on the public network interface $iface" + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.010.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.010.sh new file mode 100755 index 0000000000..476d2c9f69 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.010.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "CTDB_PARTIALLY_ONLINE_INTERFACES, all down" + +setup_ctdb + +ifaces=$(ctdb_get_interfaces) + +export CTDB_PARTIALLY_ONLINE_INTERFACES="yes" + +ethtool_interfaces_down $ifaces + +msg=$(for i in $ifaces ; do echo "ERROR: No link on the public network interface $i" ; done) + +required_result 1 "$msg" + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.011.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.011.sh new file mode 100755 index 0000000000..3e5ba34ace --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.011.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "CTDB_PARTIALLY_ONLINE_INTERFACES, 1 bond down" + +setup_ctdb + +iface=$(ctdb_get_1_interface) + +setup_bond $iface "None" + +export CTDB_PARTIALLY_ONLINE_INTERFACES="yes" + +ethtool_interfaces_down "$iface" + +ok "ERROR: No active slaves for bond device $iface" + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.012.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.012.sh new file mode 100755 index 0000000000..d27c423e44 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.012.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "CTDB_PARTIALLY_ONLINE_INTERFACES, 1 bond down" + +setup_ctdb + +ifaces=$(ctdb_get_interfaces) + +for i in $ifaces ; do + setup_bond $i "None" +done + +export CTDB_PARTIALLY_ONLINE_INTERFACES="yes" + +ethtool_interfaces_down $ifaces + +msg=$(for i in $ifaces ; do echo "ERROR: No active slaves for bond device $i" ; done) + +required_result 1 "$msg" + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.monitor.013.sh b/ctdb/tests/eventscripts/simple/10.interface.monitor.013.sh new file mode 100755 index 0000000000..874f0bcd29 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.monitor.013.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "1 bond, active slaves, link down" + +setup_ctdb + +iface=$(ctdb_get_1_interface) + +setup_bond $iface "" "up" "down" + +required_result 1 "No active slaves for 802.ad bond device $iface" + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.releaseip.001.sh b/ctdb/tests/eventscripts/simple/10.interface.releaseip.001.sh new file mode 100755 index 0000000000..56f01d66e6 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.releaseip.001.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "error - no args given" + +setup_ctdb + +iface=$(ctdb_get_1_interface) + +required_result 1 "must supply interface, IP and maskbits" + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.releaseip.002.sh b/ctdb/tests/eventscripts/simple/10.interface.releaseip.002.sh new file mode 100755 index 0000000000..d08d27c7e0 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.releaseip.002.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "error - remove a non-existent ip" + +setup_ctdb + +public_address=$(ctdb_get_1_public_address) +ip="${public_address% *}" ; ip="${ip#* }" + +required_result 1 <<EOF +RTNETLINK answers: Cannot assign requested address +Failed to del ${ip} on dev ${public_address%% *} +EOF + +simple_test $public_address diff --git a/ctdb/tests/eventscripts/simple/10.interface.startup.001.sh b/ctdb/tests/eventscripts/simple/10.interface.startup.001.sh new file mode 100755 index 0000000000..411355f105 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.startup.001.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "no public addresses" + +setup_ctdb + +export CTDB_PUBLIC_ADDRESSES="$CTDB_ETC/does/not/exist" + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.startup.002.sh b/ctdb/tests/eventscripts/simple/10.interface.startup.002.sh new file mode 100755 index 0000000000..43bacd5231 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.startup.002.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "all interfaces up" + +setup_ctdb + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.takeip.001.sh b/ctdb/tests/eventscripts/simple/10.interface.takeip.001.sh new file mode 100755 index 0000000000..56f01d66e6 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.takeip.001.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "error - no args given" + +setup_ctdb + +iface=$(ctdb_get_1_interface) + +required_result 1 "must supply interface, IP and maskbits" + +simple_test diff --git a/ctdb/tests/eventscripts/simple/10.interface.takeip.002.sh b/ctdb/tests/eventscripts/simple/10.interface.takeip.002.sh new file mode 100755 index 0000000000..9ee361a326 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.takeip.002.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "add an ip" + +setup_ctdb + +public_address=$(ctdb_get_1_public_address) + +ok_null + +simple_test $public_address diff --git a/ctdb/tests/eventscripts/simple/10.interface.takeip.003.sh b/ctdb/tests/eventscripts/simple/10.interface.takeip.003.sh new file mode 100755 index 0000000000..8997d71d76 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/10.interface.takeip.003.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "error - add same IP twice" + +setup_ctdb + +public_address=$(ctdb_get_1_public_address) + +# This is a bit gross and contrived. The method of quoting the error +# message so it makes it to required_result() is horrible. Hopefully +# improvements will come. + +err2="\ +RTNETLINK answers: File exists +Failed to add 10.0.0.1/24 on dev dev123" + +#EVENTSCRIPTS_TESTS_TRACE="sh -x" +iterate_test -- $public_address -- 2 "ok_null" \ + 2 'required_result 1 "$err2"' diff --git a/ctdb/tests/eventscripts/simple/40.vsftpd.monitor.001.sh b/ctdb/tests/eventscripts/simple/40.vsftpd.monitor.001.sh new file mode 100755 index 0000000000..fe2afd1d9f --- /dev/null +++ b/ctdb/tests/eventscripts/simple/40.vsftpd.monitor.001.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "not managed, check no-op" + +setup_vsftpd "down" + +ok_null + +simple_test $cmd diff --git a/ctdb/tests/eventscripts/simple/41.httpd.monitor.001.sh b/ctdb/tests/eventscripts/simple/41.httpd.monitor.001.sh new file mode 100755 index 0000000000..c46a45c0c7 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/41.httpd.monitor.001.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "not managed, check no-op" + +setup_httpd "down" + +ok_null + +simple_test $cmd diff --git a/ctdb/tests/eventscripts/simple/50.samba.monitor.001.sh b/ctdb/tests/eventscripts/simple/50.samba.monitor.001.sh new file mode 100644 index 0000000000..77fc2eb852 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/50.samba.monitor.001.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "not managed, check no-op" + +setup_samba "down" + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/50.samba.monitor.050.sh b/ctdb/tests/eventscripts/simple/50.samba.monitor.050.sh new file mode 100644 index 0000000000..7a1b422bd2 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/50.samba.monitor.050.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "auto-start, simple" + +setup_samba "down" + +export CTDB_MANAGED_SERVICES="foo samba winbind bar" + +ok <<EOF +Starting service "samba" - now managed +Starting winbind: OK +Starting smb: OK +EOF + +simple_test diff --git a/ctdb/tests/eventscripts/simple/50.samba.monitor.051.sh b/ctdb/tests/eventscripts/simple/50.samba.monitor.051.sh new file mode 100644 index 0000000000..3a53ac8aaa --- /dev/null +++ b/ctdb/tests/eventscripts/simple/50.samba.monitor.051.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "auto-stop, simple" + +setup_samba + +export CTDB_MANAGED_SERVICES="foo" +unset CTDB_MANAGES_SAMBA +unset CTDB_MANAGES_WINBIND + +ok <<EOF +Stopping service "samba" - no longer managed +Stopping smb: OK +Stopping winbind: OK +EOF + +simple_test diff --git a/ctdb/tests/eventscripts/simple/50.samba.monitor.101.sh b/ctdb/tests/eventscripts/simple/50.samba.monitor.101.sh new file mode 100644 index 0000000000..d4b80bbf8f --- /dev/null +++ b/ctdb/tests/eventscripts/simple/50.samba.monitor.101.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "all OK" + +setup_samba + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/50.samba.monitor.102.sh b/ctdb/tests/eventscripts/simple/50.samba.monitor.102.sh new file mode 100644 index 0000000000..2f1f446fe8 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/50.samba.monitor.102.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "winbind down" + +setup_samba +wbinfo_down + +required_result 1 "ERROR: winbind - wbinfo -p returned error" + +simple_test diff --git a/ctdb/tests/eventscripts/simple/50.samba.monitor.103.sh b/ctdb/tests/eventscripts/simple/50.samba.monitor.103.sh new file mode 100644 index 0000000000..924d953ff4 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/50.samba.monitor.103.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "port 445 down" + +setup_samba +tcp_port_down 445 + +required_result 1 <<EOF +ERROR: samba tcp port 445 is not responding +netstat -l -t -n shows this output: +Active Internet connections (servers only) +Proto Recv-Q Send-Q Local Address Foreign Address State +tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN +EOF + +simple_test diff --git a/ctdb/tests/eventscripts/simple/50.samba.monitor.104.sh b/ctdb/tests/eventscripts/simple/50.samba.monitor.104.sh new file mode 100644 index 0000000000..c05b8d45f6 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/50.samba.monitor.104.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "port 139 down" + +setup_samba +tcp_port_down 139 + +required_result 1 <<EOF +ERROR: samba tcp port 139 is not responding +netstat -l -t -n shows this output: +Active Internet connections (servers only) +Proto Recv-Q Send-Q Local Address Foreign Address State +tcp 0 0 0.0.0.0:445 0.0.0.0:* LISTEN +EOF + +simple_test diff --git a/ctdb/tests/eventscripts/simple/50.samba.monitor.105.sh b/ctdb/tests/eventscripts/simple/50.samba.monitor.105.sh new file mode 100644 index 0000000000..624c4a502c --- /dev/null +++ b/ctdb/tests/eventscripts/simple/50.samba.monitor.105.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "non-existent share path" + +setup_samba +shares_missing "ERROR: samba directory \"%s\" not available" 2 + +required_result 1 "$MISSING_SHARES_TEXT" + +simple_test diff --git a/ctdb/tests/eventscripts/simple/50.samba.monitor.106.sh b/ctdb/tests/eventscripts/simple/50.samba.monitor.106.sh new file mode 100644 index 0000000000..f54cc06c68 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/50.samba.monitor.106.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "non-existent share - not checked" + +setup_samba +shares_missing "ERROR: samba directory \"%s\" not available" 2 + +export CTDB_SAMBA_SKIP_SHARE_CHECK="yes" + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.001.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.001.sh new file mode 100644 index 0000000000..5b260ac6fb --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.001.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "not managed, check no-op" + +setup_nfs "down" + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.100.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.100.sh new file mode 100644 index 0000000000..95f4dc6fb6 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.100.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "get RPC service fail limits/actions" + +setup_nfs + +set -e + +rm -f "$rpc_fail_limits_file" +CTDB_RC_LOCAL="$CTDB_BASE/rc.local.nfs.monitor.get-limits" \ + "${CTDB_BASE}/events.d/60.nfs" "monitor" >"$rpc_fail_limits_file" + +services="knfsd|mountd|rquotad|lockd|statd" + +echo "Doing rough check of file format..." + +! grep -v -E "^(${services}) " "$rpc_fail_limits_file" diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.101.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.101.sh new file mode 100644 index 0000000000..657db97a07 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.101.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "all services available" + +setup_nfs + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.111.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.111.sh new file mode 100644 index 0000000000..8dcde029dd --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.111.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "knfsd down, 1 iteration" + +setup_nfs +rpc_services_down "nfs" + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.112.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.112.sh new file mode 100644 index 0000000000..de796ebd07 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.112.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "knfsd down, 6 iterations" + +# knfsd fails and attempts to restart it fail. + +setup_nfs +rpc_services_down "nfs" + +iterate_test 6 'ok_null' \ + 2 'rpc_set_service_failure_response "knfsd"' \ + 4 'rpc_set_service_failure_response "knfsd"' \ + 6 'rpc_set_service_failure_response "knfsd"' diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.121.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.121.sh new file mode 100644 index 0000000000..062c3f6f5c --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.121.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "lockd down, 15 iterations" + +# This simulates an ongoing failure in the eventscript's automated +# attempts to restart the service. That is, the eventscript is unable +# to restart the service. + +setup_nfs +rpc_services_down "nlockmgr" + +#EVENTSCRIPTS_TESTS_TRACE="sh -x" +iterate_test 15 "ok_null" \ + 10 "rpc_set_service_failure_response 'lockd'" \ + 15 "rpc_set_service_failure_response 'lockd'" diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.122.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.122.sh new file mode 100644 index 0000000000..b93dba7b97 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.122.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "lockd down, 15 iterations, back up after 10" + +# This simulates a success the eventscript's automated attempts to +# restart the service. + +setup_nfs +rpc_services_down "nlockmgr" + +# Iteration 10 should try to restart rpc.lockd. However, our test +# stub rpc.lockd does nothing, so we have to explicitly flag it as up. + +iterate_test 15 "ok_null" \ + 10 "rpc_set_service_failure_response 'lockd'" \ + 11 "rpc_services_up nlockmgr" + diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.131.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.131.sh new file mode 100644 index 0000000000..84d20b761c --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.131.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "rquotad down, 5 iterations" + +setup_nfs +rpc_services_down "rquotad" + +iterate_test 5 'rpc_set_service_failure_response "rquotad"' diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.132.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.132.sh new file mode 100644 index 0000000000..fad9a4c590 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.132.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "rquotad down, 5 iterations, back up after 1" + +# rquotad fails once but then comes back of its own accord after 1 +# failure. + +setup_nfs +rpc_services_down "rquotad" + +iterate_test 5 'ok_null' \ + 1 'rpc_set_service_failure_response "rquotad"' \ + 2 'rpc_services_up "rquotad"' diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.141.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.141.sh new file mode 100644 index 0000000000..377de6e229 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.141.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "statd down, 6 iterations" + +# statd fails and attempts to restart it fail. + +setup_nfs +rpc_services_down "status" + +iterate_test 6 'ok_null' \ + 2 'rpc_set_service_failure_response "statd"' \ + 4 'rpc_set_service_failure_response "statd"' \ + 6 'rpc_set_service_failure_response "statd"' diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.142.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.142.sh new file mode 100644 index 0000000000..3ca3cf64a7 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.142.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "statd down, 8 iterations, back up after 2" + +# statd fails and the first attempt to restart it succeeds. + +setup_nfs +rpc_services_down "status" + +iterate_test 8 'ok_null' \ + 2 'rpc_set_service_failure_response "statd"' \ + 3 'rpc_services_up "status"' diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.151.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.151.sh new file mode 100644 index 0000000000..af2dd26f5d --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.151.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "mountd down, 1 iteration" + +setup_nfs +rpc_services_down "mountd" + +ok_null + +simple_test diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.152.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.152.sh new file mode 100644 index 0000000000..9aad819b74 --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.152.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "mountd down, 10 iterations" + +# This simulates an ongoing failure in the eventscript's automated +# attempts to restart the service. That is, the eventscript is unable +# to restart the service. + +setup_nfs +rpc_services_down "mountd" + +iterate_test 10 "ok_null" \ + 5 "rpc_set_service_failure_response 'mountd'" \ + 10 "rpc_set_service_failure_response 'mountd'" + +#export FAKE_NETSTAT_TCP_ESTABLISHED="10.0.0.1:2049|10.254.254.1:12301 10.0.0.1:2049|10.254.254.1:12302 10.0.0.1:2049|10.254.254.1:12303 10.0.0.1:2049|10.254.254.2:12304 10.0.0.1:2049|10.254.254.2:12305" diff --git a/ctdb/tests/eventscripts/simple/60.nfs.monitor.153.sh b/ctdb/tests/eventscripts/simple/60.nfs.monitor.153.sh new file mode 100644 index 0000000000..6b2750c82c --- /dev/null +++ b/ctdb/tests/eventscripts/simple/60.nfs.monitor.153.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +. "${EVENTSCRIPTS_TESTS_DIR}/common.sh" + +define_test "mountd down, 10 iterations, back up after 5" + +setup_nfs +rpc_services_down "mountd" + +# Iteration 5 should try to restart rpc.mountd. However, our test +# stub rpc.mountd does nothing, so we have to explicitly flag it as +# up. +iterate_test 10 "ok_null" \ + 5 "rpc_set_service_failure_response 'mountd'" \ + 6 "rpc_services_up mountd" diff --git a/ctdb/tests/eventscripts/stubs/ctdb b/ctdb/tests/eventscripts/stubs/ctdb new file mode 100755 index 0000000000..ce06a35cbd --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/ctdb @@ -0,0 +1,166 @@ +#!/bin/sh + +prog="ctdb" + +usage () +{ + cat >&2 <<EOF +Usage: $prog [-Y] cmd + +A fake CTDB stub that prints items depending on the variables +FAKE_CTDB_PNN (default 0) depending on command-line options. + +Note that -Y is ignored. + +EOF + exit 1 +} + +# $POSIXLY_CORRECT means that the command passed to onnode can take +# options and getopt won't reorder things to make them options to this +# script. +_temp=$(getopt -n "$prog" -o "Yvh" -l help -- "$@") || \ + usage + +eval set -- "$_temp" + +verbose=false + +while true ; do + case "$1" in + -Y) shift ;; + -v) verbose=true ; shift ;; + --) shift ; break ;; + -h|--help|*) usage ;; # * shouldn't happen, so this is reasonable. + esac +done + +[ $# -ge 1 ] || usage + +setup_tickles () +{ + # Make sure tickles file exists. + tickles_file="$CTDB_VARDIR/fake-ctdb/tickles" + mkdir -p $(dirname "$tickles_file") + touch "$tickles_file" +} + +setup_pstore () +{ + pstore_dir="$CTDB_VARDIR/fake-ctdb/pstore/$1" + mkdir -p "$pstore_dir" +} + +case "$1" in + ip) + # NOTE: all nodes share the same public addresses file. + + # This is completely stateless and IPs move unnecessarily. + _f="${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}" + if [ -f "$_f" ] ; then + if $verbose ; then + echo ":Public IP:Node:ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:" + + else + echo ":Public IP:Node:" + fi + # Here IPs are distributed across nodes in a stupid way... + _n=0 + while read _ip _ifaces ; do + case "_$ip" in + \#*) : ;; + *) + # Find a node that is up... but don't loop forever. + _orig=$_n + while [ -f "${FAKE_CTDB_NODES_DOWN}/${_n}" ] ; do + _n=$(($_n + 1)) + if [ _n -eq $FAKE_CTDB_NUMNODES ] ; then + _n=0 + fi + if [ $_n -eq $_orig ] ; then + _n=-1 # Never down! :-) + fi + done + if $verbose ; then + # If more than 1 interface, assume all + # addresses are on the 1st. + _first_iface="${_ifaces%%,*}" + # Only show interface if address is on + # this node. + _my_iface="" + if [ "PNN:$_n" = $(ctdb -Y pnn) ]; then + _my_iface="$_first_iface" + fi + echo ":${_ip}:${_n}:${_my_iface}:${_first_iface}:${_ifaces}:" + else + echo ":${_ip}:${_n}:" + fi + esac + done <"$_f" + fi + ;; + pnn|xpnn) + # Defaults to 0 + echo "PNN:${FAKE_CTDB_PNN:-0}" + ;; + gettickles) + setup_tickles + echo ":source ip:port:destination ip:port:" + while read src dst ; do + echo ":${src}:${dst}:" + done <"$tickles_file" + ;; + addtickle) + setup_tickles + echo "$2 $3" >>"$tickles_file" + ;; + deltickle) + setup_tickles + _t=$(grep -F -v "$2 $3" "$tickles_file") + echo "$_t" >"$tickles_file" + ;; + pstore) + setup_pstore "$2" + cat "$4" >"${pstore_dir}/$3" + ;; + pfetch) + setup_pstore "$2" + cat "${pstore_dir}/$3" >"$4" 2>/dev/null + ;; + ifaces) + # Assume -Y. + echo ":Name:LinkStatus:References:" + _f="${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}" + if [ -r "$_f" ] ; then + while read _ip _iface ; do + case "_$ip" in + \#*) : ;; + *) + _status=1 + # For now assume _iface contains only 1. + if [ -f "{FAKE_CTDB_IFACES_DOWN}/${_iface}" ] ; then + _status=0 + fi + # Nobody looks at references + echo ":${_iface}:${_status}:0" + esac + done <"$_f" | + sort -u + fi + ;; + setifacelink) + # Existence of file means CTDB thinks interface is down. + _f="${FAKE_CTDB_IFACES_DOWN}/$2" + case "$3" in + up) rm -f "$_f" ;; + down) touch "$_f" ;; + *) + echo "ctdb setifacelink: unsupported interface status $3" + exit 1 + esac + ;; + *) + echo "${prog}: command \"$1\" not implemented in stub" + exit 1 +esac + diff --git a/ctdb/tests/eventscripts/stubs/ethtool b/ctdb/tests/eventscripts/stubs/ethtool new file mode 100755 index 0000000000..bd173f438f --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/ethtool @@ -0,0 +1,12 @@ +#!/bin/sh + +link="yes" + +if [ -f "${FAKE_ETHTOOL_LINK_DOWN}/${1}" ] ; then + link="no" +fi + +# Expect to add more fields later. +cat <<EOF + Link detected: ${link} +EOF diff --git a/ctdb/tests/eventscripts/stubs/exportfs b/ctdb/tests/eventscripts/stubs/exportfs new file mode 100755 index 0000000000..e3859f901f --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/exportfs @@ -0,0 +1,7 @@ +#!/bin/sh + +opts="10.0.0.0/16" #(rw,async,insecure,no_root_squash,no_subtree_check) + +for i in $FAKE_SHARES ; do + echo "${i} ${opts}" +done diff --git a/ctdb/tests/eventscripts/stubs/ip b/ctdb/tests/eventscripts/stubs/ip new file mode 100755 index 0000000000..d14b06a530 --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/ip @@ -0,0 +1,205 @@ +#!/bin/sh + +: ${FAKE_IP_STATE:=${PWD}/var/fake-ip-state} + +not_implemented () +{ + echo "ip stub command: \"$1\" not implemented" + exit 127 +} + + +case "$1" in + link) + case "$2" in + set) + iface="$3" + case "$4" in + up) + rm -f "${FAKE_IP_STATE}/interfaces-down/${iface}" + ;; + down) + mkdir -p "${FAKE_IP_STATE}/interfaces-down" + touch "${FAKE_IP_STATE}/interfaces-down/${iface}" + ;; + *) + not_implemented "$*" + esac + ;; + *) + not_implemented "$1 $2" + esac + + ;; + addr) + case "$2" in + add) + shift 2 + local="" + dev="" + brd="" + while [ -n "$1" ] ; do + case "$1" in + *.*.*.*/*) + local="$1" ; shift + ;; + local) + local="$2" ; shift 2 + ;; + broadcast|brd) + # For now assume this is always '+'. + if [ "$2" != "+" ] ; then + not_implemented "addr add ... brd $2 ..." + fi + shift 2 + ;; + dev) + dev="$2" ; shift 2 + ;; + *) + not_implemented "addr add ... $1 ..." + esac + done + if [ -z "$dev" ] ; then + not_implemented "addr add (without dev)" + fi + mkdir -p "${FAKE_IP_STATE}/addresses" + pf="${FAKE_IP_STATE}/addresses/${dev}-primary" + sf="${FAKE_IP_STATE}/addresses/${dev}-secondary" + # We could lock here... but we should be the only ones + # playing around here with these stubs. + if [ ! -f "$pf" ] ; then + echo "$local" >"$pf" + elif grep -Fq "$local" "$pf" ; then + echo "RTNETLINK answers: File exists" >&2 + exit 254 + elif [ -f "$sf" ] && grep -Fq "$local" "$sf" ; then + echo "RTNETLINK answers: File exists" >&2 + exit 254 + else + echo "$local" >>"$sf" + fi + ;; + delete|del) + shift 2 + local="" + dev="" + while [ -n "$1" ] ; do + case "$1" in + *.*.*.*/*) + local="$1" ; shift + ;; + local) + local="$2" ; shift 2 + ;; + dev) + dev="$2" ; shift 2 + ;; + *) + not_implemented "addr del ... $1 ..." + esac + done + if [ -z "$dev" ] ; then + not_implemented "addr del (without dev)" + fi + mkdir -p "${FAKE_IP_STATE}/addresses" + pf="${FAKE_IP_STATE}/addresses/${dev}-primary" + sf="${FAKE_IP_STATE}/addresses/${dev}-secondary" + # We could lock here... but we should be the only ones + # playing around here with these stubs. + if [ ! -f "$pf" ] ; then + echo "RTNETLINK answers: Cannot assign requested address" >&2 + exit 254 + elif grep -Fq "$local" "$pf" ; then + # Remove primaries AND SECONDARIES. + rm -f "$pf" "$sf" + elif [ -f "$sf" ] && grep -Fq "$local" "$sf" ; then + grep -Fv "$local" "$sf" >"${sf}.new" + mv "${sf}.new" "$sf" + else + echo "RTNETLINK answers: Cannot assign requested address" >&2 + exit 254 + fi + ;; + show|list) + shift 2 + dev="" + primary=true + secondary=true + while [ -n "$1" ] ; do + case "$1" in + dev) + dev="$2" ; shift 2 + ;; + # Do stupid things and stupid things will happen! + primary) + primary=true ; secondary=false ; shift + ;; + secondary) + secondary=true ; primary=false ; shift + ;; + *) + # Assume an interface name + dev="$1" ; shift 1 + esac + done + devices="$dev" + if [ -z "$devices" ] ; then + # No device specified? Get all the primaries... + devices=$(ls "${FAKE_IP_STATE}/addresses/"*-primary 2>/dev/null | \ + sed -e 's@.*/@@' -e 's@-primary$@@') + fi + calc_brd () + { + case "${local#*/}" in + 24) + brd="${local%.*}.255" + ;; + *) + not_implemented "list ... fake bits other than 24: ${local#*/}" + esac + } + show_iface() + { + pf="${FAKE_IP_STATE}/addresses/${dev}-primary" + sf="${FAKE_IP_STATE}/addresses/${dev}-secondary" + mac=$(echo $dev | md5sum | sed -r -e 's@(..)(..)(..)(..)(..)(..).*@\1:\2:\3:\4:\5:\6@') + cat <<EOF +${n}: ${dev}: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 + link/ether ${mac} brd ff:ff:ff:ff:ff:ff +EOF + if $primary && [ -r "$pf" ] ; then + read local <"$pf" + calc_brd +cat <<EOF + inet ${local} brd ${brd} scope global ${dev} +EOF + fi + if $secondary && [ -r "$sf" ] ; then + while read local ; do + calc_brd +cat <<EOF + inet ${local} brd ${brd} scope global secondary ${dev} +EOF + done <"$sf" + fi +cat <<EOF + valid_lft forever preferred_lft forever +EOF + + } + n=1 + for dev in $devices ; do + show_iface + n=$(($n + 1)) + done + ;; + *) + not_implemented "$1 $2" + esac + ;; + *) + not_implemented "$1" +esac + +exit 0 diff --git a/ctdb/tests/eventscripts/stubs/iptables b/ctdb/tests/eventscripts/stubs/iptables new file mode 100755 index 0000000000..2c65f7ba11 --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/iptables @@ -0,0 +1,5 @@ +#!/bin/sh + +# Always succeed. + +exit 0 diff --git a/ctdb/tests/eventscripts/stubs/kill b/ctdb/tests/eventscripts/stubs/kill new file mode 100755 index 0000000000..b69e3e62a3 --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/kill @@ -0,0 +1,7 @@ +#!/bin/sh + +# Always succeed. This means that kill -0 will always find a +# process and anything else will successfully kill. This should +# exercise a good avriety of code paths. + +exit 0 diff --git a/ctdb/tests/eventscripts/stubs/killall b/ctdb/tests/eventscripts/stubs/killall new file mode 100755 index 0000000000..1e182e1e0d --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/killall @@ -0,0 +1,7 @@ +#!/bin/sh + +# Always succeed. This means that killall -0 will always find a +# process and anything else will successfully kill. This should +# exercise a good avriety of code paths. + +exit 0 diff --git a/ctdb/tests/eventscripts/stubs/net b/ctdb/tests/eventscripts/stubs/net new file mode 100755 index 0000000000..3f96413313 --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/net @@ -0,0 +1,5 @@ +#!/bin/sh + +# Always succeed for now... + +exit 0 diff --git a/ctdb/tests/eventscripts/stubs/netstat b/ctdb/tests/eventscripts/stubs/netstat new file mode 100755 index 0000000000..cf0656651a --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/netstat @@ -0,0 +1,99 @@ +#!/bin/bash + +prog="netstat" + +usage () +{ + cat >&2 <<EOF +Usage: $prog [ -t | --unix ] [ -n ] [ -a ] [ -l ] + +A fake netstat stub that prints items depending on the variables +FAKE_NETSTAT_TCP_ESTABLISHED, FAKE_NETSTAT_TCP_LISTEN, +FAKE_NETSTAT_UNIX_LISTEN, depending on command-line options. + +Note that -n is ignored. + +EOF + exit 1 +} + +# Defaults. +tcp=false +unix=false +all=false +listen=false + +parse_options () +{ + # $POSIXLY_CORRECT means that the command passed to onnode can + # take options and getopt won't reorder things to make them + # options to this script. + _temp=$(POSIXLY_CORRECT=1 getopt -n "$prog" -o "tnalh" -l unix -l help -- "$@") + + [ $? != 0 ] && usage + + eval set -- "$_temp" + + while true ; do + case "$1" in + -n) shift ;; + -a) all=true ; shift ;; + -t) tcp=true ; shift ;; + -l) listen=true ; shift ;; + --unix) unix=true ; shift ;; + --) shift ; break ;; + -h|--help|*) usage ;; # * shouldn't happen, so this is reasonable. + esac + done + + [ $# -gt 0 ] && usage + + # If neither -t or --unix specified then print all. + $tcp || $unix || { tcp=true ; unix=true ; } +} + +parse_options "$@" + +if $tcp ; then + if $listen ; then + echo "Active Internet connections (servers only)" + elif $all ; then + echo "Active Internet connections (servers and established)" + else + echo "Active Internet connections (w/o servers)" + fi + + echo "Proto Recv-Q Send-Q Local Address Foreign Address State" + + tcp_fmt="tcp 0 0 %-23s %-23s %s\n" + for i in $FAKE_NETSTAT_TCP_ESTABLISHED ; do + src="${i%|*}" + dst="${i#*|}" + printf "$tcp_fmt" $src $dst "ESTABLISHED" + done + + if $all || $listen ; then + for i in $FAKE_NETSTAT_TCP_LISTEN ; do + printf "$tcp_fmt" $i "0.0.0.0:*" "LISTEN" + done + fi +fi + +if $unix ; then + if $listen ; then + echo "Active UNIX domain sockets (servers only)" + elif $all ; then + echo "Active UNIX domain sockets (servers and established)" + else + echo "Active UNIX domain sockets (w/o servers)" + fi + + echo "Proto RefCnt Flags Type State I-Node Path" + + unix_fmt="unix 2 [ ACC ] STREAM LISTENING %-8d %s\n" + if $all || $listen ; then + for i in $FAKE_NETSTAT_UNIX_LISTEN ; do + printf "$unix_fmt" 12345 "$i" + done + fi +fi diff --git a/ctdb/tests/eventscripts/stubs/pkill b/ctdb/tests/eventscripts/stubs/pkill new file mode 100755 index 0000000000..b3f1de5a57 --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/pkill @@ -0,0 +1,7 @@ +#!/bin/sh + +# Always succeed. This means that pkill -0 will always find a +# process and anything else will successfully kill. This should +# exercise a good avriety of code paths. + +exit 0 diff --git a/ctdb/tests/eventscripts/stubs/rpc.lockd b/ctdb/tests/eventscripts/stubs/rpc.lockd new file mode 100755 index 0000000000..e71f6cd8ff --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/rpc.lockd @@ -0,0 +1,6 @@ +#!/bin/sh + +# Restart always "works". However, the test infrastructure may +# continue to mark the service as down, so that's what matters. + +exit 0 diff --git a/ctdb/tests/eventscripts/stubs/rpc.mountd b/ctdb/tests/eventscripts/stubs/rpc.mountd new file mode 100755 index 0000000000..e71f6cd8ff --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/rpc.mountd @@ -0,0 +1,6 @@ +#!/bin/sh + +# Restart always "works". However, the test infrastructure may +# continue to mark the service as down, so that's what matters. + +exit 0 diff --git a/ctdb/tests/eventscripts/stubs/rpc.rquotad b/ctdb/tests/eventscripts/stubs/rpc.rquotad new file mode 100755 index 0000000000..e71f6cd8ff --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/rpc.rquotad @@ -0,0 +1,6 @@ +#!/bin/sh + +# Restart always "works". However, the test infrastructure may +# continue to mark the service as down, so that's what matters. + +exit 0 diff --git a/ctdb/tests/eventscripts/stubs/rpc.statd b/ctdb/tests/eventscripts/stubs/rpc.statd new file mode 100755 index 0000000000..e71f6cd8ff --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/rpc.statd @@ -0,0 +1,6 @@ +#!/bin/sh + +# Restart always "works". However, the test infrastructure may +# continue to mark the service as down, so that's what matters. + +exit 0 diff --git a/ctdb/tests/eventscripts/stubs/rpcinfo b/ctdb/tests/eventscripts/stubs/rpcinfo new file mode 100755 index 0000000000..dd175f3d9c --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/rpcinfo @@ -0,0 +1,79 @@ +#!/bin/bash + +prog="rpcinfo" + +usage () +{ + cat >&2 <<EOF +Usage: $prog -u host program [version] + +A fake rpcinfo stub that succeeds for items in FAKE_RPCINFO_SERVICES, +depending on command-line options. + +Note that "-u host" is ignored. + +EOF + exit 1 +} + +parse_options () +{ + # $POSIXLY_CORRECT means that the command passed to onnode can + # take options and getopt won't reorder things to make them + # options to this script. + _temp=$(POSIXLY_CORRECT=1 getopt -n "$prog" -o "u:h" -l unix -l help -- "$@") + + [ $? != 0 ] && usage + + eval set -- "$_temp" + + while true ; do + case "$1" in + -u) shift 2 ;; # ignore + --) shift ; break ;; + -h|--help|*) usage ;; # * shouldn't happen, so this is reasonable. + esac + done + + [ 1 -le $# -a $# -le 2 ] || usage + + p="$1" + v="$2" +} + +parse_options "$@" + +for i in ${FAKE_RPCINFO_SERVICES} ; do + # This is stupidly cummulative, but needs to happen after the + # initial split of the list above. + IFS="${IFS}:" + set -- $i + # $1 = program, $2 = low version, $3 = high version + + if [ "$1" = "$p" ] ; then + if [ -n "$v" ] ; then + if [ "$2" -le "$v" -a "$v" -le "$3" ] ; then + echo "program ${p} version ${v} ready and waiting" + exit 0 + else + echo "rpcinfo: RPC: Program/version mismatch; low version = ${2}, high version = ${3}" >&2 + echo "program ${p} version ${v} is not available" + exit 1 + fi + else + for j in $(seq $2 $3) ; do + echo "program ${p} version ${j} ready and waiting" + done + exit 0 + fi + fi +done + +echo "rpcinfo: RPC: Program not registered" >&2 +if [ -n "$v" ] ; then + echo "program ${p} version ${v} is not available" +else + echo "program ${p} is not available" +fi + +exit 1 diff --git a/ctdb/tests/eventscripts/stubs/service b/ctdb/tests/eventscripts/stubs/service new file mode 100755 index 0000000000..5f47b55e00 --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/service @@ -0,0 +1,64 @@ +#!/bin/sh + +service_status_dir="${EVENTSCRIPTS_TESTS_VAR_DIR}/service_fake_status" +mkdir -p "$service_status_dir" + +service="$1" +flag="${service_status_dir}/${service}" + +start() +{ + if [ -f "$flag" ] ; then + echo "service: can't start ${service} - already running" + exit 1 + else + touch "$flag" + echo "Starting ${service}: OK" + fi +} + +stop () +{ + if [ -f "$flag" ] ; then + echo "Stopping ${service}: OK" + rm -f "$flag" + else + echo "service: can't stop ${service} - not running" + exit 1 + fi +} + +case "$2" in + start) + start + ;; + stop) + stop + ;; + restart|reload) + stop + start + ;; + status) + if [ -f "$flag" ] ; then + echo "$service running" + exit 0 + else + echo "$service not running" + exit 3 + fi + ;; + force-started) + # For test setup... + touch "$flag" + ;; + force-stopped) + # For test setup... + rm -f "$flag" + ;; + *) + echo "service $service $2 not supported" + exit 1 +esac + +exit 0 diff --git a/ctdb/tests/eventscripts/stubs/testparm b/ctdb/tests/eventscripts/stubs/testparm new file mode 100755 index 0000000000..83aa578673 --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/testparm @@ -0,0 +1,36 @@ +#!/bin/sh + +# Ensure that testparm always uses our canned configuration instead of +# the global one, unless some other file is specified. This requires +# testparm to be installed but is quicker than reimplementing all the +# various command-line options. + +file_specified=false +for i ; do + case "$i" in + -*) : ;; + *) file_specified=true + esac +done + +if $file_specified ; then + # This should include the shares, since this is used when the + # samba eventscript caches the output. + /usr/bin/testparm "$@" +else + # We force our own smb.conf and add the shares. + /usr/bin/testparm "$@" "${CTDB_ETCDIR}/samba/smb.conf" + + for i in $FAKE_SHARES ; do + bi=$(basename "$i") +cat <<EOF + +[${bi}] + path = $i + comment = fake share $bi + guest ok = no + read only = no + browseable = yes +EOF + done +fi diff --git a/ctdb/tests/eventscripts/stubs/wbinfo b/ctdb/tests/eventscripts/stubs/wbinfo new file mode 100755 index 0000000000..4fc6b98331 --- /dev/null +++ b/ctdb/tests/eventscripts/stubs/wbinfo @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ "$FAKE_WBINFO_FAIL" = "yes" ] ; then + exit 1 +fi + +exit 0 |