]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - scripts/zimport.sh
zimport.sh: Allow custom pool create options
[FreeBSD/FreeBSD.git] / scripts / zimport.sh
1 #!/bin/bash
2 #
3 # Verify that an assortment of known good reference pools can be imported
4 # using different versions of the ZoL code.
5 #
6 # By default references pools for the major ZFS implementation will be
7 # checked against the most recent ZoL tags and the master development branch.
8 # Alternate tags or branches may be verified with the '-s <src-tag> option.
9 # Passing the keyword "installed" will instruct the script to test whatever
10 # version is installed.
11 #
12 # Preferentially a reference pool is used for all tests.  However, if one
13 # does not exist and the pool-tag matches one of the src-tags then a new
14 # reference pool will be created using binaries from that source build.
15 # This is particularly useful when you need to test your changes before
16 # opening a pull request.  The keyword 'all' can be used as short hand
17 # refer to all available reference pools.
18 #
19 # New reference pools may be added by placing a bzip2 compressed tarball
20 # of the pool in the scripts/zfs-images directory and then passing
21 # the -p <pool-tag> option.  To increase the test coverage reference pools
22 # should be collected for all the major ZFS implementations.  Having these
23 # pools easily available is also helpful to the developers.
24 #
25 # Care should be taken to run these tests with a kernel supported by all
26 # the listed tags.  Otherwise build failure will cause false positives.
27 #
28 #
29 # EXAMPLES:
30 #
31 # The following example will verify the zfs-0.6.2 tag, the master branch,
32 # and the installed zfs version can correctly import the listed pools.
33 # Note there is no reference pool available for master and installed but
34 # because binaries are available one is automatically constructed.  The
35 # working directory is also preserved between runs (-k) preventing the
36 # need to rebuild from source for multiple runs.
37 #
38 #  zimport.sh -k -f /var/tmp/zimport \
39 #      -s "zfs-0.6.2 master installed" \
40 #      -p "zevo-1.1.1 zol-0.6.2 zol-0.6.2-173 master installed"
41 #
42 # --------------------- ZFS on Linux Source Versions --------------
43 #                 zfs-0.6.2       master          0.6.2-175_g36eb554
44 # -----------------------------------------------------------------
45 # Clone SPL       Local         Local           Skip
46 # Clone ZFS       Local         Local           Skip
47 # Build SPL       Pass          Pass            Skip
48 # Build ZFS       Pass          Pass            Skip
49 # -----------------------------------------------------------------
50 # zevo-1.1.1      Pass          Pass            Pass
51 # zol-0.6.2       Pass          Pass            Pass
52 # zol-0.6.2-173   Fail          Pass            Pass
53 # master          Pass          Pass            Pass
54 # installed       Pass          Pass            Pass
55 #
56
57 BASE_DIR=$(dirname "$0")
58 SCRIPT_COMMON=common.sh
59 if [ -f "${BASE_DIR}/${SCRIPT_COMMON}" ]; then
60         . "${BASE_DIR}/${SCRIPT_COMMON}"
61 else
62         echo "Missing helper script ${SCRIPT_COMMON}" && exit 1
63 fi
64
65 PROG=zimport.sh
66 SRC_TAGS="zfs-0.6.5.11 master"
67 POOL_TAGS="all master"
68 POOL_CREATE_OPTIONS=
69 TEST_DIR=$(mktemp -u -d -p /var/tmp zimport.XXXXXXXX)
70 KEEP="no"
71 VERBOSE="no"
72 COLOR="yes"
73 REPO="https://github.com/zfsonlinux"
74 IMAGES_DIR="$SCRIPTDIR/zfs-images/"
75 IMAGES_TAR="https://github.com/zfsonlinux/zfs-images/tarball/master"
76 ERROR=0
77
78 CONFIG_LOG="configure.log"
79 CONFIG_OPTIONS=${CONFIG_OPTIONS:-""}
80 MAKE_LOG="make.log"
81 MAKE_OPTIONS=${MAKE_OPTIONS:-"-s -j$(nproc)"}
82
83 COLOR_GREEN="\033[0;32m"
84 COLOR_RED="\033[0;31m"
85 COLOR_BROWN="\033[0;33m"
86 COLOR_RESET="\033[0m"
87
88 usage() {
89 cat << EOF
90 USAGE:
91 zimport.sh [hvl] [-r repo] [-s src-tag] [-i pool-dir] [-p pool-tag]
92     [-f path] [-o options]
93
94 DESCRIPTION:
95         ZPOOL import verification tests
96
97 OPTIONS:
98         -h                Show this message
99         -v                Verbose
100         -c                No color
101         -k                Keep temporary directory
102         -r <repo>         Source repository ($REPO)
103         -s <src-tag>...   Verify ZoL versions with the listed tags
104         -i <pool-dir>     Pool image directory
105         -p <pool-tag>...  Verify pools created with the listed tags
106         -f <path>         Temporary directory to use
107         -o <options>      Additional options to pass to 'zpool create'
108
109 EOF
110 }
111
112 while getopts 'hvckr:s:i:p:f:o:?' OPTION; do
113         case $OPTION in
114         h)
115                 usage
116                 exit 1
117                 ;;
118         v)
119                 VERBOSE="yes"
120                 ;;
121         c)
122                 COLOR="no"
123                 ;;
124         k)
125                 KEEP="yes"
126                 ;;
127         r)
128                 REPO="$OPTARG"
129                 ;;
130         s)
131                 SRC_TAGS="$OPTARG"
132                 ;;
133         i)
134                 IMAGES_DIR="$OPTARG"
135                 ;;
136         p)
137                 POOL_TAGS="$OPTARG"
138                 ;;
139         f)
140                 TEST_DIR="$OPTARG"
141                 ;;
142         o)
143                 POOL_CREATE_OPTIONS="$OPTARG"
144                 ;;
145         ?)
146                 usage
147                 exit 1
148                 ;;
149         esac
150 done
151
152 #
153 # Verify the module start is not loaded
154 #
155 if lsmod | grep zfs >/dev/null; then
156         echo "ZFS modules must be unloaded"
157         exit 1
158 fi
159
160 #
161 # Create a random directory tree of files and sub-directories to
162 # to act as a copy source for the various regression tests.
163 #
164 populate() {
165         local ROOT=$1
166         local MAX_DIR_SIZE=$2
167         local MAX_FILE_SIZE=$3
168
169         # shellcheck disable=SC2086
170         mkdir -p $ROOT/{a,b,c,d,e,f,g}/{h,i}
171         DIRS=$(find "$ROOT")
172
173         for DIR in $DIRS; do
174                 COUNT=$((RANDOM % MAX_DIR_SIZE))
175
176                 # shellcheck disable=SC2034
177                 for i in $(seq $COUNT); do
178                         FILE=$(mktemp -p "$DIR")
179                         SIZE=$((RANDOM % MAX_FILE_SIZE))
180                         dd if=/dev/urandom of="$FILE" bs=1k \
181                             count="$SIZE" &>/dev/null
182                 done
183         done
184
185         return 0
186 }
187
188 SRC_DIR=$(mktemp -d -p /var/tmp/ zfs.src.XXXXXXXX)
189 trap 'rm -Rf "$SRC_DIR"' INT TERM EXIT
190 populate "$SRC_DIR" 10 100
191
192 SRC_DIR="$TEST_DIR/src"
193 SRC_DIR_SPL="$SRC_DIR/spl"
194 SRC_DIR_ZFS="$SRC_DIR/zfs"
195
196 if [ "$COLOR" = "no" ]; then
197         COLOR_GREEN=""
198         COLOR_BROWN=""
199         COLOR_RED=""
200         COLOR_RESET=""
201 fi
202
203 pass_nonewline() {
204         echo -n -e "${COLOR_GREEN}Pass${COLOR_RESET}\t\t"
205 }
206
207 skip_nonewline() {
208         echo -n -e "${COLOR_BROWN}Skip${COLOR_RESET}\t\t"
209 }
210
211 fail_nonewline() {
212         echo -n -e "${COLOR_RED}Fail${COLOR_RESET}\t\t"
213 }
214
215 #
216 # Log a failure message, cleanup, and return an error.
217 #
218 fail() {
219         echo -e "$PROG: $1" >&2
220         $ZFS_SH -u >/dev/null 2>&1
221         exit 1
222 }
223
224 #
225 # Set several helper variables which are derived from a source tag.
226 #
227 # SPL_TAG - The tag zfs-x.y.z is translated to spl-x.y.z.
228 # SPL_DIR - The spl directory name.
229 # SPL_URL - The spl github URL to fetch the tarball.
230 # ZFS_TAG - The passed zfs-x.y.z tag
231 # ZFS_DIR - The zfs directory name
232 # ZFS_URL - The zfs github URL to fetch the tarball
233 #
234 src_set_vars() {
235         local TAG=$1
236
237         SPL_TAG="${TAG//zfs/spl}"
238         SPL_DIR="$SRC_DIR_SPL/$SPL_TAG"
239         SPL_URL="$REPO/spl/tarball/$SPL_TAG"
240
241         ZFS_TAG="$TAG"
242         ZFS_DIR="$SRC_DIR_ZFS/$ZFS_TAG"
243         ZFS_URL="$REPO/zfs/tarball/$ZFS_TAG"
244
245         if [ "$TAG" = "installed" ]; then
246                 ZPOOL_CMD=$(which zpool)
247                 ZFS_CMD=$(which zfs)
248                 ZFS_SH="/usr/share/zfs/zfs.sh"
249         else
250                 ZPOOL_CMD="./cmd/zpool/zpool"
251                 ZFS_CMD="./cmd/zfs/zfs"
252                 ZFS_SH="./scripts/zfs.sh"
253         fi
254 }
255
256 #
257 # Set several helper variables which are derived from a pool name such
258 # as zol-0.6.x, zevo-1.1.1, etc.  These refer to example pools from various
259 # ZFS implementations which are used to verify compatibility.
260 #
261 # POOL_TAG          - The example pools name in scripts/zfs-images/.
262 # POOL_BZIP         - The full path to the example bzip2 compressed pool.
263 # POOL_DIR          - The top level test path for this pool.
264 # POOL_DIR_PRISTINE - The directory containing a pristine version of the pool.
265 # POOL_DIR_COPY     - The directory containing a working copy of the pool.
266 # POOL_DIR_SRC      - Location of a source build if it exists for this pool.
267 #
268 pool_set_vars() {
269         local TAG=$1
270
271         POOL_TAG=$TAG
272         POOL_BZIP=$IMAGES_DIR/$POOL_TAG.tar.bz2
273         POOL_DIR=$TEST_DIR/pools/$POOL_TAG
274         POOL_DIR_PRISTINE=$POOL_DIR/pristine
275         POOL_DIR_COPY=$POOL_DIR/copy
276         POOL_DIR_SRC="$SRC_DIR_ZFS/${POOL_TAG//zol/zfs}"
277 }
278
279 #
280 # Construct a non-trivial pool given a specific version of the source.  More
281 # interesting pools provide better test coverage so this function should
282 # extended as needed to create more realistic pools.
283 #
284 pool_create() {
285         pool_set_vars "$1"
286         src_set_vars "$1"
287
288         if [ "$POOL_TAG" != "installed" ]; then
289                 cd "$POOL_DIR_SRC"
290         fi
291
292         $ZFS_SH zfs="spa_config_path=$POOL_DIR_PRISTINE" || \
293             fail "Failed to load kmods"
294
295         # Create a file vdev RAIDZ pool.
296         truncate -s 1G \
297             "$POOL_DIR_PRISTINE/vdev1" "$POOL_DIR_PRISTINE/vdev2" \
298             "$POOL_DIR_PRISTINE/vdev3" "$POOL_DIR_PRISTINE/vdev4" || \
299             fail "Failed 'truncate -s 1G ...'"
300         # shellcheck disable=SC2086
301         $ZPOOL_CMD create $POOL_CREATE_OPTIONS "$POOL_TAG" raidz \
302             "$POOL_DIR_PRISTINE/vdev1" "$POOL_DIR_PRISTINE/vdev2" \
303             "$POOL_DIR_PRISTINE/vdev3" "$POOL_DIR_PRISTINE/vdev4" || \
304             fail "Failed '$ZPOOL_CMD create $POOL_CREATE_OPTIONS $POOL_TAG ...'"
305
306         # Create a pool/fs filesystem with some random contents.
307         $ZFS_CMD create "$POOL_TAG/fs" || \
308             fail "Failed '$ZFS_CMD create $POOL_TAG/fs'"
309         populate "/$POOL_TAG/fs/" 10 100
310
311         # Snapshot that filesystem, clone it, remove the files/dirs,
312         # replace them with new files/dirs.
313         $ZFS_CMD snap "$POOL_TAG/fs@snap" || \
314             fail "Failed '$ZFS_CMD snap $POOL_TAG/fs@snap'"
315         $ZFS_CMD clone "$POOL_TAG/fs@snap" "$POOL_TAG/clone" || \
316             fail "Failed '$ZFS_CMD clone $POOL_TAG/fs@snap $POOL_TAG/clone'"
317         # shellcheck disable=SC2086
318         rm -Rf /$POOL_TAG/clone/*
319         populate "/$POOL_TAG/clone/" 10 100
320
321         # Scrub the pool, delay slightly, then export it.  It is now
322         # somewhat interesting for testing purposes.
323         $ZPOOL_CMD scrub "$POOL_TAG" || \
324             fail "Failed '$ZPOOL_CMD scrub $POOL_TAG'"
325         sleep 10
326         $ZPOOL_CMD export "$POOL_TAG" || \
327             fail "Failed '$ZPOOL_CMD export $POOL_TAG'"
328
329         $ZFS_SH -u || fail "Failed to unload kmods"
330 }
331
332 # If the zfs-images directory doesn't exist fetch a copy from Github then
333 # cache it in the $TEST_DIR and update $IMAGES_DIR.
334 if [ ! -d "$IMAGES_DIR" ]; then
335         IMAGES_DIR="$TEST_DIR/zfs-images"
336         mkdir -p "$IMAGES_DIR"
337         curl -sL "$IMAGES_TAR" | \
338             tar -xz -C "$IMAGES_DIR" --strip-components=1 || \
339             fail "Failed to download pool images"
340 fi
341
342 # Given the available images in the zfs-images directory substitute the
343 # list of available images for the reserved keyword 'all'.
344 for TAG in $POOL_TAGS; do
345
346         if  [ "$TAG" = "all" ]; then
347                 # shellcheck disable=SC2010
348                 ALL_TAGS=$(ls "$IMAGES_DIR" | grep "tar.bz2" | \
349                     sed 's/.tar.bz2//' | tr '\n' ' ')
350                 NEW_TAGS="$NEW_TAGS $ALL_TAGS"
351         else
352                 NEW_TAGS="$NEW_TAGS $TAG"
353         fi
354 done
355 POOL_TAGS="$NEW_TAGS"
356
357 if [ "$VERBOSE" = "yes" ]; then
358         echo "---------------------------- Options ----------------------------"
359         echo "VERBOSE=$VERBOSE"
360         echo "KEEP=$KEEP"
361         echo "REPO=$REPO"
362         echo "SRC_TAGS=$SRC_TAGS"
363         echo "POOL_TAGS=$POOL_TAGS"
364         echo "PATH=$TEST_DIR"
365         echo "POOL_CREATE_OPTIONS=$POOL_CREATE_OPTIONS"
366         echo
367 fi
368
369 if [ ! -d "$TEST_DIR" ]; then
370         mkdir -p "$TEST_DIR"
371 fi
372
373 if [ ! -d "$SRC_DIR" ]; then
374         mkdir -p "$SRC_DIR"
375 fi
376
377 # Print a header for all tags which are being tested.
378 echo "--------------------- ZFS on Linux Source Versions --------------"
379 printf "%-16s" " "
380 for TAG in $SRC_TAGS; do
381         src_set_vars "$TAG"
382
383         if [ "$TAG" = "installed" ]; then
384                 ZFS_VERSION=$(modinfo zfs | awk '/version:/ { print $2; exit }')
385                 if [ -n "$ZFS_VERSION" ]; then
386                         printf "%-16s" "$ZFS_VERSION"
387                 else
388                         fail "ZFS is not installed"
389                 fi
390         else
391                 printf "%-16s" "$TAG"
392         fi
393 done
394 echo -e "\n-----------------------------------------------------------------"
395
396 #
397 # Attempt to generate the tarball from your local git repository, if that
398 # fails then attempt to download the tarball from Github.
399 #
400 printf "%-16s" "Clone SPL"
401 for TAG in $SRC_TAGS; do
402         src_set_vars "$TAG"
403
404         if [ -d "$SPL_DIR" ]; then
405                 skip_nonewline
406         elif  [ "$SPL_TAG" = "installed" ]; then
407                 skip_nonewline
408         else
409                 cd "$SRC_DIR"
410
411                 if [ ! -d "$SRC_DIR_SPL" ]; then
412                         mkdir -p "$SRC_DIR_SPL"
413                 fi
414
415                 git archive --format=tar --prefix="$SPL_TAG/ $SPL_TAG" \
416                     -o "$SRC_DIR_SPL/$SPL_TAG.tar" &>/dev/null || \
417                     rm "$SRC_DIR_SPL/$SPL_TAG.tar"
418                 if [ -s "$SRC_DIR_SPL/$SPL_TAG.tar" ]; then
419                         tar -xf "$SRC_DIR_SPL/$SPL_TAG.tar" -C "$SRC_DIR_SPL"
420                         rm "$SRC_DIR_SPL/$SPL_TAG.tar"
421                         echo -n -e "${COLOR_GREEN}Local${COLOR_RESET}\t\t"
422                 else
423                         mkdir -p "$SPL_DIR" || fail "Failed to create $SPL_DIR"
424                         curl -sL "$SPL_URL" | tar -xz -C "$SPL_DIR" \
425                             --strip-components=1 || \
426                             fail "Failed to download $SPL_URL"
427                         echo -n -e "${COLOR_GREEN}Remote${COLOR_RESET}\t\t"
428                 fi
429         fi
430 done
431 printf "\n"
432
433 #
434 # Attempt to generate the tarball from your local git repository, if that
435 # fails then attempt to download the tarball from Github.
436 #
437 printf "%-16s" "Clone ZFS"
438 for TAG in $SRC_TAGS; do
439         src_set_vars "$TAG"
440
441         if [ -d "$ZFS_DIR" ]; then
442                 skip_nonewline
443         elif  [ "$ZFS_TAG" = "installed" ]; then
444                 skip_nonewline
445         else
446                 cd "$SRC_DIR"
447
448                 if [ ! -d "$SRC_DIR_ZFS" ]; then
449                         mkdir -p "$SRC_DIR_ZFS"
450                 fi
451
452                 git archive --format=tar --prefix="$ZFS_TAG/ $ZFS_TAG" \
453                     -o "$SRC_DIR_ZFS/$ZFS_TAG.tar" &>/dev/null || \
454                     rm "$SRC_DIR_ZFS/$ZFS_TAG.tar"
455                 if [ -s "$SRC_DIR_ZFS/$ZFS_TAG.tar" ]; then
456                         tar -xf "$SRC_DIR_ZFS/$ZFS_TAG.tar" -C "$SRC_DIR_ZFS"
457                         rm "$SRC_DIR_ZFS/$ZFS_TAG.tar"
458                         echo -n -e "${COLOR_GREEN}Local${COLOR_RESET}\t\t"
459                 else
460                         mkdir -p "$ZFS_DIR" || fail "Failed to create $ZFS_DIR"
461                         curl -sL "$ZFS_URL" | tar -xz -C "$ZFS_DIR" \
462                             --strip-components=1 || \
463                             fail "Failed to download $ZFS_URL"
464                         echo -n -e "${COLOR_GREEN}Remote${COLOR_RESET}\t\t"
465                 fi
466         fi
467 done
468 printf "\n"
469
470 # Build the listed tags
471 printf "%-16s" "Build SPL"
472 for TAG in $SRC_TAGS; do
473         src_set_vars "$TAG"
474
475         if [ -f "$SPL_DIR/module/spl/spl.ko" ]; then
476                 skip_nonewline
477         elif  [ "$SPL_TAG" = "installed" ]; then
478                 skip_nonewline
479         else
480                 cd "$SPL_DIR"
481                 make distclean &>/dev/null
482                 ./autogen.sh >>"$CONFIG_LOG" 2>&1 || \
483                     fail "Failed SPL 'autogen.sh'"
484                 # shellcheck disable=SC2086
485                 ./configure $CONFIG_OPTIONS >>"$CONFIG_LOG" 2>&1 || \
486                     fail "Failed SPL 'configure $CONFIG_OPTIONS'"
487                 # shellcheck disable=SC2086
488                 make $MAKE_OPTIONS >>"$MAKE_LOG" 2>&1 || \
489                     fail "Failed SPL 'make $MAKE_OPTIONS'"
490                 pass_nonewline
491         fi
492 done
493 printf "\n"
494
495 # Build the listed tags
496 printf "%-16s" "Build ZFS"
497 for TAG in $SRC_TAGS; do
498         src_set_vars "$TAG"
499
500         if [ -f "$ZFS_DIR/module/zfs/zfs.ko" ]; then
501                 skip_nonewline
502         elif  [ "$ZFS_TAG" = "installed" ]; then
503                 skip_nonewline
504         else
505                 cd "$ZFS_DIR"
506                 make distclean &>/dev/null
507                 ./autogen.sh >>"$CONFIG_LOG" 2>&1 || \
508                     fail "Failed ZFS 'autogen.sh'"
509                 # shellcheck disable=SC2086
510                 ./configure --with-spl="$SPL_DIR" $CONFIG_OPTIONS \
511                     >>"$CONFIG_LOG" 2>&1 || \
512                     fail "Failed ZFS 'configure $CONFIG_OPTIONS'"
513                 # shellcheck disable=SC2086
514                 make $MAKE_OPTIONS >>"$MAKE_LOG" 2>&1 || \
515                     fail "Failed ZFS 'make $MAKE_OPTIONS'"
516                 pass_nonewline
517         fi
518 done
519 printf "\n"
520 echo "-----------------------------------------------------------------"
521
522 # Either create a new pool using 'zpool create', or alternately restore an
523 # existing pool from another ZFS implementation for compatibility testing.
524 for TAG in $POOL_TAGS; do
525         pool_set_vars "$TAG"
526         SKIP=0
527
528         printf "%-16s" "$POOL_TAG"
529         rm -Rf "$POOL_DIR"
530         mkdir -p "$POOL_DIR_PRISTINE"
531
532         # Use the existing compressed image if available.
533         if [ -f "$POOL_BZIP" ]; then
534                 tar -xjf "$POOL_BZIP" -C "$POOL_DIR_PRISTINE" \
535                     --strip-components=1 || \
536                     fail "Failed 'tar -xjf $POOL_BZIP"
537         # Use the installed version to create the pool.
538         elif  [ "$TAG" = "installed" ]; then
539                 pool_create "$TAG"
540         # A source build is available to create the pool.
541         elif [ -d "$POOL_DIR_SRC" ]; then
542                 pool_create "$TAG"
543         else
544                 SKIP=1
545         fi
546
547         # Verify 'zpool import' works for all listed source versions.
548         for TAG in $SRC_TAGS; do
549
550                 if [ $SKIP -eq 1 ]; then
551                         skip_nonewline
552                         continue
553                 fi
554
555                 src_set_vars "$TAG"
556                 if [ "$TAG" != "installed" ]; then
557                         cd "$ZFS_DIR"
558                 fi
559                 $ZFS_SH zfs="spa_config_path=$POOL_DIR_COPY"
560
561                 cp -a --sparse=always "$POOL_DIR_PRISTINE" \
562                     "$POOL_DIR_COPY" || \
563                     fail "Failed to copy $POOL_DIR_PRISTINE to $POOL_DIR_COPY"
564                 POOL_NAME=$($ZPOOL_CMD import -d "$POOL_DIR_COPY" | \
565                     awk '/pool:/ { print $2; exit 0 }')
566
567                 $ZPOOL_CMD import -N -d "$POOL_DIR_COPY" \
568                    "$POOL_NAME" &>/dev/null
569                 if [ $? -ne 0 ]; then
570                         fail_nonewline
571                         ERROR=1
572                 else
573                         $ZPOOL_CMD export "$POOL_NAME" || \
574                             fail "Failed to export pool"
575                         pass_nonewline
576                 fi
577
578                 rm -Rf "$POOL_DIR_COPY"
579
580                 $ZFS_SH -u || fail "Failed to unload kmods"
581         done
582         printf "\n"
583 done
584
585 if [ "$KEEP" = "no" ]; then
586         rm -Rf "$TEST_DIR"
587 fi
588
589 exit $ERROR