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.)
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
@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
[...] http://andyleonard.com/2010/04/07/automatic-zfs-snapshot-rotation-on-freebsd/ Amplify’d from andyleonard.com [...]
飄狂山莊 | [引用]zfs snapshot script
10 Mar 11 at 11:02 am
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
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
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
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
@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
@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
I’m setting this up now on my home server, it looks like exactly what I was after. Many thanks for your efforts!
sim
12 Apr 12 at 2:16 pm
Great script and documentation — thanks for all of the time you saved me. Nice to see someone giving back with some KISS code/documentation.
John
23 Apr 12 at 4:14 pm