ctdb-tests: Avoid ShellCheck warnings
[Samba.git] / ctdb / tests / UNIT / eventscripts / scripts / local.sh
blob39a2a087a2189e276a1e6954dc915c73f826e5e9
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
11 case "$stubs_dir" in
12 /*) : ;;
13 *) stubs_dir="${PWD}/${stubs_dir}" ;;
14 esac
16 # Use stubs as helpers
17 export CTDB_HELPER_BINDIR="$stubs_dir"
19 PATH="${stubs_dir}:${PATH}"
21 export CTDB="ctdb"
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"
33 else
34 die "Unable to setup \$CTDB_SYS_ETCDIR"
37 setup_ctdb_base "$CTDB_TEST_TMP_DIR" "etc-ctdb" \
38 debug_locks.sh \
39 functions \
40 nfs-checks.d \
41 nfs-linux-kernel-callout \
42 statd-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
53 debug()
55 if [ -n "$1" ]; then
56 echo "$@" >&2
57 else
58 cat >&2
61 else
62 debug()
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
74 # component).
75 setup_script_options()
77 if [ $# -eq 2 ]; then
78 _script="$2"
79 elif [ $# -eq 0 ]; then
80 _script=""
81 else
82 die "usage: setup_script_options [ component script ]"
85 if [ -n "$_script" ]; then
86 _options="${CTDB_BASE}/events/legacy/${_script}.options"
87 else
88 _options="${script_dir}/${script%.script}.options"
91 cat >>"$_options"
93 # Source the options so that tests can use the variables
94 . "$_options"
97 setup_dbdir()
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
104 [database]
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"
114 setup_date()
116 export FAKE_DATE_OUTPUT="$1"
119 setup_tcp_listen()
121 export FAKE_TCP_LISTEN="$*"
124 tcp_port_listening()
126 for _i; do
127 FAKE_TCP_LISTEN="${FAKE_TCP_LISTEN} ${_i}"
128 done
131 tcp_port_down()
133 _port="$1"
134 debug "Marking TCP port \"${_port}\" as not listening"
136 _t=""
137 for _i in $FAKE_TCP_LISTEN; do
138 if [ "$_i" = "$_port" ]; then
139 continue
141 _t="${_t} ${_i}"
142 done
144 FAKE_TCP_LISTEN="$_t"
147 setup_unix_listen()
149 export FAKE_NETSTAT_UNIX_LISTEN="$*"
152 unix_socket_listening()
154 _s="$1"
156 FAKE_NETSTAT_UNIX_LISTEN="${FAKE_NETSTAT_UNIX_LISTEN} ${_s}"
159 setup_shares()
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}"
166 mkdir -p "$_s"
167 FAKE_SHARES="${FAKE_SHARES}${FAKE_SHARES:+ }${_s}"
168 done
171 shares_missing()
173 # Mark some shares as non-existent
174 _type="$1"
175 shift
177 _out=""
178 _nl="
181 _n=1
182 for _i in $FAKE_SHARES; do
183 for _j; do
184 if [ $_n -ne "$_j" ]; then
185 continue
188 debug "Mark share $_n as missing share \"$_i\""
189 rmdir "$_i"
190 _t=$(printf "ERROR: %s directory \"%s\" not available" \
191 "$_type" "${_i}")
192 _out="${_out}${_out:+${_nl}}${_t}"
193 done
194 _n=$((_n + 1))
195 done
197 echo "$_out"
200 _ethtool_setup()
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()
209 _ethtool_setup
211 for _i; do
212 echo "Marking interface $_i DOWN for ethtool"
213 touch "${FAKE_ETHTOOL_LINK_DOWN}/${_i}"
214 done
217 ethtool_interfaces_up()
219 _ethtool_setup
221 for _i; do
222 echo "Marking interface $_i UP for ethtool"
223 rm -f "${FAKE_ETHTOOL_LINK_DOWN}/${_i}"
224 done
227 dump_routes()
229 echo "# ip rule show"
230 ip rule show
232 ip rule show |
233 while read -r _p _ _i _ _t; do
234 # Remove trailing colon after priority/preference.
235 _p="${_p%:}"
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"
241 done
244 # Copied from 13.per_ip_routing for now... so this is lazy testing :-(
245 ipv4_host_addr_to_net()
247 _host="$1"
248 _maskbits="$2"
250 # Convert the host address to an unsigned long by splitting out
251 # the octets and doing the math.
252 _host_ul=0
253 for _o in $(
254 export IFS="."
255 # shellcheck disable=SC2086
256 # Intentional word splitting
257 echo $_host
258 ); do
259 _host_ul=$(((_host_ul << 8) + _o)) # work around Emacs color bug
260 done
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.
267 _net=""
268 for _o in $(seq 1 4); do
269 _net="$((_net_ul & 255))${_net:+.}${_net}"
270 _net_ul=$((_net_ul >> 8))
271 done
273 echo "${_net}/${_maskbits}"
276 ######################################################################
278 # CTDB fakery
280 # shellcheck disable=SC2120
281 # Argument can be used in testcases
282 setup_numnodes()
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}"
295 cat >"$_f" <<EOF
296 # This is a comment
297 10.0.0.1/24 dev123
298 10.0.0.2/24 dev123
299 10.0.0.3/24 dev123
300 10.0.0.4/24 dev123
301 10.0.0.5/24 dev123
302 10.0.0.6/24 dev123
303 10.0.1.1/24 dev456
304 10.0.1.2/24 dev456
305 10.0.1.3/24 dev456
308 # Needed for IP allocation
309 setup_numnodes
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.
315 ctdb_set_pnn()
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)
333 echo "${_t%% *}"
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()
340 ctdb ip -v -X | {
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"
348 break
350 done <"${CTDB_BASE}/public_addresses"
351 done
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 | {
360 head -n 1
361 cat >/dev/null
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.
368 check_routes()
370 _num_ips="${1:-1}"
371 _should_add_default="$2"
373 _policy_rules=""
374 _policy_routes=""
376 ctdb_get_my_public_addresses |
377 if [ "$_num_ips" = "all" ]; then
379 else
381 head -n "$_num_ips"
382 cat >/dev/null
384 fi | {
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 "
399 done
401 ok <<EOF
402 # ip rule show
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
409 } || test_fail
412 ######################################################################
414 nfs_load_config()
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
419 . "$_c"
420 break
422 done
425 setup_nfs_callout()
427 export CTDB_NFS_CALLOUT="${CTDB_HELPER_BINDIR}/nfs-fake-callout"
428 export NFS_FAKE_CALLOUT_MAGIC="$1"
431 program_stack_trace()
433 _prog="$1"
434 _pid="$2"
436 cat <<EOF
437 Stack trace for ${_prog}[${_pid}]:
438 [<ffffffff87654321>] fake_stack_trace_for_pid_${_pid}/stack+0x0/0xff
442 ######################################################################
444 # Result and test functions
446 ############################################################
448 setup()
450 die "setup() is not defined"
453 # Set some globals and print the summary.
454 define_test()
456 desc="$1"
458 _f=$(basename "$0" ".sh")
460 # Remaining format should be NN.script.event.NUM or
461 # NN.script.NUM or script.NUM:
462 _num="${_f##*.}"
463 _f="${_f%.*}"
465 case "$_f" in
466 [0-9][0-9].*)
467 case "$_f" in
468 [0-9][0-9].*.*)
469 script="${_f%.*}.script"
470 event="${_f##*.}"
472 [0-9][0-9].*)
473 script="${_f}.script"
474 unset event
476 esac
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}" ;;
484 esac
485 mkdir -p "$script_dir"
486 ln -s "${_data_dir}/${script}" "$script_dir"
489 script="${_f%.*}"
490 script="$_f"
491 unset event
492 script_dir="${CTDB_BASE}"
494 esac
496 _s="${script_dir}/${script}"
497 [ -r "$_s" ] ||
498 die "Internal error - unable to find script \"${_s}\""
500 case "$script" in
501 *.script) script_short="${script%.script}" ;;
502 *.sh) script_short="${script%.sh}" ;;
503 *) script_short="$script" ;;
504 esac
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
511 . "$_f"
514 ctdb_set_pnn 0
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.
522 simple_test()
524 [ -n "$event" ] || die 'simple_test: event not set'
526 args="$*"
528 # shellcheck disable=SC2317
529 # used in unit_test(), etc.
530 test_header()
532 echo "Running script \"$script $event${args:+ }$args\""
535 # shellcheck disable=SC2317
536 # used in unit_test(), etc.
537 extra_header()
539 cat <<EOF
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" "$@"
551 reset_test_header
552 reset_extra_header
555 simple_test_event()
557 # If something has previously failed then don't continue.
558 : "${_passed:=true}"
559 $_passed || return 1
561 event="$1"
562 shift
563 echo "=================================================="
564 simple_test "$@"
567 simple_test_command()
569 unit_test_notrace "$@"