3 # All pairwise combinations of node failures.
6 # Author: Chris Cooper <ccooper@clusterfs.com>
8 # Script fails pair of nodes:
9 # -- in parallel by default
10 # -- in series if SERIAL is set
12 LUSTRE=${LUSTRE:-`dirname $0`/..}
14 CLEANUP=${CLEANUP:-""}
15 . $LUSTRE/tests/test-framework.sh
19 . ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
20 TESTSUITELOG=${TESTSUITELOG:-$TMP/$(basename $0 .sh)}
21 DEBUGLOG=$TESTSUITELOG.debug
26 echo "--- env ---" >&2
28 echo "--- env ---" >&2
31 [ "$SHARED_DIRECTORY" ] || \
32 { skip "$0: Empty SHARED_DIRECTORY" && exit 0; }
34 [ -n "$CLIENTS" ] || { skip "$0 Need two or more remote clients" && exit 0; }
35 [ $CLIENTCOUNT -ge 3 ] || \
36 { skip "$0 Need two or more remote clients, have $CLIENTCOUNT" && exit 0; }
38 END_RUN_FILE=${END_RUN_FILE:-$SHARED_DIRECTORY/end_run_file}
39 LOAD_PID_FILE=${LOAD_PID_FILE:-$TMP/client-load.pid}
41 remote_mds_nodsh && skip "remote MDS with nodsh" && exit 0
42 remote_ost_nodsh && skip "remote OST with nodsh" && exit 0
44 check_timeout || exit 1
48 check_and_setup_lustre
49 rm -rf $DIR/[df][0-9]*
51 # the test node needs to be insulated from a lustre failure as much as possible,
52 # so not even loading the lustre modules is ideal.
54 # -- remove hostname from clients list
55 zconf_umount $(hostname) $MOUNT
56 NODES_TO_USE=${NODES_TO_USE:-$CLIENTS}
57 NODES_TO_USE=$(exclude_items_from_list $NODES_TO_USE $(hostname))
59 check_progs_installed $NODES_TO_USE ${CLIENT_LOADS[@]}
61 MDTS=$(get_facets MDS)
62 OSTS=$(get_facets OST)
66 reboot_recover_node () {
67 # item var contains a pair of clients if nodetype=clients
68 # I would prefer to have a list here
71 local timeout=$($LCTL get_param -n timeout)
73 # MDS, OST item contains the facet
75 MDS|OST ) facet_failover $item
76 [ "$SERIAL" ] && wait_recovery_complete $item $((timeout * 4)) || true
78 clients) for c in ${item//,/ }; do
81 echo "Reintegrating $c"
82 # one client fails; need dk logs from this client only
83 zconf_mount $c $MOUNT || NODES="$c $(facet_host mds) $(osts_nodes)" error_exit "zconf_mount failed"
85 start_client_loads $item
88 # don't use error (), the logs from all nodes not needed
89 * ) echo "reboot_recover_node: nodetype=$nodetype. Must be one of 'MDS', 'OST', or 'clients'."
96 local excluded=${2:-""}
102 clients) list=$NODES_TO_USE
105 # don't use error (), the logs from all nodes not needed
106 * ) echo "Invalid type=$type. Must be one of 'MDS', 'OST', or 'clients'."
110 [ "$excluded" ] && list=$(exclude_items_from_list $list $excluded)
112 if [ ! "$(echo $list)" ]; then
117 item=$(get_random_entry $list)
118 if [ "$type" = clients ] ; then
119 item="$item $(get_random_entry $(exclude_items_from_list $list $item))"
120 item=$(comma_list $item)
127 # for the two nodetypes specified, chooses a random node(s) from each
128 # class, reboots the nodes sequentially, and then restarts lustre on
135 local client_nodes=""
142 ==== START === $title "
144 item1=$(get_item_type $type1)
146 { echo "type1=$type1 item1 is empty" && return 0; }
147 item2=$(get_item_type $type2 $item1)
149 { echo "type1=$type1 item1=$item1 type2=$type2 item2=$item2 is empty" && return 0; }
151 # Check that our client loads are still running. If any have died,
152 # that means they have died outside of recovery, which is unacceptable.
153 log "==== Checking the clients loads BEFORE failover -- failure NOT OK"
155 # FIXME. need print summary on exit
156 if ! check_client_loads $NODES_TO_USE; then
160 log "Done checking client loads. Failing type1=$type1 item1=$item1 ... "
162 reboot_recover_node $item1 $type1
164 # Hendrix test17 description:
165 # Introduce a failure, wait at
166 # least 5 minutes (for recovery),
168 # failure, and wait another 5
171 # reboot_recover_node waits recovery in according to
173 # We have a "double failures" if SERIAL is not set,
174 # do not need a sleep between failures for "double failures"
176 log " Failing type2=$type2 item2=$item2 ... "
177 reboot_recover_node $item2 $type2
179 # Client loads are allowed to die while in recovery, so we just
181 log "==== Checking the clients loads AFTER failovers -- ERRORS_OK=$ERRORS_OK"
182 restart_client_loads $NODES_TO_USE $ERRORS_OK || return $?
183 log "Done checking / re-Starting client loads. PASS"
187 summary_and_cleanup () {
191 # Having not empty END_RUN_FILE means the failed loads only
192 if [ -s $END_RUN_FILE ]; then
193 echo "Found the END_RUN_FILE file: $END_RUN_FILE"
196 read END_RUN_NODE < $END_RUN_FILE
198 # a client load will end (i.e. fail) if it finds
199 # the end run file. that does not mean that that client load
200 # actually failed though. the first node in the END_RUN_NODE is
201 # the one we are really interested in.
202 if [ -n "$END_RUN_NODE" ]; then
203 var=$(client_var_name $END_RUN_NODE)_load
204 echo "Client load failed on node $END_RUN_NODE"
206 echo "client $END_RUN_NODE load debug output :"
207 local logfile=${TESTSUITELOG}_run_${!var}.sh-${END_RUN_NODE}.debug
208 do_node ${END_RUN_NODE} "set -x; [ -e $logfile ] && cat $logfile " || true
213 echo $(date +'%F %H:%M:%S') Terminating clients loads ...
214 echo "$0" >> $END_RUN_FILE
216 [ $rc -eq 0 ] || result=FAIL
219 Server failover period: $FAILOVER_PERIOD seconds
220 Exited after: $ELAPSED seconds
221 Status: $result: rc=$rc"
223 # make sure the client loads die
224 do_nodes $NODES_TO_USE "set -x; test -f $TMP/client-load.pid && \
225 { kill -s TERM \$(cat $TMP/client-load.pid) || true; }"
227 # and free up the pdshes that started them, if any are still around
228 if [ -n "$CLIENT_LOAD_PIDS" ]; then
229 kill $CLIENT_LOAD_PIDS || true
231 kill -9 $CLIENT_LOAD_PIDS || true
234 if [ $rc -ne 0 ]; then
235 # we are interested in only on failed clients and servers
236 local failedclients=$(cat $END_RUN_FILE | grep -v $0)
237 # FIXME: need ostfailover-s nodes also for FLAVOR=OST
238 local product=$(gather_logs $(comma_list $(osts_nodes) \
239 $mds_HOST $mdsfailover_HOST $failedclients))
240 echo logs files $product
243 [ $rc -eq 0 ] && zconf_mount $(hostname) $MOUNT
247 trap summary_and_cleanup EXIT TERM INT
252 log "-----============= $0 starting =============-----"
258 # Set SERIAL to serialize the failure through a recovery of the first failure.
262 [ "$SERIAL" ] && ERRORS_OK=""
264 FAILOVER_PERIOD=${FAILOVER_PERIOD:-$((60*5))} # 5 minutes
266 # Start client loads.
267 start_client_loads $NODES_TO_USE
268 echo clients load pids:
269 if ! do_nodesv $NODES_TO_USE "cat $TMP/client-load.pid"; then
273 # FIXME: Do we want to have an initial sleep period where the clients
274 # just run before introducing a failure?
275 sleep $FAILOVER_PERIOD
278 failover_pair MDS OST "test 1: failover MDS, then OST =========="
279 sleep $FAILOVER_PERIOD
282 failover_pair MDS clients "test 2: failover MDS, then 2 clients ===="
283 sleep $FAILOVER_PERIOD
286 # No test 3 for 1.8.x lustre version
289 if [ $OSTCOUNT -gt 1 ]; then
290 failover_pair OST OST "test 4: failover OST, then another OST =="
291 sleep $FAILOVER_PERIOD
293 skip "$0 : $OSTCOUNT < 2 OSTs, test 4 skipped"
297 failover_pair OST clients "test 5: failover OST, then 2 clients ===="
298 sleep $FAILOVER_PERIOD
301 failover_pair OST MDS "test 6: failover OST, then MDS =========="
302 sleep $FAILOVER_PERIOD
305 failover_pair clients MDS "test 7: failover 2 clients, then MDS ===="
306 sleep $FAILOVER_PERIOD
309 #failover_pair clients OST "test 8: failover 2 clients, then OST ===="
310 sleep $FAILOVER_PERIOD
313 if [ $CLIENTCOUNT -ge 5 ]; then
314 failover_pair clients clients "test 9: failover 2 clients, then 2 different clients =="
315 sleep $FAILOVER_PERIOD
317 log "==== Checking the clients loads AFTER all failovers -- failure NOT OK"
318 if ! check_client_loads $NODES_TO_USE; then
319 log "Client load failed after failover. Exiting"
323 CURRENT_TS=$(date +%s)
324 ELAPSED=$((CURRENT_TS - START_TS))
326 log "Completed successfully in $ELAPSED seconds"