thinking sysadmin

qstat -u aleonard -s z

Automatic ZFS Snapshot Rotation on FreeBSD

9 comments

OpenSolaris has ZFS Automatic Snapshots; FreeBSD, while it has ZFS, doesn’t have a comparable feature that I’m aware of. So I wrote my own, zfs-snapshot.sh:

#!/usr/local/bin/bash

# Path to ZFS executable:
ZFS=/sbin/zfs

# Parse arguments:
TARGET=$1
SNAP=$2
COUNT=$3

# Function to display usage:
usage() {
    scriptname=`/usr/bin/basename $0`
    echo "$scriptname: Take and rotate snapshots on a ZFS file system"
    echo
    echo "  Usage:"
    echo "  $scriptname target snap_name count"
    echo
    echo "  target:    ZFS file system to act on"
    echo "  snap_name: Base name for snapshots, to be followed by a '.' and"
    echo "             an integer indicating relative age of the snapshot"
    echo "  count:     Number of snapshots in the snap_name.number format to"
    echo "             keep at one time.  Newest snapshot ends in '.0'."
    echo
    exit
}

# Basic argument checks:
if [ -z $COUNT ] ; then
    usage
fi

if [ ! -z $4 ] ; then
    usage
fi

# Snapshots are number starting at 0; $max_snap is the highest numbered
# snapshot that will be kept.
max_snap=$(($COUNT -1))

# Clean up oldest snapshot:
if [ -d /${TARGET}/.zfs/snapshot/${SNAP}.${max_snap} ] ; then
    $ZFS destroy -r ${TARGET}@${SNAP}.${max_snap}
fi

# Rename existing snapshots:
dest=$max_snap
while [ $dest -gt 0 ] ; do
    src=$(($dest - 1))
    if [ -d /${TARGET}/.zfs/snapshot/${SNAP}.${src} ] ; then
	$ZFS rename -r ${TARGET}@${SNAP}.${src} ${TARGET}@${SNAP}.${dest}
    fi
    dest=$(($dest - 1))
done

# Create new snapshot:
$ZFS snapshot -r ${TARGET}@${SNAP}.0

From the command line, call the script something like the following:

./zfs-snapshot.sh tank weekly 5

This would take a recursive snapshot of the “tank” zpool with the basename weekly, rotating through five snapshots with names “weekly.0″ through “weekly.4″. This allows you to implement a snapshot scheme approximately similar to NetApp’s hourly-daily-weekly scheme, if you like. Because my FreeBSD workstation isn’t on 24×7, I run hourly snapshots out of /etc/crontab:

# Automated ZFS backups (hourly):
0 * * * * root /root/bin/zfs-snapshot.sh tank hourly 25

And daily/weekly/monthly snapshots out of /usr/local/etc/anacrontab (from the sysutils/anacron port):

PATH=/bin:/sbin:/usr/bin:/usr/sbin

# days		make sure the command is executed at least every 'days' days
# delay		delay in minutes, before a command starts
# id		unique id of a command

# days	delay	id		command
1	5	daily		periodic daily
1	10	daily_snap	/root/bin/zfs-snapshot.sh tank daily 8
7	15	weekly		periodic weekly
7	30	weekly_snap	/root/bin/zfs-snapshot.sh tank weekly 5
30	60	monthly		periodic monthly
30	90	monthly_snap	/root/bin/zfs-snapshot.sh tank monthly 13

(Of course, this isn’t as cool as the Gnome-integrated Time Slider in OpenSolaris, but it scratches my itch sufficiently.)

Written by Andy

April 7th, 2010 at 7:59 pm

Posted in freebsd

Tagged with , , , ,

9 Responses to 'Automatic ZFS Snapshot Rotation on FreeBSD'

Subscribe to comments with RSS or TrackBack to 'Automatic ZFS Snapshot Rotation on FreeBSD'.

  1. Thanks for this script!
    But, can You make change this script to:
    script creates a snapshot of the real date/time?
    Like tank@12:00:00-01-31-11

    Best Regards.

    P.s.
    Sorry for my English :)

    Desper

    10 Jan 11 at 1:23 pm

  2. @Desper – The challenge there would be associating a particular time stamp with the type of snapshot. Would you require that your dailies/weeklies/monthlies always run at the same time of day and determine your snapshot type from that? Or would you add a prefix or change the naming convention for the non-hourlies?

    (One nice thing about the time stamp is that you could eliminate the zfs rename portion of the script.)

    Andy

    13 Jan 11 at 11:00 am

  3. Hi there,

    Am running FreeBSD 8.2 with the v28 pool patch, i think something must have changed in the command syntax – i vaguely remember this when i was running OpenSolaris that zfs list changed…

    cannot create snapshot ‘tank/vol0/users@hourly.0′: dataset already exists
    no snapshots were created

    Looks like the rename is not working, will investigate further…

    iMx

    20 Mar 11 at 6:59 am

  4. Ah ha, its this bit:

    # Clean up oldest snapshot:
    if [ -d /${TARGET}/.zfs/snapshot/${SNAP}.${max_snap} ] ; then
    $ZFS destroy -r ${TARGET}@${SNAP}.${max_snap}
    fi

    its because i have the zfs mounted differently from the zpool name:

    ie tank/vol0/users@hourly.0

    is mounted as /vol0/users

    iMx

    20 Mar 11 at 7:02 am

  5. Thanks for your script! I did a small change to use the real mount point with:

    TARGET_MOUNT=$($ZFS get -H -o value mountpoint $TARGET)

    I put a copy on my own blog http://hype-o-thetic.com/2011/03/22/andyleonard-com-zfs-snapshot-sh/

    gimpe

    22 Mar 11 at 6:19 pm

  6. Thanks for the nice script!

    I made it compatible with zfs-fuse which doesn’t have .zfs directories:
    https://gist.github.com/1087896

    Ertug Karamatli

    17 Jul 11 at 10:30 am

  7. @Ertug – Thanks – and interesting timing. I had just written almost the same thing to work around FreeBSD’s kern/156781 bug (the .zfs/snapshot directory stops working).

    Andy

    18 Jul 11 at 11:51 am

  8. @Ertug – Thanks! the current version of zfsonlinux also lacks the .zfs directory. You just saved me a lot of time.

    Aaron

    7 Feb 12 at 7:27 am

Leave a Reply