5 export CTDB_TEST_MODE="yes"
7 # Following 2 lines may be modified by installation script
8 CTDB_TESTS_ARE_INSTALLED=false
9 CTDB_TEST_DIR=$(dirname "$0")
10 export CTDB_TESTS_ARE_INSTALLED CTDB_TEST_DIR
12 export TEST_SCRIPTS_DIR="${CTDB_TEST_DIR}/scripts"
14 . "${TEST_SCRIPTS_DIR}/common.sh"
16 # common.sh will set TEST_SUBDIR to a stupid value when installed
17 # because common.sh is usually sourced by a test. TEST_SUBDIR needs
18 # to be correctly set so setup_ctdb_base() finds the etc-ctdb/
19 # subdirectory and the test event script is correctly installed, so
21 TEST_SUBDIR="$CTDB_TEST_DIR"
23 if ! $CTDB_TESTS_ARE_INSTALLED ; then
24 hdir="$CTDB_SCRIPTS_HELPER_BINDIR"
25 export CTDB_EVENTD="${hdir}/ctdb-eventd"
26 export CTDB_EVENT_HELPER="${hdir}/ctdb-event"
27 export CTDB_LOCK_HELPER="${hdir}/ctdb_lock_helper"
28 export CTDB_RECOVERY_HELPER="${hdir}/ctdb_recovery_helper"
29 export CTDB_TAKEOVER_HELPER="${hdir}/ctdb_takeover_helper"
30 export CTDB_CLUSTER_MUTEX_HELPER="${hdir}/ctdb_mutex_fcntl_helper"
33 ########################################
35 # If the given IP is hosted then print 2 items: maskbits and iface
45 _t=$(ip addr show to "${_addr}/${_bits}")
55 for _i in $(seq 0 $((_num_nodes - 1)) ) ; do
57 _j=$(printf "%04x" $((0x5f00 + 1 + _i)) )
58 _node_ip="fd00::5357:${_j}"
59 if have_ip "$_node_ip" ; then
63 ERROR: ${_node_ip} not on an interface, please add it
69 _d=$(( 1 + (_i % 100) ))
70 echo "127.0.${_c}.${_d}"
74 # Fail if we don't have all of the IPv6 addresses assigned
78 setup_public_addresses ()
84 for _i in $(seq 0 $((_num_nodes - 1)) ) ; do
85 if [ "$_i" -eq "$_node_no_ips" ] ; then
89 # 2 public addresses on most nodes, just to make
92 printf 'fc00:10::1:%x/64 lo\n' $((1 + _i))
93 printf 'fc00:10::2:%x/64 lo\n' $((1 + _i))
95 _c1=$(( 100 + (_i / 100) ))
96 _c2=$(( 200 + (_i / 100) ))
97 _d=$(( 1 + (_i % 100) ))
98 printf '192.168.%d.%d/24 lo\n' "$_c1" "$_d"
99 printf '192.168.%d.%d/24 lo\n' "$_c2" "$_d"
104 setup_socket_wrapper ()
106 _socket_wrapper_so="$1"
108 _so="${directory}/libsocket-wrapper.so"
109 if [ ! -f "$_socket_wrapper_so" ] ; then
110 die "$0 setup: Unable to find ${_socket_wrapper_so}"
113 # Find absoluate path if only relative is given
114 case "$_socket_wrapper_so" in
116 *) _socket_wrapper_so="${PWD}/${_socket_wrapper_so}" ;;
120 ln -s "$_socket_wrapper_so" "$_so"
127 local_daemons_setup_usage ()
130 $0 <directory> setup [ <options>... ]
133 -F Disable failover (default: failover enabled)
134 -N <file> Nodes file (default: automatically generated)
135 -n <num> Number of nodes (default: 3)
136 -P <file> Public addresses file (default: automatically generated)
137 -R Use a command for the recovery lock (default: use a file)
138 -S <library> Socket wrapper shared library to preload (default: none)
139 -6 Generate IPv6 IPs for nodes, public addresses (default: IPv4)
145 local_daemons_setup ()
147 _disable_failover=false
150 _public_addresses_file=""
151 _recovery_lock_use_command=false
157 while getopts "FN:n:P:RS:6h?" _opt ; do
159 F) _disable_failover=true ;;
160 N) _nodes_file="$OPTARG" ;;
161 n) _num_nodes="$OPTARG" ;;
162 P) _public_addresses_file="$OPTARG" ;;
163 R) _recovery_lock_use_command=true ;;
164 S) _socket_wrapper="$OPTARG" ;;
166 \?|h) local_daemons_setup_usage ;;
169 shift $((OPTIND - 1))
171 mkdir -p "$directory"
173 _nodes_all="${directory}/nodes"
174 if [ -n "$_nodes_file" ] ; then
175 cp "$_nodes_file" "$_nodes_all"
177 setup_nodes "$_num_nodes" $_use_ipv6 >"$_nodes_all"
180 # If there are (strictly) greater than 2 nodes then we'll
181 # "randomly" choose a node to have no public addresses
183 if [ "$_num_nodes" -gt 2 ] ; then
184 _node_no_ips=$(($$ % _num_nodes))
187 _public_addresses_all="${directory}/public_addresses"
188 if [ -n "$_public_addresses_file" ] ; then
189 cp "$_public_addresses_file" "$_public_addresses_all"
191 setup_public_addresses "$_num_nodes" \
193 $_use_ipv6 >"$_public_addresses_all"
196 _recovery_lock="${directory}/rec.lock"
197 if $_recovery_lock_use_command ; then
198 _helper="${CTDB_SCRIPTS_HELPER_BINDIR}/ctdb_mutex_fcntl_helper"
199 _recovery_lock="! ${_helper} ${_recovery_lock}"
202 if [ -n "$_socket_wrapper" ] ; then
203 setup_socket_wrapper "$_socket_wrapper"
206 for _n in $(seq 0 $((_num_nodes - 1))) ; do
207 setup_ctdb_base "$directory" "node.${_n}" \
208 functions notify.sh debug-hung-script.sh
210 cp "$_nodes_all" "${CTDB_BASE}/nodes"
212 _public_addresses="${CTDB_BASE}/public_addresses"
214 if [ -z "$_public_addresses_file" ] && \
215 [ $_node_no_ips -eq "$_n" ] ; then
216 echo "Node ${_n} will have no public IPs."
217 : >"$_public_addresses"
219 cp "$_public_addresses_all" "$_public_addresses"
222 _node_ip=$(sed -n -e "$((_n + 1))p" "$_nodes_all")
224 _db_dir="${CTDB_BASE}/db"
225 for _d in "volatile" "persistent" "state" ; do
226 mkdir -p "${_db_dir}/${_d}"
229 cat >"${CTDB_BASE}/ctdb.conf" <<EOF
231 location = file:${CTDB_BASE}/log.ctdb
235 recovery lock = ${_recovery_lock}
236 node address = ${_node_ip}
239 volatile database directory = ${_db_dir}/volatile
240 persistent database directory = ${_db_dir}/persistent
241 state database directory = ${_db_dir}/state
244 disabled = ${_disable_failover}
247 debug script = debug-hung-script.sh
252 local_daemons_ssh_usage ()
255 usage: $0 <directory> ssh [ -n ] <ip> <command>
263 if [ $# -lt 2 ] ; then
264 local_daemons_ssh_usage
267 # Only try to respect ssh -n option, others can't be used so discard them
269 while getopts "nh?" _opt ; do
271 n) _close_stdin=true ;;
272 \?|h) local_daemons_ssh_usage ;;
276 shift $((OPTIND - 1))
278 if [ $# -lt 2 ] ; then
279 local_daemons_ssh_usage
282 _nodes="${directory}/nodes"
284 # IP adress of node. onnode can pass hostnames but not in these tests
289 # Determine the correct CTDB base directory
290 _num=$(awk -v ip="$_ip" '$1 == ip { print NR }' "$_nodes")
292 export CTDB_BASE="${directory}/node.${_node}"
294 if [ ! -d "$CTDB_BASE" ] ; then
295 die "$0 ssh: Unable to find base for node ${_ip}"
298 if $_close_stdin ; then
307 # onnode will execute this, which fakes ssh against local daemons
308 export ONNODE_SSH="${0} ${directory} ssh"
310 # onnode just needs the nodes file, so use the common one
311 export CTDB_BASE="$directory"
314 local_daemons_generic_usage ()
317 usage: $0 <directory> ${1} <nodes>
319 <nodes> can be "all", a node number or any specification supported by onnode
325 local_daemons_start_socket_wrapper ()
327 _so="${directory}/libsocket-wrapper.so"
330 if [ -d "$_d" ] && [ -f "$_so" ] ; then
331 export SOCKET_WRAPPER_DIR="$_d"
332 export LD_PRELOAD="$_so"
336 local_daemons_start ()
338 if [ $# -ne 1 ] || [ "$1" = "-h" ] ; then
339 local_daemons_generic_usage "start"
342 local_daemons_start_socket_wrapper
348 onnode "$_nodes" "${VALGRIND:-} ctdbd &"
351 local_daemons_stop ()
353 if [ $# -ne 1 ] || [ "$1" = "-h" ] ; then
354 local_daemons_generic_usage "stop"
361 onnode -p "$_nodes" "${VALGRIND:-} ${CTDB:-ctdb} shutdown"
364 local_daemons_onnode_usage ()
367 usage: $0 <directory> onnode <nodes> <command>...
369 <nodes> can be "all", a node number or any specification supported by onnode
375 local_daemons_onnode ()
377 if [ $# -lt 2 ] || [ "$1" = "-h" ] ; then
378 local_daemons_onnode_usage
386 onnode "$_nodes" "$@"
389 local_daemons_print_socket ()
391 if [ $# -ne 1 ] || [ "$1" = "-h" ] ; then
392 local_daemons_generic_usage "print-socket"
400 _path="${CTDB_SCRIPTS_HELPER_BINDIR}/ctdb-path"
401 onnode -q "$_nodes" "${VALGRIND:-} ${_path} socket ctdbd"
404 local_daemons_print_log ()
406 if [ $# -ne 1 ] || [ "$1" = "-h" ] ; then
407 local_daemons_generic_usage "print-log"
415 # shellcheck disable=SC2016
416 # $CTDB_BASE must only be expanded under onnode, not in top-level shell
417 onnode -q "$_nodes" 'echo ${CTDB_BASE}/log.ctdb' |
418 while IFS='' read -r _l ; do
419 _dir=$(dirname "$_l")
420 _node=$(basename "$_dir")
421 # Add fake hostname after date and time, which are the
422 # first 2 words on each line
423 sed -e "s|^\\([^ ][^ ]* [^ ][^ ]*\\)|\\1 ${_node}|" "$_l"
432 usage: $0 <directory> <command> [ <options>... ]
435 setup Set up daemon configuration according to given options
436 start Start specified daemon(s)
437 stop Stop specified daemon(s)
438 onnode Run a command in the environment of specified daemon(s)
439 print-socket Print the Unix domain socket used by specified daemon(s)
440 print-log Print logs for specified daemon(s) to stdout
442 All commands use <directory> for daemon configuration
444 Run command with -h option to see per-command usage
450 if [ $# -lt 2 ] ; then
459 setup) local_daemons_setup "$@" ;;
460 ssh) local_daemons_ssh "$@" ;; # Internal, not shown by usage()
461 start) local_daemons_start "$@" ;;
462 stop) local_daemons_stop "$@" ;;
463 onnode) local_daemons_onnode "$@" ;;
464 print-socket) local_daemons_print_socket "$@" ;;
465 print-log) local_daemons_print_log "$@" ;;