Whamcloud - gitweb
b=2973
[fs/lustre-release.git] / lustre / tests / test-framework.sh
1 #!/bin/sh
2
3 set -e
4
5 export REFORMAT=""
6 export VERBOSE=false
7
8 # eg, assert_env LUSTRE MDSNODES OSTNODES CLIENTS
9 assert_env() {
10     local failed=""
11     for name in $@; do
12       if [ -z "${!name}" ]; then
13           echo "$0: $name must be set"
14           failed=1
15       fi
16     done
17     [ $failed ] && exit 1 || true
18 }
19
20 usage() {
21     echo "usage: $0 [-r] [-f cfgfile]"
22     echo "       -r: reformat"
23
24     exit
25 }
26
27 init_test_env() {
28     export LUSTRE=`absolute_path $LUSTRE`
29     export TESTSUITE=`basename $0 .sh`
30     export XMLCONFIG="${TESTSUITE}.xml"
31     export LTESTDIR=${LTESTDIR:-$LUSTRE/../ltest}
32
33     [ -d /r ] && export ROOT=/r
34
35     export PATH=:$PATH:$LUSTRE/utils:$LUSTRE/tests
36     export LLMOUNT=${LLMOUNT:-"llmount"}
37     export LCONF=${LCONF:-"lconf"}
38     export LMC=${LMC:-"lmc"}
39     export LCTL=${LCTL:-"$LUSTRE/utils/lctl"}
40     export CHECKSTAT="${CHECKSTAT:-checkstat} "
41
42     # Paths on remote nodes, if different 
43     export RLUSTRE=${RLUSTRE:-$LUSTRE}
44     export RPWD=${RPWD:-$PWD}
45
46     # command line
47     
48     while getopts "rvf:" opt $*; do 
49         case $opt in
50             f) CONFIG=$OPTARG;;
51             r) REFORMAT=--reformat;;
52             v) VERBOSE=true;;
53             \?) usage;;
54         esac
55     done
56     
57     # save the name of the config file for the upcall
58     echo "XMLCONFIG=$LUSTRE/tests/$XMLCONFIG"  > $LUSTRE/tests/XMLCONFIG
59 #    echo "CONFIG=`canonical_path $CONFIG`"  > $LUSTRE/tests/CONFIG
60 }
61
62 # Facet functions
63 start() {
64     facet=$1
65     shift
66     active=`facet_active $facet`
67     do_facet $facet $LCONF --select ${facet}_svc=${active}_facet \
68         --node ${active}_facet  --ptldebug $PTLDEBUG --subsystem $SUBSYSTEM \
69         $@ $XMLCONFIG
70 }
71
72 stop() {
73     facet=$1
74     active=`facet_active $facet`
75     shift
76     do_facet $facet $LCONF --select ${facet}_svc=${active}_facet \
77         --node ${active}_facet  --ptldebug $PTLDEBUG --subsystem $SUBSYSTEM \
78         $@ --cleanup $XMLCONFIG
79 }
80
81 zconf_mount() {
82     client=$1
83     mnt=$2
84
85     do_node $client mkdir $mnt 2> /dev/null || :
86
87     if [ -x /sbin/mount.lustre ] ; then
88         do_node $client mount -t lustre -o nettype=$NETTYPE `facet_active_host mds`:/mds_svc/client_facet $mnt || return 1
89     else
90        # this is so cheating
91        do_node $client $LCONF --nosetup --node client_facet $XMLCONFIG  > /dev/null || return 2
92        $LCONF --nosetup --node client_facet $XMLCONFIG
93        do_node $client $LLMOUNT `facet_active_host mds`:/mds_svc/client_facet $mnt -o nettype=$NETTYPE|| return 4
94     fi
95
96     [ -d /r ] && $LCTL modules > /r/tmp/ogdb-`hostname`
97     return 0
98 }
99
100 zconf_umount() {
101     client=$1
102     mnt=$2
103     [ "$3" ] && force=-f
104     do_node $client umount $force  $mnt || :
105     do_node $client $LCONF --cleanup --nosetup --node client_facet $XMLCONFIG > /dev/null || :
106 }
107
108 shutdown_facet() {
109     facet=$1
110     if [ "$FAILURE_MODE" = HARD ]; then
111        $POWER_DOWN `facet_active_host $facet`
112        sleep 2 
113     elif [ "$FAILURE_MODE" = SOFT ]; then
114        stop $facet --force --failover --nomod
115     fi
116 }
117
118 reboot_facet() {
119     facet=$1
120     if [ "$FAILURE_MODE" = HARD ]; then
121        $POWER_UP `facet_active_host $facet`
122     fi
123 }
124
125 wait_for_host() {
126    HOST=$1
127    check_network  $HOST 900
128    while ! do_node $HOST "ls -d $LUSTRE " > /dev/null; do sleep 5; done
129 }
130
131 wait_for() {
132    facet=$1
133    HOST=`facet_active_host $facet`
134    wait_for_host $HOST
135 }
136
137 client_df() {
138     # not every config has many clients
139     if [ ! -z "$CLIENTS" ]; then
140         $PDSH $CLIENTS "df $MOUNT" > /dev/null
141     fi
142 }
143
144 facet_failover() {
145     facet=$1
146     echo "Failing $facet node `facet_active_host $facet`"
147     shutdown_facet $facet
148     reboot_facet $facet
149     client_df &
150     DFPID=$!
151     echo "df pid is $DFPID"
152     change_active $facet
153     TO=`facet_active_host $facet`
154     echo "Failover $facet to $TO"
155     wait_for $facet
156     start $facet
157 }
158
159 replay_barrier() {
160     local facet=$1
161     do_facet $facet sync
162     df $MOUNT
163     do_facet $facet $LCTL --device %${facet}_svc readonly
164     do_facet $facet $LCTL --device %${facet}_svc notransno
165     do_facet $facet $LCTL mark "REPLAY BARRIER"
166     $LCTL mark "REPLAY BARRIER"
167 }
168
169 mds_evict_client() {
170     UUID=`cat /proc/fs/lustre/mdc/*_MNT_*/uuid`
171     do_facet mds "echo $UUID > /proc/fs/lustre/mds/mds_svc/evict_client"
172 }
173
174 fail() {
175     local facet=$1
176     facet_failover $facet
177     df $MOUNT || error "post-failover df: $?"
178 }
179
180 fail_abort() {
181     local facet=$1
182     stop $facet --force --failover --nomod
183     change_active $facet
184     start $facet
185     do_facet $facet lctl --device %${facet}_svc abort_recovery
186     df $MOUNT || echo "first df failed: $?"
187     df $MOUNT || error "post-failover df: $?"
188 }
189
190 do_lmc() {
191     $LMC -m ${XMLCONFIG} $@
192 }
193
194 h2gm () {
195    if [ "$1" = "client" ]; then echo \'*\'; else
196        $PDSH $1 $GMNALNID -l | cut -d\  -f2
197    fi
198 }
199
200 h2tcp() {
201    if [ "$1" = "client" ]; then echo \'*\'; else
202    echo $1 
203    fi
204 }
205 declare -fx h2tcp
206
207 h2elan() {
208    if [ "$1" = "client" ]; then echo \'*\'; else
209    echo $1 | sed 's/[^0-9]*//g'
210    fi
211 }
212 declare -fx h2elan
213
214 facet_host() {
215    local facet=$1
216    varname=${facet}_HOST
217    echo -n ${!varname}
218 }
219
220 facet_nid() {
221    facet=$1
222    HOST=`facet_host $facet`
223    if [ -z "$HOST" ]; then
224         echo "The env variable ${facet}_HOST must be set."
225         exit 1
226    fi
227    echo `h2$NETTYPE $HOST`
228 }
229
230 facet_active() {
231     local facet=$1
232     local activevar=${facet}active
233     active=${!activevar}
234     if [ -z "$active" ] ; then 
235         echo -n ${facet}
236     else
237         echo -n ${active}
238     fi
239 }
240
241 facet_active_host() {
242     local facet=$1
243     local active=`facet_active $facet`
244     if [ "$facet" == client ]; then
245         hostname
246     else
247         echo `facet_host $active`
248     fi
249 }
250
251 change_active() {
252     local facet=$1
253     failover=${facet}failover 
254     host=`facet_host $failover`
255     [ -z "$host" ] && return
256     curactive=`facet_active $facet`
257     if [ -z "${curactive}" -o "$curactive" == "$failover" ] ; then
258         eval export ${facet}active=$facet
259     else
260         eval export ${facet}active=$failover
261     fi
262     # save the active host for this facet
263     activevar=${facet}active
264     echo "$activevar=${!activevar}" > ./$activevar
265 }
266
267 do_node() {
268     HOST=$1
269     shift
270
271     if $VERBOSE; then
272         echo "CMD: $HOST $@"
273         $PDSH $HOST $LCTL mark "$@" > /dev/null 2>&1 || :
274     fi
275     $PDSH $HOST "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests; cd $RPWD; sh -c \"$@\")"
276 }
277 do_facet() {
278     facet=$1
279     shift
280     HOST=`facet_active_host $facet`
281     do_node $HOST $@
282 }
283
284 add_facet() {
285     local facet=$1
286     shift
287     echo "add facet $facet: `facet_host $facet`"
288     do_lmc --add node --node ${facet}_facet $@ --timeout $TIMEOUT \
289         --lustre_upcall $UPCALL --ptldebug $PTLDEBUG --subsystem $SUBSYSTEM
290     do_lmc --add net --node ${facet}_facet --nid `facet_nid $facet` \
291         --nettype $NETTYPE
292 }
293
294 add_mds() {
295     facet=$1
296     shift
297     rm -f ${facet}active
298     add_facet $facet
299     do_lmc --add mds --node ${facet}_facet --mds ${facet}_svc $*
300 }
301
302 add_mdsfailover() {
303     facet=$1
304     shift
305     add_facet ${facet}failover  --lustre_upcall $UPCALL
306     do_lmc --add mds  --node ${facet}failover_facet --mds ${facet}_svc $*
307 }
308
309 add_ost() {
310     facet=$1
311     shift
312     rm -f ${facet}active
313     add_facet $facet
314     do_lmc --add ost --node ${facet}_facet --ost ${facet}_svc $*
315 }
316
317 add_ostfailover() {
318     facet=$1
319     shift
320     add_facet ${facet}failover
321     do_lmc --add ost --failover --node ${facet}failover_facet --ost ${facet}_svc $*
322 }
323
324 add_lov() {
325     lov=$1
326     mds_facet=$2
327     shift; shift
328     do_lmc --add lov --mds ${mds_facet}_svc --lov $lov $*
329     
330 }
331
332 add_client() {
333     facet=$1
334     mds=$2
335     shift; shift
336     add_facet $facet --lustre_upcall $UPCALL
337     do_lmc --add mtpt --node ${facet}_facet --mds ${mds}_svc $*
338
339 }
340
341
342 ####### 
343 # General functions
344
345 check_network() {
346    local NETWORK=0
347    local WAIT=0
348    local MAX=$2
349    while [ $NETWORK -eq 0 ]; do
350       ping -c 1 -w 3 $1 > /dev/null
351       if [ $? -eq 0 ]; then
352          NETWORK=1
353       else
354          WAIT=$((WAIT + 5))
355          echo "waiting for $1, $((MAX - WAIT)) secs left"
356          sleep 5
357       fi
358       if [ $WAIT -gt $MAX ]; then
359          echo "Network not available"
360          exit 1
361       fi
362    done
363 }
364 check_port() {
365    while( !($DSH2 $1 "netstat -tna | grep -q $2") ) ; do
366       sleep 9
367    done
368 }
369
370 no_dsh() {
371    shift
372    eval $@
373 }
374
375 comma_list() {
376     # the sed converts spaces to commas, but leaves the last space
377     # alone, so the line doesn't end with a comma.
378     echo "$*" | tr -s " " "\n" | sort -b -u | tr "\n" " " | sed 's/ \([^$]\)/,\1/g'
379 }
380
381 absolute_path() {
382    (cd `dirname $1`; echo $PWD/`basename $1`)
383 }
384
385 ##################################
386 # OBD_FAIL funcs
387
388 drop_request() {
389 # OBD_FAIL_MDS_ALL_REQUEST_NET
390     RC=0
391     do_facet mds "echo 0x123 > /proc/sys/lustre/fail_loc"
392     do_facet client "$1" || RC=$?
393     do_facet mds "echo 0 > /proc/sys/lustre/fail_loc"
394     return $RC
395 }
396
397 drop_reply() {
398 # OBD_FAIL_MDS_ALL_REPLY_NET
399     RC=0
400     do_facet mds "echo 0x122 > /proc/sys/lustre/fail_loc"
401     do_facet client "$@" || RC=$?
402     do_facet mds "echo 0 > /proc/sys/lustre/fail_loc"
403     return $RC
404 }
405
406 pause_bulk() {
407 #define OBD_FAIL_OST_BRW_PAUSE_BULK      0x214
408     RC=0
409     do_facet ost "echo 0x214 > /proc/sys/lustre/fail_loc"
410     do_facet client "$1" || RC=$?
411     do_facet client "sync"
412     do_facet ost "echo 0 > /proc/sys/lustre/fail_loc"
413     return $RC
414 }
415
416 drop_ldlm_cancel() {
417 #define OBD_FAIL_LDLM_CANCEL             0x304
418     RC=0
419     do_facet client "echo 0x304 > /proc/sys/lustre/fail_loc"
420     do_facet client "$@" || RC=$?
421     do_facet client "echo 0 > /proc/sys/lustre/fail_loc"
422     return $RC
423 }
424
425 drop_bl_callback() {
426 #define OBD_FAIL_LDLM_BL_CALLBACK        0x305
427     RC=0
428     do_facet client "echo 0x305 > /proc/sys/lustre/fail_loc"
429     do_facet client "$@" || RC=$?
430     do_facet client "echo 0 > /proc/sys/lustre/fail_loc"
431     return $RC
432 }
433
434 clear_failloc() {
435     facet=$1
436     pause=$2
437     sleep $pause
438     echo "clearing fail_loc on $facet"
439     do_facet $facet "sysctl -w lustre.fail_loc=0"
440 }
441
442 cancel_lru_locks() {
443     $LCTL mark cancel_lru_locks
444     for d in /proc/fs/lustre/ldlm/namespaces/$1*; do
445         if [ -f $d/lru_size ]; then
446             echo clear > $d/lru_size
447             grep [0-9] $d/lock_unused_count
448         fi
449     done
450 }
451
452
453 pgcache_empty() {
454     for a in /proc/fs/lustre/llite/*/dump_page_cache; do
455         if [ `wc -l $a | awk '{print $1}'` -gt 1 ]; then
456                 echo there is still data in page cache $a ?
457                 cat $a;
458                 return 1;
459         fi
460     done
461     return 0
462 }
463
464 ##################################
465 # Test interface 
466 error() {
467     echo "${TESTSUITE}: **** FAIL:" $@
468     log "FAIL: $@"
469     exit 1
470 }
471
472 build_test_filter() {
473         for O in $ONLY; do
474             eval ONLY_${O}=true
475         done
476         for E in $EXCEPT $ALWAYS_EXCEPT; do
477             eval EXCEPT_${E}=true
478         done
479 }
480
481 _basetest() {
482     echo $*
483 }
484
485 basetest() {
486     IFS=abcdefghijklmnopqrstuvwxyz _basetest $1
487 }
488
489 run_test() {
490         export base=`basetest $1`
491         if [ ! -z "$ONLY" ]; then
492                  testname=ONLY_$1
493                  if [ ${!testname}x != x ]; then
494                      run_one $1 "$2"
495                      return $?
496                  fi
497                  testname=ONLY_$base
498                  if [ ${!testname}x != x ]; then
499                      run_one $1 "$2"
500                      return $?
501                  fi
502                  echo -n "."
503                  return 0
504         fi
505         testname=EXCEPT_$1
506         if [ ${!testname}x != x ]; then
507                  echo "skipping excluded test $1"
508                  return 0
509         fi
510         testname=EXCEPT_$base
511         if [ ${!testname}x != x ]; then
512                  echo "skipping excluded test $1 (base $base)"
513                  return 0
514         fi
515         run_one $1 "$2"
516
517         return $?
518 }
519
520 EQUALS="======================================================================"
521 equals_msg() {
522    msg="$@"
523
524    local suffixlen=$((${#EQUALS} - ${#msg}))
525    [ $suffixlen -lt 5 ] && suffixlen=5
526    printf '===== %s %.*s\n' "$msg" $suffixlen $EQUALS
527 }
528
529 log() {
530         echo "$*"
531         lctl mark "$*" 2> /dev/null || true
532 }
533
534 run_one() {
535     testnum=$1
536     message=$2
537     tfile=f${testnum}
538     tdir=d${base}
539
540     # Pretty tests run faster.
541     equals_msg $testnum: $message
542
543     log "== test $1: $2"
544     test_${testnum} || error "test_$testnum failed with $?"
545 }
546
547 canonical_path() {
548    (cd `dirname $1`; echo $PWD/`basename $1`)
549 }
550