andyleonard.com – zfs-snapshot.sh

Here’s a nice script found on thinking sysadmin. I slightly modified it to use the real mount point instead of assuming “/”, my changes are highlighted below:

#!/usr/local/bin/bash
# FROM: http://andyleonard.com/2010/04/07/automatic-zfs-snapshot-rotation-on-freebsd/

# 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

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

# 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_MOUNT}/.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_MOUNT}/.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

Thanks Andy!

3 Replies to “andyleonard.com – zfs-snapshot.sh”

  1. Hi, I found that the following addition was needed immediately after the line that sets TARGET_MOUNT, to cope with my ZFS-on-root setup:

    if [ “${TARGET_MOUNT}” == “legacy” ] ; then
    TARGET_MOUNT=””
    fi

    As always, no warranty is offered – use at your own risk! 🙂

  2. On Solaris I found that mnttab was easiest way to get the ZFS dataset name (in poolname/dataset format).

    I used:
    NAWK=”/usr/bin/nawk”
    dataset() {
    $NAWK -v mount=”$1″ ‘BEGIN{FS=”t”} $2==mount&&$3==”zfs”{print $1}’ /etc/mnttab
    }
    zfsdataset=$(dataset $TARGET)

    Then resulting snapshots and renames run against $zfsdataset rather than $TARGET, while the script still looks for $TARGET/.zfs/ for snapshot details. This seems to work well against legacy mounts as well as zfs mountpoints of default and specific flavors. It would do nothing for ZVOLs, though.

    This was written against Solaris 10u11 but it would probably work on Linux /etc/mtab as well. I’d like to use `zfs list -t snapshot`, but that’s not prevalent on every ZFS system.

    I could post the diff, but I think it would clutter up your comments section. Let me know if you want it!

Leave a Reply

Your email address will not be published. Required fields are marked *