1 # Hey Emacs, this is a -*- shell-script -*- !!! :-)
4 # Augment PATH with relevant stubs/ directories.
7 stubs_dir
="${CTDB_TEST_SUITE_DIR}/stubs"
8 [ -d "${stubs_dir}" ] || die
"Failed to locate stubs/ subdirectory"
10 # Make the path absolute for tests that change directory
13 *) stubs_dir
="${PWD}/${stubs_dir}" ;;
16 # Use stubs as helpers
17 export CTDB_HELPER_BINDIR
="$stubs_dir"
19 PATH
="${stubs_dir}:${PATH}"
23 # Force this to be absolute - event scripts can change directory
24 CTDB_TEST_TMP_DIR
=$
(cd "$CTDB_TEST_TMP_DIR" && echo "$PWD")
26 export CTDB_LOGGING
="file:${CTDB_TEST_TMP_DIR}/log.ctdb"
27 touch "${CTDB_LOGGING#file:}" ||
28 die
"Unable to setup logging for \"$CTDB_LOGGING\""
30 if [ -d "${CTDB_TEST_SUITE_DIR}/etc" ]; then
31 cp -a "${CTDB_TEST_SUITE_DIR}/etc" "$CTDB_TEST_TMP_DIR"
32 export CTDB_SYS_ETCDIR
="${CTDB_TEST_TMP_DIR}/etc"
34 die
"Unable to setup \$CTDB_SYS_ETCDIR"
37 setup_ctdb_base
"$CTDB_TEST_TMP_DIR" "etc-ctdb" \
41 nfs-linux-kernel-callout \
44 export FAKE_CTDB_STATE
="${CTDB_TEST_TMP_DIR}/fake-ctdb"
45 mkdir
-p "$FAKE_CTDB_STATE"
47 export FAKE_NETWORK_STATE
="${CTDB_TEST_TMP_DIR}/fake-network-state"
48 mkdir
-p "$FAKE_NETWORK_STATE"
50 ######################################################################
52 if "$CTDB_TEST_VERBOSE"; then
68 ######################################################################
70 # General setup fakery
72 # Default is to use script name with ".options" appended. With
73 # arguments, this can specify an alternate script name (and
75 setup_script_options
()
79 elif [ $# -eq 0 ]; then
82 die
"usage: setup_script_options [ component script ]"
85 if [ -n "$_script" ]; then
86 _options
="${CTDB_BASE}/events/legacy/${_script}.options"
88 _options
="${script_dir}/${script%.script}.options"
93 # Source the options so that tests can use the variables
99 export CTDB_DBDIR_BASE
="${CTDB_TEST_TMP_DIR}/db"
100 CTDB_DBDIR
="${CTDB_DBDIR_BASE}/volatile"
101 CTDB_DBDIR_PERSISTENT
="${CTDB_DBDIR_BASE}/persistent"
102 CTDB_DBDIR_STATE
="${CTDB_DBDIR_BASE}/state"
103 cat >>"${CTDB_BASE}/ctdb.conf" <<EOF
105 volatile database directory = ${CTDB_DBDIR}
106 persistent database directory = ${CTDB_DBDIR_PERSISTENT}
107 state database directory = ${CTDB_DBDIR_STATE}
109 mkdir
-p "$CTDB_DBDIR"
110 mkdir
-p "$CTDB_DBDIR_PERSISTENT"
111 mkdir
-p "$CTDB_DBDIR_STATE"
116 export FAKE_DATE_OUTPUT
="$1"
121 export FAKE_TCP_LISTEN
="$*"
127 FAKE_TCP_LISTEN
="${FAKE_TCP_LISTEN} ${_i}"
134 debug
"Marking TCP port \"${_port}\" as not listening"
137 for _i
in $FAKE_TCP_LISTEN; do
138 if [ "$_i" = "$_port" ]; then
144 FAKE_TCP_LISTEN
="$_t"
149 export FAKE_NETSTAT_UNIX_LISTEN
="$*"
152 unix_socket_listening
()
156 FAKE_NETSTAT_UNIX_LISTEN
="${FAKE_NETSTAT_UNIX_LISTEN} ${_s}"
161 debug
"Setting up shares (3 existing shares)"
162 # Create 3 fake shares/exports.
163 export FAKE_SHARES
=""
164 for i
in $
(seq 1 3); do
165 _s
="${CTDB_TEST_TMP_DIR}/shares/share${i}"
167 FAKE_SHARES
="${FAKE_SHARES}${FAKE_SHARES:+ }${_s}"
173 # Mark some shares as non-existent
182 for _i
in $FAKE_SHARES; do
184 if [ $_n -ne "$_j" ]; then
188 debug
"Mark share $_n as missing share \"$_i\""
190 _t
=$
(printf "ERROR: %s directory \"%s\" not available" \
192 _out
="${_out}${_out:+${_nl}}${_t}"
202 FAKE_ETHTOOL_LINK_DOWN
="${FAKE_NETWORK_STATE}/ethtool-link-down"
203 export FAKE_ETHTOOL_LINK_DOWN
204 mkdir
-p "$FAKE_ETHTOOL_LINK_DOWN"
207 ethtool_interfaces_down
()
212 echo "Marking interface $_i DOWN for ethtool"
213 touch "${FAKE_ETHTOOL_LINK_DOWN}/${_i}"
217 ethtool_interfaces_up
()
222 echo "Marking interface $_i UP for ethtool"
223 rm -f "${FAKE_ETHTOOL_LINK_DOWN}/${_i}"
229 echo "# ip rule show"
233 while read -r _p _ _i _ _t
; do
234 # Remove trailing colon after priority/preference.
236 # Only remove rules that match our priority/preference.
237 [ "$CTDB_PER_IP_ROUTING_RULE_PREF" = "$_p" ] ||
continue
239 echo "# ip route show table $_t"
240 ip route show table
"$_t"
244 # Copied from 13.per_ip_routing for now... so this is lazy testing :-(
245 ipv4_host_addr_to_net
()
250 # Convert the host address to an unsigned long by splitting out
251 # the octets and doing the math.
255 # shellcheck disable=SC2086
256 # Intentional word splitting
259 _host_ul
=$
(((_host_ul
<< 8) + _o)) # work around Emacs color bug
262 # Calculate the mask and apply it.
263 _mask_ul=$((0xffffffff << (32 - _maskbits)))
264 _net_ul=$((_host_ul & _mask_ul))
266 # Now convert to a network address one byte at a time.
268 for _o in $(seq 1 4); do
269 _net="$((_net_ul & 255))${_net:+.}${_net}"
270 _net_ul=$((_net_ul >> 8))
273 echo "${_net}/${_maskbits}"
276 ######################################################################
280 # shellcheck disable=SC2120
281 # Argument can be used in testcases
284 export FAKE_CTDB_NUMNODES
="${1:-3}"
285 echo "Setting up CTDB with ${FAKE_CTDB_NUMNODES} fake nodes"
288 # For now this creates the same public addresses each time. However,
289 # it could be made more flexible.
290 setup_public_addresses
()
292 _f
="${CTDB_BASE}/public_addresses"
294 echo "Setting up public addresses in ${_f}"
308 # Needed for IP allocation
312 # Need to cope with ctdb_get_pnn(). If a test changes PNN then it
313 # needs to be using a different state directory, otherwise the wrong
314 # PNN can already be cached in the state directory.
317 export FAKE_CTDB_PNN
="$1"
318 echo "Setting up PNN ${FAKE_CTDB_PNN}"
320 CTDB_SCRIPT_VARDIR
="${CTDB_TEST_TMP_DIR}/scripts/${FAKE_CTDB_PNN}"
321 export CTDB_SCRIPT_VARDIR
322 mkdir
-p "$CTDB_SCRIPT_VARDIR"
325 ctdb_get_interfaces
()
327 ctdb ifaces
-X |
awk -F'|' 'FNR > 1 {print $2}' |
xargs
330 ctdb_get_1_interface
()
332 _t
=$
(ctdb_get_interfaces
)
336 # Print public addresses on this node as: interface IP maskbits
337 # Each line is suitable for passing to takeip/releaseip
338 ctdb_get_my_public_addresses
()
341 read -r _
# skip header line
343 while IFS
="|" read -r _ _ip _ _iface _
; do
344 [ -n "$_iface" ] ||
continue
345 while IFS
="/$IFS" read -r _i _maskbits _
; do
346 if [ "$_ip" = "$_i" ]; then
347 echo "$_iface $_ip $_maskbits"
350 done <"${CTDB_BASE}/public_addresses"
355 # Prints the 1st public address as: interface IP maskbits
356 # This is suitable for passing to takeip/releaseip
357 ctdb_get_1_public_address
()
359 ctdb_get_my_public_addresses |
{
365 # Check the routes against those that are expected. $1 is the number
366 # of assigned IPs to use (<num>, all), defaulting to 1. If $2 is
367 # "default" then expect default routes to have been added.
371 _should_add_default
="$2"
376 ctdb_get_my_public_addresses |
377 if [ "$_num_ips" = "all" ]; then
385 while read -r _dev _ip _bits
; do
386 _net
=$
(ipv4_host_addr_to_net
"$_ip" "$_bits")
387 _gw
="${_net%.*}.254" # a dumb, calculated default
389 _policy_rules
="${_policy_rules}
390 ${CTDB_PER_IP_ROUTING_RULE_PREF}: from $_ip lookup ctdb.$_ip "
391 _policy_routes
="${_policy_routes}
392 # ip route show table ctdb.$_ip
393 $_net dev $_dev scope link "
395 if [ "$_should_add_default" = "default" ]; then
396 _policy_routes
="${_policy_routes}
397 default via $_gw dev $_dev "
403 0: from all lookup local ${_policy_rules}
404 32766: from all lookup main
405 32767: from all lookup default ${_policy_routes}
408 simple_test_command dump_routes
412 ######################################################################
416 _etc
="$CTDB_SYS_ETCDIR" # shortcut for readability
417 for _c
in "$_etc/sysconfig/nfs" "$_etc/default/nfs" "$_etc/ctdb/sysconfig/nfs"; do
418 if [ -r "$_c" ]; then
427 export CTDB_NFS_CALLOUT
="${CTDB_HELPER_BINDIR}/nfs-fake-callout"
428 export NFS_FAKE_CALLOUT_MAGIC
="$1"
431 program_stack_trace
()
437 Stack trace for ${_prog}[${_pid}]:
438 [<ffffffff87654321>] fake_stack_trace_for_pid_${_pid}/stack+0x0/0xff
442 ######################################################################
444 # Result and test functions
446 ############################################################
450 die
"setup() is not defined"
453 # Set some globals and print the summary.
458 _f
=$
(basename "$0" ".sh")
460 # Remaining format should be NN.script.event.NUM or
461 # NN.script.NUM or script.NUM:
469 script="${_f%.*}.script"
473 script="${_f}.script"
477 # "Enable" the script
478 _subdir
="events/legacy"
479 script_dir
="${CTDB_BASE}/${_subdir}"
480 # Symlink target needs to be absolute
481 case "$CTDB_SCRIPTS_DATA_DIR" in
482 /*) _data_dir
="${CTDB_SCRIPTS_DATA_DIR}/${_subdir}" ;;
483 *) _data_dir
="${PWD}/${CTDB_SCRIPTS_DATA_DIR}/${_subdir}" ;;
485 mkdir
-p "$script_dir"
486 ln -s "${_data_dir}/${script}" "$script_dir"
492 script_dir
="${CTDB_BASE}"
496 _s
="${script_dir}/${script}"
498 die
"Internal error - unable to find script \"${_s}\""
501 *.
script) script_short
="${script%.script}" ;;
502 *.sh
) script_short
="${script%.sh}" ;;
503 *) script_short
="$script" ;;
506 printf "%-17s %-10s %-4s - %s\n\n" \
507 "$script_short" "$event" "$_num" "$desc"
509 _f
="${CTDB_TEST_SUITE_DIR}/scripts/${script_short}.sh"
510 if [ -r "$_f" ]; then
517 # Run an eventscript once. The test passes if the return code and
518 # output match those required.
520 # Any args are passed to the eventscript.
524 [ -n "$event" ] || die
'simple_test: event not set'
528 # shellcheck disable=SC2317
529 # used in unit_test(), etc.
532 echo "Running script \"$script $event${args:+ }$args\""
535 # shellcheck disable=SC2317
536 # used in unit_test(), etc.
541 ##################################################
542 CTDB_BASE="$CTDB_BASE"
543 CTDB_SYS_ETCDIR="$CTDB_SYS_ETCDIR"
544 ctdb client is "$(which ctdb)"
545 ip command is "$(which ip)"
549 script_test
"${script_dir}/${script}" "$event" "$@"
557 # If something has previously failed then don't continue.
563 echo "=================================================="
567 simple_test_command
()
569 unit_test_notrace
"$@"