Whamcloud - gitweb
805fddc98e69df9d6c38ee8cebaf53349309263f
[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 init_logging
21
22 DEBUGLOG=$TESTLOG_PREFIX.suite_debug_log.$(hostname -s).log
23
24 exec 2>$DEBUGLOG
25 echo "--- env ---" >&2
26 env >&2
27 echo "--- env ---" >&2
28 set -x
29
30 [ "$SHARED_DIRECTORY" ] || \
31     { FAIL_ON_ERROR=true skip_env "$0 Empty SHARED_DIRECTORY" && exit 0; }
32
33 check_shared_dir $SHARED_DIRECTORY ||
34     error "$SHARED_DIRECTORY isn't a shared directory"
35
36 [ -n "$CLIENTS" ] || \
37     { FAIL_ON_ERROR=true skip_env "$0 Need two or more remote clients" && exit 0; }
38
39 [ $CLIENTCOUNT -ge 3 ] || \
40     { FAIL_ON_ERROR=true skip_env "$0 Need two or more remote clients, have $((CLIENTCOUNT - 1))" && exit 0; }
41
42 END_RUN_FILE=${END_RUN_FILE:-$SHARED_DIRECTORY/end_run_file}
43 LOAD_PID_FILE=${LOAD_PID_FILE:-$TMP/client-load.pid}
44
45 remote_mds_nodsh && skip "remote MDS with nodsh" && exit 0
46 remote_ost_nodsh && skip "remote OST with nodsh" && exit 0
47
48 check_timeout || exit 1
49
50 [[ $FAILURE_MODE = SOFT ]] && \
51     log "WARNING: $0 is not functional with FAILURE_MODE = SOFT, bz22797"
52
53 build_test_filter
54
55 check_and_setup_lustre
56 rm -rf $DIR/[df][0-9]*
57
58 # the test node needs to be insulated from a lustre failure as much as possible,
59 # so not even loading the lustre modules is ideal.
60 # -- umount lustre
61 # -- remove hostname from clients list
62 zconf_umount $(hostname) $MOUNT
63 NODES_TO_USE=${NODES_TO_USE:-$CLIENTS}
64 NODES_TO_USE=$(exclude_items_from_list $NODES_TO_USE $(hostname))
65
66 check_progs_installed $NODES_TO_USE ${CLIENT_LOADS[@]}
67
68 MDTS=$(get_facets MDS)
69 OSTS=$(get_facets OST)
70
71 rm -f $END_RUN_FILE
72
73 reboot_recover_node () {
74     # item var contains a pair of clients if nodetype=clients
75     # I would prefer to have a list here
76     local item=$1
77     local nodetype=$2   
78     local timeout=$($LCTL get_param  -n timeout)
79
80     # MDS, OST item contains the facet
81     case $nodetype in
82        MDS|OST )    facet_failover $item
83                 [ "$SERIAL" ] && wait_recovery_complete $item || true
84                 ;;
85        clients) for c in ${item//,/ }; do
86                       # make sure the client loads die
87                       do_nodes $c "set -x; test -f $LOAD_PID_FILE &&
88                           { kill -s TERM \\\$(cat $LOAD_PID_FILE);
89                           rm -f $LOAD_PID_FILE || true; }"
90                       shutdown_client $c
91                       boot_node $c
92                       echo "Reintegrating $c"
93                       # one client fails; need dk logs from this client only 
94                       zconf_mount $c $MOUNT || NODES="$c $(mdts_nodes) $(osts_nodes)" error_exit "zconf_mount failed"
95                  done
96                  start_client_loads $item
97                  ;;
98                 # script failure:
99                 # don't use error (), the logs from all nodes not needed
100        * )      echo "reboot_recover_node: nodetype=$nodetype. Must be one of 'MDS', 'OST', or 'clients'."
101                 exit 1;;
102     esac
103 }
104
105 get_item_type () {
106     local type=$1
107     local excluded=${2:-""}
108
109     local list
110     case $type in
111        MDS )    list=$MDTS;;
112        OST )    list=$OSTS;;
113        clients) list=$NODES_TO_USE
114                 ;;
115                 # script failure:
116                 # don't use error (), the logs from all nodes not needed
117        * )      echo "Invalid type=$type. Must be one of 'MDS', 'OST', or 'clients'."
118                 exit 1;;
119     esac
120
121     [ "$excluded" ] && list=$(exclude_items_from_list $list $excluded)
122     # empty list
123     if [ ! "$(echo $list)" ]; then
124         echo
125         return
126     fi
127
128     item=$(get_random_entry $list)
129     if [ "$type" = clients ] ; then
130         item="$item $(get_random_entry $(exclude_items_from_list $list $item))"
131         item=$(comma_list $item)
132     fi
133     echo $item
134 }
135
136 # failover_pair
137 #
138 # for the two nodetypes specified, chooses a random node(s) from each
139 # class, reboots the nodes sequentially, and then restarts lustre on
140 # the nodes.
141 failover_pair() {
142     local type1=$1
143     local type2=$2
144     local title=$3
145
146     local client_nodes=""
147     local item1=
148     local item2=
149     local client1=
150     local client2=
151
152     log "
153 ==== START === $title "
154
155     item1=$(get_item_type $type1)
156     [ "$item1" ] || \
157         { echo "type1=$type1 item1 is empty" && return 0; }
158     item2=$(get_item_type $type2 $item1)
159     [ "$item2" ] || \
160         { echo "type1=$type1 item1=$item1 type2=$type2 item2=$item2 is empty" && return 0; }
161
162     # Check that our client loads are still running. If any have died,
163     # that means they have died outside of recovery, which is unacceptable.
164     log "==== Checking the clients loads BEFORE failover -- failure NOT OK"
165
166     # FIXME. need print summary on exit
167     if ! check_client_loads $NODES_TO_USE; then
168         exit 4
169     fi
170
171     log "Done checking client loads. Failing type1=$type1 item1=$item1 ... "
172
173     reboot_recover_node $item1 $type1
174
175     # Hendrix test17 description: 
176     # Introduce a failure, wait at
177     # least 5 minutes (for recovery),
178     # introduce a 2nd
179     # failure, and wait another 5
180     # minutes
181
182     # reboot_recover_node waits recovery in according to
183     # SERIAL value.
184     # We have a "double failures" if SERIAL is not set,
185     # do not need a sleep between failures for "double failures"
186
187     log "                            Failing type2=$type2 item2=$item2 ... "    
188     reboot_recover_node $item2 $type2
189
190     # Client loads are allowed to die while in recovery, so we just
191     # restart them.
192     log "==== Checking the clients loads AFTER  failovers -- ERRORS_OK=$ERRORS_OK"
193     restart_client_loads $NODES_TO_USE $ERRORS_OK || return $? 
194     log "Done checking / re-Starting client loads. PASS"
195     return 0
196 }
197
198 summary_and_cleanup () {
199     local rc=$?
200     local var
201     trap 0
202
203     # Having not empty END_RUN_FILE means the failed loads only
204     if [ -s $END_RUN_FILE ]; then
205         echo "Found the END_RUN_FILE file: $END_RUN_FILE"
206         cat $END_RUN_FILE
207         local END_RUN_NODE=
208         read END_RUN_NODE < $END_RUN_FILE
209
210         # A client load will stop if it found the END_RUN_FILE file.
211         # That does not mean the client load actually failed though.
212         # The first node in END_RUN_FILE is the one we are interested in.
213         if [ -n "$END_RUN_NODE" ]; then
214             var=$(node_var_name $END_RUN_NODE)_load
215             echo "Client load failed on node $END_RUN_NODE"
216             echo
217             echo "Client $END_RUN_NODE load stdout and debug files:
218                 $TESTLOG_PREFIX.run_${!var}_stdout.$END_RUN_NODE.log
219                 $TESTLOG_PREFIX.run_${!var}_debug.$END_RUN_NODE.log"
220         fi
221         rc=1
222     fi
223
224     echo $(date +'%F %H:%M:%S') Terminating clients loads ...
225     echo "$0" >> $END_RUN_FILE
226     local result=PASS
227     [ $rc -eq 0 ] || result=FAIL
228
229     log "
230 Server failover period: $FAILOVER_PERIOD seconds
231 Exited after:           $ELAPSED seconds
232 Status: $result: rc=$rc"
233
234     # make sure the client loads die
235     do_nodes $NODES_TO_USE "set -x; test -f $LOAD_PID_FILE &&
236         { kill -s TERM \\\$(cat $LOAD_PID_FILE);
237         rm -f $LOAD_PID_FILE || true; }"
238
239     # and free up the pdshes that started them, if any are still around
240     if [ -n "$CLIENT_LOAD_PIDS" ]; then
241         kill $CLIENT_LOAD_PIDS || true
242         sleep 5
243         kill -9 $CLIENT_LOAD_PIDS || true
244     fi
245
246     if [ $rc -ne 0 ]; then
247         # we are interested in only on failed clients and servers
248         local failedclients=$(cat $END_RUN_FILE | grep -v $0)
249         # FIXME: need ostfailover-s nodes also for FLAVOR=OST
250         local product=$(gather_logs $(comma_list $(osts_nodes) \
251                         $(mdts_nodes) $mdsfailover_HOST $failedclients) 1)
252         echo $product
253     fi
254
255     [ $rc -eq 0 ] && zconf_mount $(hostname) $MOUNT
256     exit $rc
257 }
258
259 trap summary_and_cleanup EXIT TERM INT
260
261 #
262 # MAIN
263 #
264 log "-----============= $0 starting =============-----"
265
266 START_TS=$(date +%s)
267 CURRENT_TS=$START_TS
268 ELAPSED=0
269
270 # Set SERIAL to serialize the failure through a recovery of the first failure. 
271 SERIAL=${SERIAL:-""}
272 ERRORS_OK="yes"
273
274 [ "$SERIAL" ] && ERRORS_OK="" 
275
276 FAILOVER_PERIOD=${FAILOVER_PERIOD:-$((60*5))} # 5 minutes
277
278 # Start client loads.
279 start_client_loads $NODES_TO_USE
280
281 echo clients load pids:
282 if ! do_nodesv $NODES_TO_USE "cat $LOAD_PID_FILE"; then
283     exit 3
284 fi
285
286 # FIXME: Do we want to have an initial sleep period where the clients 
287 # just run before introducing a failure?
288 sleep $FAILOVER_PERIOD
289
290 #CMD_TEST_NUM=17.1
291 failover_pair MDS OST     "test 1: failover MDS, then OST =========="
292 sleep $FAILOVER_PERIOD
293
294 #CMD_TEST_NUM=17.2
295 failover_pair MDS clients "test 2: failover MDS, then 2 clients ===="
296 sleep $FAILOVER_PERIOD
297
298 #CMD_TEST_NUM=17.3
299 if [ $MDSCOUNT -gt 1 ]; then
300     failover_pair MDS MDS     "test 3: failover MDS, then another MDS =="
301     sleep $FAILOVER_PERIOD
302 else
303     skip "$0 : $MDSCOUNT < 2 MDTs, test 3 skipped"
304 fi 
305
306 #CMD_TEST_NUM=17.4
307 if [ $OSTCOUNT -gt 1 ]; then
308     failover_pair OST OST     "test 4: failover OST, then another OST =="
309     sleep $FAILOVER_PERIOD
310 else
311     skip "$0 : $OSTCOUNT < 2 OSTs, test 4 skipped"
312 fi 
313
314 #CMD_TEST_NUM=17.5
315 failover_pair OST clients "test 5: failover OST, then 2 clients ===="
316 sleep $FAILOVER_PERIOD
317
318 #CMD_TEST_NUM=17.6
319 failover_pair OST MDS     "test 6: failover OST, then MDS =========="
320 sleep $FAILOVER_PERIOD
321
322 #CMD_TEST_NUM=17.7
323 failover_pair clients MDS "test 7: failover 2 clients, then MDS ===="
324 sleep $FAILOVER_PERIOD
325
326 #CMD_TEST_NUM=17.8
327 #failover_pair clients OST "test 8: failover 2 clients, then OST ===="
328 sleep $FAILOVER_PERIOD
329
330 #CMD_TEST_NUM=17.9
331 if [ $CLIENTCOUNT -ge 5 ]; then
332     failover_pair clients clients "test 9: failover 2 clients, then 2 different clients =="
333     sleep $FAILOVER_PERIOD
334 fi
335 log "==== Checking the clients loads AFTER  all failovers -- failure NOT OK"
336 if ! check_client_loads $NODES_TO_USE; then
337     log "Client load failed after failover. Exiting"
338     exit 5
339 fi
340
341 CURRENT_TS=$(date +%s)
342 ELAPSED=$((CURRENT_TS - START_TS))
343
344 log "Completed successfully in $ELAPSED seconds"
345
346 exit 0