Whamcloud - gitweb
1f84f925d4cf8c49ed0f1b8ee9853ea1d8c49892
[fs/lustre-release.git] / lustre / tests / recovery-double-scale.sh
1 #!/bin/bash
2
3 # All pairwise combinations of node failures.
4 # Was cmd3-17
5 #
6 # Author: Chris Cooper <ccooper@clusterfs.com>
7 #
8 # Script fails pair of nodes:
9 # --  in parallel by default
10 # --  in series if SERIAL is set
11
12 LUSTRE=${LUSTRE:-`dirname $0`/..}
13 SETUP=${SETUP:-""}
14 CLEANUP=${CLEANUP:-""}
15 . $LUSTRE/tests/test-framework.sh
16
17 init_test_env $@
18
19 . ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
20 TESTSUITELOG=${TESTSUITELOG:-$TMP/$(basename $0 .sh)}
21 DEBUGLOG=$TESTSUITELOG.debug
22
23 cleanup_logs
24
25 exec 2>$DEBUGLOG
26 echo "--- env ---" >&2
27 env >&2
28 echo "--- env ---" >&2
29 set -x
30
31 [ "$SHARED_DIRECTORY" ] || \
32     { skip "$0: Empty SHARED_DIRECTORY" && exit 0; }
33
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; }
37
38 END_RUN_FILE=${END_RUN_FILE:-$SHARED_DIRECTORY/end_run_file}
39 LOAD_PID_FILE=${LOAD_PID_FILE:-$TMP/client-load.pid}
40
41 remote_mds_nodsh && skip "remote MDS with nodsh" && exit 0
42 remote_ost_nodsh && skip "remote OST with nodsh" && exit 0
43
44 check_timeout || exit 1
45
46 build_test_filter
47
48 check_and_setup_lustre
49 rm -rf $DIR/[df][0-9]*
50
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.
53 # -- umount lustre
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))
58
59 check_progs_installed $NODES_TO_USE ${CLIENT_LOADS[@]}
60
61 MDTS=$(get_facets MDS)
62 OSTS=$(get_facets OST)
63
64 rm -f $END_RUN_FILE
65
66 reboot_recover_node () {
67     # item var contains a pair of clients if nodetype=clients
68     # I would prefer to have a list here
69     local item=$1
70     local nodetype=$2   
71     local timeout=$($LCTL get_param  -n timeout)
72
73     # MDS, OST item contains the facet
74     case $nodetype in
75        MDS|OST )    facet_failover $item
76                 [ "$SERIAL" ] && wait_recovery_complete $item $((timeout * 4)) || true
77                 ;;
78        clients) for c in ${item//,/ }; do
79                       shutdown_client $c
80                       boot_node $c
81                       echo "Reintegrating $c"
82                       # one client fails; need dk logs from this client only 
83                       zconf_mount $c $MOUNT || NODES="$c $(mdts_nodes) $(osts_nodes)" error_exit "zconf_mount failed"
84                  done
85                  start_client_loads $item
86                  ;;
87                 # script failure:
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'."
90                 exit 1;;
91     esac
92 }
93
94 get_item_type () {
95     local type=$1
96     local excluded=${2:-""}
97
98     local list
99     case $type in
100        MDS )    list=$MDTS;;
101        OST )    list=$OSTS;;
102        clients) list=$NODES_TO_USE
103                 ;;
104                 # script failure:
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'."
107                 exit 1;;
108     esac
109
110     [ "$excluded" ] && list=$(exclude_items_from_list $list $excluded)
111     # empty list
112     if [ ! "$(echo $list)" ]; then
113         echo
114         return
115     fi
116
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)
121     fi
122     echo $item
123 }
124
125 # failover_pair
126 #
127 # for the two nodetypes specified, chooses a random node(s) from each
128 # class, reboots the nodes sequentially, and then restarts lustre on
129 # the nodes.
130 failover_pair() {
131     local type1=$1
132     local type2=$2
133     local title=$3
134
135     local client_nodes=""
136     local item1=
137     local item2=
138     local client1=
139     local client2=
140
141     log "
142 ==== START === $title "
143
144     item1=$(get_item_type $type1)
145     [ "$item1" ] || \
146         { echo "type1=$type1 item1 is empty" && return 0; }
147     item2=$(get_item_type $type2 $item1)
148     [ "$item2" ] || \
149         { echo "type1=$type1 item1=$item1 type2=$type2 item2=$item2 is empty" && return 0; }
150
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"
154
155     # FIXME. need print summary on exit
156     if ! check_client_loads $NODES_TO_USE; then
157         exit 4
158     fi
159
160     log "Done checking client loads. Failing type1=$type1 item1=$item1 ... "
161
162     reboot_recover_node $item1 $type1
163
164     # Hendrix test17 description: 
165     # Introduce a failure, wait at
166     # least 5 minutes (for recovery),
167     # introduce a 2nd
168     # failure, and wait another 5
169     # minutes
170
171     # reboot_recover_node waits recovery in according to
172     # SERIAL value.
173     # We have a "double failures" if SERIAL is not set,
174     # do not need a sleep between failures for "double failures"
175
176     log "                            Failing type2=$type2 item2=$item2 ... "    
177     reboot_recover_node $item2 $type2
178
179     # Client loads are allowed to die while in recovery, so we just
180     # restart them.
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"
184     return 0
185 }
186
187 summary_and_cleanup () {
188     local rc=$?
189     trap 0
190
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"
194         cat $END_RUN_FILE
195         local END_RUN_NODE=
196         read END_RUN_NODE < $END_RUN_FILE
197
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"
205             echo
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
209         fi
210         rc=1
211     fi
212
213     echo $(date +'%F %H:%M:%S') Terminating clients loads ...
214     echo "$0" >> $END_RUN_FILE
215     local result=PASS
216     [ $rc -eq 0 ] || result=FAIL
217
218     log "
219 Server failover period: $FAILOVER_PERIOD seconds
220 Exited after:           $ELAPSED seconds
221 Status: $result: rc=$rc"
222
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; }"
226
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
230         sleep 5
231         kill -9 $CLIENT_LOAD_PIDS || true
232     fi
233
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                                  $(mdts_nodes) $mdsfailover_HOST $failedclients))
240         echo logs files $product
241     fi
242
243     [ $rc -eq 0 ] && zconf_mount $(hostname) $MOUNT
244     exit $rc
245 }
246
247 trap summary_and_cleanup EXIT TERM INT
248
249 #
250 # MAIN
251 #
252 log "-----============= $0 starting =============-----"
253
254 START_TS=$(date +%s)
255 CURRENT_TS=$START_TS
256 ELAPSED=0
257
258 # Set SERIAL to serialize the failure through a recovery of the first failure. 
259 SERIAL=${SERIAL:-""}
260 ERRORS_OK="yes"
261
262 [ "$SERIAL" ] && ERRORS_OK="" 
263
264 FAILOVER_PERIOD=${FAILOVER_PERIOD:-$((60*5))} # 5 minutes
265
266 # Start client loads.
267 start_client_loads $NODES_TO_USE
268 echo clients load pids:
269 if ! do_nodes $NODES_TO_USE "set -x; echo \$(hostname): && cat $TMP/client-load.pid"; then
270     if [ -e $DEBUGLOG ]; then
271         exec 2<&-
272         cat $DEBUGLOG
273         exit 3
274     fi
275 fi
276
277 # FIXME: Do we want to have an initial sleep period where the clients 
278 # just run before introducing a failure?
279 sleep $FAILOVER_PERIOD
280
281 #CMD_TEST_NUM=17.1
282 failover_pair MDS OST     "test 1: failover MDS, then OST =========="
283 sleep $FAILOVER_PERIOD
284
285 #CMD_TEST_NUM=17.2
286 failover_pair MDS clients "test 2: failover MDS, then 2 clients ===="
287 sleep $FAILOVER_PERIOD
288
289 #CMD_TEST_NUM=17.3
290 if [ $MDSCOUNT -gt 1 ]; then
291     failover_pair MDS MDS     "test 3: failover MDS, then another MDS =="
292     sleep $FAILOVER_PERIOD
293 else
294     skip "$0 : $MDSCOUNT < 2 MDTs, test 3 skipped"
295 fi 
296
297 #CMD_TEST_NUM=17.4
298 if [ $OSTCOUNT -gt 1 ]; then
299     failover_pair OST OST     "test 4: failover OST, then another OST =="
300     sleep $FAILOVER_PERIOD
301 else
302     skip "$0 : $OSTCOUNT < 2 OSTs, test 4 skipped"
303 fi 
304
305 #CMD_TEST_NUM=17.5
306 failover_pair OST clients "test 5: failover OST, then 2 clients ===="
307 sleep $FAILOVER_PERIOD
308
309 #CMD_TEST_NUM=17.6
310 failover_pair OST MDS     "test 6: failover OST, then MDS =========="
311 sleep $FAILOVER_PERIOD
312
313 #CMD_TEST_NUM=17.7
314 failover_pair clients MDS "test 7: failover 2 clients, then MDS ===="
315 sleep $FAILOVER_PERIOD
316
317 #CMD_TEST_NUM=17.8
318 #failover_pair clients OST "test 8: failover 2 clients, then OST ===="
319 sleep $FAILOVER_PERIOD
320
321 #CMD_TEST_NUM=17.9
322 if [ $CLIENTCOUNT -ge 5 ]; then
323     failover_pair clients clients "test 9: failover 2 clients, then 2 different clients =="
324     sleep $FAILOVER_PERIOD
325 fi
326 log "==== Checking the clients loads AFTER  all failovers -- failure NOT OK"
327 if ! check_client_loads $NODES_TO_USE; then
328     log "Client load failed after failover. Exiting"
329     exit 5
330 fi
331
332 CURRENT_TS=$(date +%s)
333 ELAPSED=$((CURRENT_TS - START_TS))
334
335 log "Completed successfully in $ELAPSED seconds"
336
337 exit 0