FreeNAS Bash script to start a ZFS scrub on each pool (scrub.sh)

This script will start a scrub on each ZFS pool (one at a time) and will send an e-mail or display the result when everyting is completed. I wrote this script to launch each scrub one after the other and a summary by e-mail that can tell me how much time it took to each ZFS scrub.

Put this script on your FreeNAS box using the File Manager or directly at the shell by copy-pasting it. I put it in “/mnt/usb-data/bin/scrub.sh”.

To make it run automatically, go into System –> Advanced –> Cron and add it as Monthly cron job.

NOTE: Don’t forget to change the e-mail addresses in the script!

FROM=from@devnull.com
TO=to@devnull.com

Here’s the script:

#!/bin/bash

#VERSION: 0.2
#AUTHOR: gimpe
#EMAIL: gimpe [at] hype-o-thetic.com
#WEBSITE: http://hype-o-thetic.com
#DESCRIPTION: Created on FreeNAS 0.7RC1 (Sardaukar)
# This script will start a scrub on each ZFS pool (one at a time) and
# will send an e-mail or display the result when everyting is completed.

#CHANGELOG
# 0.2: 2009-08-27 Code clean up
# 0.1: 2009-08-25 Make it work

#SOURCES:
# http://aspiringsysadmin.com/blog/2007/06/07/scrub-your-zfs-file-systems-regularly/
# http://www.sun.com/bigadmin/scripts/sunScripts/zfs_completion.bash.txt
# http://www.packetwatch.net/documents/guides/2009073001.php

# e-mail variables
FROM=from@devnull.com
TO=to@devnull.com
SUBJECT="$0 results"
BODY=""

# arguments
VERBOSE=0
SENDEMAIL=1
args=("$@")
for arg in $args; do
    case $arg in
        "-v" | "--verbose")
            VERBOSE=1
            ;;
        "-n" | "--noemail")
            SENDEMAIL=0
            ;;
        "-a" | "--author")
            echo "by gimpe at hype-o-thetic.com"
            exit
            ;;
        "-h" | "--help" | *)
            echo "
usage: $0 [-v --verbose|-n --noemail]
    -v --verbose    output display
    -n --noemail    don't send an e-mail with result
    -a --author     display author info (by gimpe at hype-o-thetic.com)
    -h --help       display this help
"
            exit
            ;;
    esac
done

# work variables
ERROR=0
SEP=" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "
RUNNING=1

# commands & configuration
ZPOOL=/sbin/zpool
PRINTF=/usr/bin/printf
MSMTP=/usr/local/bin/msmtp
MSMTPCONF=/var/etc/msmtp.conf

# print a message
function _log {
    DATE="`date +"%Y-%m-%d %H:%M:%S"`"
    # add message to e-mail body
    BODY="${BODY}$DATE: $1\n"

    # output to console if verbose mode
    if [ $VERBOSE = 1 ]; then
        echo "$DATE: $1"
    fi
}

# find all pools
pools=$($ZPOOL list -H -o name)

# for each pool
for pool in $pools; do
    # start scrub for $pool
    _log "starting scrub on $pool"
    zpool scrub $pool
    RUNNING=1
    # wait until scrub for $pool has finished running
    while [ $RUNNING = 1 ];     do
        # still running?
        if $ZPOOL status -v $pool | grep -q "scrub in progress"; then
            sleep 60
        # not running
        else
            # finished with this pool, exit
            _log "scrub ended on $pool"
            _log "`$ZPOOL status -v $pool`"
            _log "$SEP"
            RUNNING=0
            # check for errors
            if ! $ZPOOL status -v $pool | grep -q "No known data errors"; then
                _log "data errors detected on $pool"
                ERROR=1
            fi
        fi
    done
done

# change e-mail subject if there was error
if [ $ERROR = 1 ]; then
    SUBJECT="${SUBJECT}: ERROR(S) DETECTED"
fi

# send e-mail
if [ $SENDEMAIL = 1 ]; then
    $PRINTF "From:$FROM\nTo:$TO\nSubject:$SUBJECT\n\n$BODY" | $MSMTP --file=$MSMTPCONF -t
fi

Here’s what the e-mail content looks like:

2009-09-01 02:00:01: starting scrub on backup
2009-09-01 02:35:19: scrub ended on backup
2009-09-01 02:35:19:   pool: backup
 state: ONLINE
 scrub: scrub completed with 0 errors on Tue Sep  1 02:34:50 2009
config:

       NAME        STATE     READ WRITE CKSUM
       backup      ONLINE       0     0     0
         mirror    ONLINE       0     0     0
           ad8     ONLINE       0     0     0
           ad10    ONLINE       0     0     0

errors: No known data errors
2009-09-01 02:35:19:  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2009-09-01 02:35:19: starting scrub on data
2009-09-01 02:41:24: scrub ended on data
2009-09-01 02:41:24:   pool: data
 state: ONLINE
 scrub: scrub completed with 0 errors on Tue Sep  1 02:40:50 2009
config:

       NAME        STATE     READ WRITE CKSUM
       data        ONLINE       0     0     0
         ad6       ONLINE       0     0     0

errors: No known data errors
2009-09-01 02:41:24:  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2009-09-01 02:41:24: starting scrub on media
2009-09-01 05:41:58: scrub ended on media
2009-09-01 05:41:58:   pool: media
 state: ONLINE
 scrub: scrub completed with 0 errors on Tue Sep  1 05:41:00 2009
config:

       NAME        STATE     READ WRITE CKSUM
       media       ONLINE       0     0     0
         ad14      ONLINE       0     0     0

errors: No known data errors
2009-09-01 05:41:58:  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Please, leave me a comment if you use it to let me know what you think!

4 Comments

  1. [...] You can find the script here: FreeNAS Bash script to start a ZFS scrub on each pool (scrub.sh) – hype-o-thetic?com [...]

  2. [...] hype-o-thetic?com : FreeNAS Bash playscript to move a ZFS vegetation on … [...]

  3. harryd71 says:

    Many thanks for this script. I’ve written a blogpost about scrubbing and take snapshots and I’ve added a link to your website…

    See here -> http://harryd71.blogspot.com/2009/10/freenas-07-zfs-snapshots-and-scrubbing.html

  4. [...] hype-o-thetic?com : FreeNAS Bash script to start a ZFS scrub …pools=$($ZPOOL list -H -o name) # for each pool. for pool in $pools; do # start scrub for … zpool [...]

Leave a Reply

Creative Commons Attribution-ShareAlike 2.5 Canada
This work by gimpe is licensed under a Creative Commons Attribution-ShareAlike 2.5 Canada.