Last active
December 14, 2015 07:39
-
-
Save mshroyer/5052559 to your computer and use it in GitHub Desktop.
Utility script for maintaining rolling snapshots of ZFS datasets on FreeBSD 9.1.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| # snapzfs.sh - Maintain rotating ZFS dataset snapshots | |
| # | |
| # Creates, rotates, and prunes rolling snapshots of ZFS datasets. When | |
| # this script is run, the sets defined in the configuration section below | |
| # are snapshot and rotated as necessary depending on the age and number of | |
| # existing snapshots. Written for and tested on FreeBSD 9.1. | |
| # | |
| # Mark Shroyer | |
| # Wed Feb 27 10:39:33 EST 2013 | |
| ### BEGIN CONFIGURATION ################################################### | |
| ## Snapshot set definitions | |
| snapshot_sets='swteam' | |
| # Software team document share | |
| swteam_pool='data' | |
| swteam_dataset='swteam' | |
| swteam_mount='/data/swteam' | |
| swteam_keep_days=7 | |
| swteam_keep_weeks=4 | |
| swteam_keep_months=6 | |
| ### END CONFIGURATION ##################################################### | |
| alias zfs=/sbin/zfs | |
| get_mtime() | |
| { | |
| stat -f %Sm -t $1 $2 | |
| } | |
| snapshot_name() | |
| { | |
| local class="$1" | |
| local number="$2" | |
| printf "%s.%03d" "$class" "$number" | |
| } | |
| create_snapshot() | |
| { | |
| local pool="$1" | |
| local dataset="$2" | |
| local mount="$3" | |
| local class="$4" | |
| local retention="$5" | |
| echo "=> Deleting expired ${class} snapshots..." | |
| local index_max=$(( $retention - 1)) | |
| local index_cur=$index_max | |
| local snapshot_cur=`snapshot_name ${class} ${index_cur}` | |
| while [ -e "${mount}/.zfs/snapshot/${snapshot_cur}" ]; do | |
| echo "${mount}/${snapshot_cur}" | |
| zfs destroy "${pool}/${dataset}@${snapshot_cur}" | |
| index_cur=$(( $index_cur + 1 )) | |
| snapshot_cur=`snapshot_name ${class} ${index_cur}` | |
| done | |
| echo "=> Rotating ${class} snapshots..." | |
| local index_new=$index_max | |
| local index_old= | |
| while [ $index_new -gt 0 ]; do | |
| index_old=$(( $index_new - 1)) | |
| local name_old=`snapshot_name ${class} ${index_old}` | |
| local name_new=`snapshot_name ${class} ${index_new}` | |
| if [ -e "${mount}/.zfs/snapshot/${name_old}" ]; then | |
| zfs rename "${pool}/${dataset}@${name_old}" \ | |
| "${pool}/${dataset}@${name_new}" | |
| fi | |
| index_new=$index_old | |
| done | |
| echo "=> Creating new ${class} snapshot..." | |
| local snapshot_first=`snapshot_name ${class} 0` | |
| zfs snapshot "${pool}/${dataset}@${snapshot_first}" | |
| } | |
| check_snapshot() | |
| { | |
| local pool="$1" | |
| local dataset="$2" | |
| local mount="$3" | |
| local class="$4" | |
| local retention="$5" | |
| local format="$6" | |
| if [ -z "$retention" ] || [ "$retention" -eq 0 ]; then | |
| # Don't need a snapshot | |
| return 1 | |
| fi | |
| local snapshot_path="${mount}/.zfs/snapshot/`snapshot_name ${class} 0`" | |
| if [ ! -e "${snapshot_path}" ]; then | |
| # Time for a new snapshot | |
| return 0 | |
| fi | |
| local date_current=`date +${format}` | |
| local date_snapshot=`get_mtime ${format} ${snapshot_path}` | |
| if [ $date_current -gt $date_snapshot ]; then | |
| # Time for a new snapshot | |
| return 0 | |
| else | |
| # No new snapshot in this class required | |
| return 1 | |
| fi | |
| } | |
| for set_name in `echo $snapshot_sets`; do | |
| set_pool=`eval "echo \\\$\${set_name}_pool"` | |
| set_dataset=`eval "echo \\\$\${set_name}_dataset"` | |
| set_mount=`eval "echo \\\$\${set_name}_mount"` | |
| set_keep_days=`eval "echo \\\$\${set_name}_keep_days"` | |
| set_keep_weeks=`eval "echo \\\$\${set_name}_keep_weeks"` | |
| set_keep_months=`eval "echo \\\$\${set_name}_keep_months"` | |
| # So that future date comparisons against the snapshot's mtime will | |
| # work as expected... | |
| touch "${set_mount}" | |
| check_snapshot "$set_pool" "$set_dataset" "$set_mount" \ | |
| daily "$set_keep_days" %Y%j | |
| if [ $? -eq 0 ]; then | |
| create_snapshot "$set_pool" "$set_dataset" "$set_mount" \ | |
| daily "$set_keep_days" | |
| fi | |
| check_snapshot "$set_pool" "$set_dataset" "$set_mount" \ | |
| weekly "$set_keep_weeks" %Y%U | |
| if [ $? -eq 0 ]; then | |
| create_snapshot "$set_pool" "$set_dataset" "$set_mount" \ | |
| weekly "$set_keep_weeks" | |
| fi | |
| check_snapshot "$set_pool" "$set_dataset" "$set_mount" \ | |
| monthly "$set_keep_months" %Y%m | |
| if [ $? -eq 0 ]; then | |
| create_snapshot "$set_pool" "$set_dataset" "$set_mount" \ | |
| monthly "$set_keep_months" | |
| fi | |
| done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment