here is my script to rsync a directory to a zfs filesystem, rotate existing snapshots, then create a "latest" snapshot. work to be done - check for an include/exclude list for the rsync command - create a monthly snapshot be careful of possible line wraps #!/bin/sh RSYNC_CMD="/usr/local/bin/rsync -axS --delete-delay --stats" # first argument is the remote server to connect (ie. server1) # second argument is the remote target (ie. /home/) note trailing slashes just like in rsync # third argument is which pool to use (ie. tank) # fourth argument is what ZFS fileystem on that pool (ie server1/home) # fifth argument is how many snapshots for this zfs filesystem RMT_SERVER=$1 RMT_TARGET=$2 LCL_POOL=$3 LCL_ZFS=$4 SNAPCOUNT=$5 OUTFILE=/tmp/rsync_zfs_rotate-${LCL_POOL}-${LCL_ZFS}.log ERRFILE=/tmp/rsync_zfs_rotate-${LCL_POOL}-${LCL_ZFS}.err MAILER=/usr/sbin/sendmail MAILTO=someone at domain.com # NO EDITS BELOW THIS ################################################### # remove any old ERRFILE/OUTFILE to start fresh rm -f ${OUTFILE} rm -f ${ERRFILE} echo "" > $OUTFILE echo "----------------- RSYNC BEGIN ----------------" >> $OUTFILE date >> $OUTFILE echo "" >> $OUTFILE echo "$RSYNC_CMD $RMT_SERVER:$RMT_TARGET /$LCL_POOL/$LCL_ZFS" >> $OUTFILE $RSYNC_CMD $RMT_SERVER:$RMT_TARGET /$LCL_POOL/$LCL_ZFS 2> $ERRFILE >> $OUTFILE ERR=$? if [ "$ERR" != "0" ] ; then if [ "$ERR" != "24" ] ; then echo "Rsync Error Code $ERR" ; cat $ERRFILE | mailx -s "RSYNC BACKUP ERROR - ${RMT_SERVER}:${RMT_TARGET}" ${MAILTO} ; exit ; fi ; fi ; echo "" >> $OUTFILE date >> $OUTFILE echo "------------------ RSYNC END ------------------" >> $OUTFILE echo "" >> $OUTFILE echo "" >> $OUTFILE echo "" >> $OUTFILE echo "--------------- BEGIN ZFS ROTATION ------------------" >> $OUTFILE date >> $OUTFILE echo "" >> $OUTFILE echo "Number of snapshots to keep=${SNAPCOUNT}" SNAPPATH=/${LCL_POOL}/${LCL_ZFS}/.zfs/snapshot NEWSNAP=${SNAPCOUNT} ; # destroy the oldest ($SNAPCOUNT) if exists if [ -d ${SNAPPATH}/${SNAPCOUNT} ] ; then echo "" ; echo "Found ${LCL_POOL}/${LCL_ZFS}@${SNAPCOUNT}" ; echo "destroying snapshot ${SNAPCOUNT} found for ${LCL_ZFS}" ; echo "zfs destroy ${LCL_POOL}/${LCL_ZFS}@${SNAPCOUNT}" ; echo "destroying snapshot ${SNAPCOUNT} found for ${LCL_ZFS}" >> $OUTFILE ; echo "zfs destroy ${LCL_POOL}/${LCL_ZFS}@${SNAPCOUNT}" >> $OUTFILE ; zfs destroy ${LCL_POOL}/${LCL_ZFS}@${SNAPCOUNT} 2> $ERRFILE ; SNAPCOUNT=`expr $SNAPCOUNT - 1` ; echo "" ; echo "" ; fi ; # start searching for the others until [ $SNAPCOUNT -lt 1 ]; do echo "Looking for ${LCL_POOL}/${LCL_ZFS}@${SNAPCOUNT}" ; if [ -d ${SNAPPATH}/${SNAPCOUNT} ]; then OLDSNAP=${SNAPCOUNT} ; NEWSNAP=${OLDSNAP} ; NEWSNAP=`expr $NEWSNAP + 1` ; echo "SNAPCOUNT = ${SNAPCOUNT} NEWSNAP = ${NEWSNAP}" ; echo "Found ${LCL_POOL}/${LCL_ZFS}@${OLDSNAP}" ; echo "" ; echo "zfs rename ${LCL_POOL}/${LCL_ZFS}@${OLDSNAP} ${LCL_POOL}/${LCL_ZFS}@${NEWSNAP}" ; echo "zfs rename ${LCL_POOL}/${LCL_ZFS}@${OLDSNAP} ${LCL_POOL}/${LCL_ZFS}@${NEWSNAP}" >> $OUTFILE ; zfs rename ${LCL_POOL}/${LCL_ZFS}@${OLDSNAP} ${LCL_POOL}/${LCL_ZFS}@${NEWSNAP} 2>> $ERRFILE ; SNAPCOUNT=`expr $SNAPCOUNT - 1` ; echo "" ; echo "" ; else OLDSNAP=${SNAPCOUNT} ; NEWSNAP=${OLDSNAP} ; NEWSNAP=`expr $NEWSNAP + 1` ; echo "SNAPCOUNT = ${SNAPCOUNT} NEWSNAP = ${NEWSNAP}" ; echo "${LCL_POOL}/${LCL_ZFS}@${OLDSNAP} not found"; echo "${LCL_POOL}/${LCL_ZFS}@${OLDSNAP} not found" >> $OUTFILE ; SNAPCOUNT=`expr $SNAPCOUNT - 1` ; echo "" ; echo "" ; fi ; done ; # now rotate latest to 1 if exists if [ -d ${SNAPPATH}/latest ]; then echo "Found ${LCL_POOL}/${LCL_ZFS}@latest" ; echo "" ; zfs rename ${LCL_POOL}/${LCL_ZFS}@latest ${LCL_POOL}/${LCL_ZFS}@1 2>> $ERRFILE ; echo "zfs rename ${LCL_POOL}/${LCL_ZFS}@latest ${LCL_POOL}/${LCL_ZFS}@1" ; echo "zfs rename ${LCL_POOL}/${LCL_ZFS}@latest ${LCL_POOL}/${LCL_ZFS}@1" >> $OUTFILE ; echo "" ; fi ; # create the latest snapshot echo "Creating latest snapshot" ; zfs snapshot ${LCL_POOL}/${LCL_ZFS}@latest 2>> $ERRFILE ; echo "zfs snapshot ${LCL_POOL}/${LCL_ZFS}@latest" ; echo "zfs snapshot ${LCL_POOL}/${LCL_ZFS}@latest" >> $OUTFILE ; echo "" >> $OUTFILE date >> $OUTFILE echo "--------------- END ZFS ROTATION ------------------" >> $OUTFILE echo "" >> $OUTFILE # now we will send an email with all this if [ -s ${ERRFILE} ]; then cat $ERRFILE | mailx -s "BACKUP ERROR - ${RMT_SERVER}:${RMT_TARGET}" ${MAILTO} ; cat $OUTFILE | mailx -s "BACKUP REPORT - ${RMT_SERVER}:${RMT_TARGET}" ${MAILTO} ; else cat $OUTFILE | mailx -s "BACKUP REPORT - ${RMT_SERVER}:${RMT_TARGET}" ${MAILTO} ; fi ;