2014-11-18 16:02:20 +01:00
#!/bin/sh
#
# 2014/11/14 - Initial script creation
#
# Based on snapxfer script by pds from zpool.org
# https://zpool.org/zfs-snapshots-and-remote-replication/
#
# Also main use zfSnap (https://github.com/zfsnap/zfsnap/wiki/zfSnap)
# Must take the 1.x version (tree legacy). Too many changes in the 2.0.0 beta.
# Local ZFS filesystems that will have a snapshot
DATASETS = "datastore/vm"
# Destination host for snapshot replication
# The user must have enought rights to use `zfs command`
2014-11-20 14:30:29 +01:00
DHOST = "root@192.168.0.100"
2014-11-18 16:02:20 +01:00
# Output logfile
LOGFILE = "/var/log/snapsend/snapsend.log"
2014-11-20 14:30:29 +01:00
# Temp file for mail content
TEMP_MAIL = "/var/log/snapsend/temp.mail"
2014-11-18 16:02:20 +01:00
# Tools that help implement snapshot logic (and transfer soon according the pull-requests)
ZSNAP = "/usr/local/bin/zfSnap.sh"
# Administrator's email
MAILADMIN = "admin1@localhost,admin2@localhost"
# List of all ZFS snapshot
SNAP_LIST = ''
REMOTE_SNAP_LIST = ''
# The prefix to add to the previous snapshot's name which is now useless
PREFIXSNAP = 'done_'
######################################################################
# Functions #
######################################################################
# Returns 0 if snapshot exists
SnapExists( ) {
SNAP_LIST = " ${ SNAP_LIST :- ` zfs list -H -o name -t snapshot` } "
local i
for i in $SNAP_LIST ; do
[ " $1 " = " $i " ] && return 0
done
return 1
}
# Returns 0 if snapshot exists on the remote host
RemoteSnapExist( ) {
REMOTE_SNAP_LIST = " ${ REMOTE_SNAP_LIST :- ` ssh ${ 1 } zfs list -H -o name -t snapshot` } "
local i
for i in $REMOTE_SNAP_LIST ; do
[ " $2 " = " $i " ] && return 0
done
return 1
}
######################################################################
# Main logic #
######################################################################
interval = $1
usage( )
{
if [ " X ${ interval } " = "X" ] ; then
printf 'Usage: %s (async|hourly|daily|weekly|purge)\n' $( basename $0 )
printf '\n'
printf '* Asynchronous DR snapshots are kept for 1 hour\n'
printf '* Hourly snapshots are kept for 1 day\n'
printf '* Daily snapshots are kept for one week\n'
printf '* Weekly snapshots are kept for one month\n'
printf '\n'
exit 1
fi
}
if [ ! -f " ${ LOGFILE } " ] ; then
mkdir -p $( dirname ${ LOGFILE } )
touch " ${ LOGFILE } "
2014-11-20 14:30:29 +01:00
touch " ${ TEMP_MAIL } "
2014-11-18 16:02:20 +01:00
fi
case " ${ interval } " in
'async' )
for dset in $DATASETS
do
# Take snapshots for asynchronouss DR purposes
$ZSNAP -v -s -S -a 1h $dset >> $LOGFILE
# Get the last snapshot name on localhost
LOCALSNAP = $( zfs list -H -o name -t snapshot -r ${ dset } | tail -n1 | cut -d@ -f2)
#printf 'Local snapshot: %s\n' ${LOCALSNAP}
# Get the last snapshot name on remote host $DHOST
DHOSTSNAP = $( ssh ${ DHOST } zfs list -H -o name -t snapshot -r ${ dset } | tail -n1 | cut -d@ -f2)
#printf 'Remote snapshot: %s\n' ${DHOSTSNAP}
# Test if $DHOSTSNAP exist on the local system
# Recompose the full snapshot name with $dset@$DHOSTSNAP
if SnapExists " ${ dset } @ ${ DHOSTSNAP } " ; then
#printf '%s exist on the local system\n' ${DHOSTSNAP}
printf '%s@%s will be send to %s to replace the old snapshot: %s' ${ dset } ${ LOCALSNAP } ${ DHOST } ${ DHOSTSNAP } >> $LOGFILE
# Send the snapshot the remote host
# zfs send -I datastore/vm@2014-11-17_11.26.22--1h datastore/vm@2014-11-18_14.19.10--1h | ssh nec02.ipr.univ-rennes1.fr zfs recv datastore/vm
zfs send -I " ${ DHOSTSNAP } " " ${ dset } @ ${ LOCALSNAP } " | ssh " ${ DHOST } " zfs recv " ${ dset } "
2014-11-20 14:30:29 +01:00
printf ' ... DONE\n' >> $LOGFILE
2014-11-18 16:02:20 +01:00
else
# Mail admin
2014-11-20 14:30:29 +01:00
printf 'ERROR snapshot %s does not exist on the local system\n' ${ DHOSTSNAP } | mail ${ MAILADMIN } -s " snapsend_error $( hostname -f) "
2014-11-18 16:02:20 +01:00
printf 'ERROR snapshot %s for %s does not exist on the local system\n' ${ DHOSTSNAP } ${ dset } >> $LOGFILE
fi
# Test if the snapshot was successfully receive on the remote host
if RemoteSnapExist " ${ DHOST } " " ${ dset } @ ${ LOCALSNAP } " ; then
printf 'SUCCESS: the snapshot %s for %s exist on the remote host (%s)\n' ${ LOCALSNAP } ${ dset } ${ DHOST } >> $LOGFILE
# Rename the useless snapshot for the next purge
zfs rename ${ dset } @${ DHOSTSNAP } ${ dset } @${ PREFIXSNAP } ${ DHOSTSNAP }
else
# Mail admin
2014-11-20 14:30:29 +01:00
printf 'ERROR snapshot %s for %s does not exist on the remote host (%s)\n' ${ LOCALSNAP } ${ dset } ${ DHOST } | mail ${ MAILADMIN } -s " snapsend_error $( hostname -f) "
2014-11-18 16:02:20 +01:00
printf 'ERROR snapshot %s for %s does not exist on the remote host (%s)\n' ${ LOCALSNAP } ${ dset } ${ DHOST } >> $LOGFILE
fi
done
printf '\n' >> $LOGFILE
; ;
'hourly' )
# take snapshots, keep for one day
for dset in $DATASETS
do
$ZSNAP -v -s -S -a 1d $dset >> $LOGFILE
done
printf '\n' >> $LOGFILE
; ;
'daily' )
# take snapshots, keep for one week
for dset in $DATASETS
do
2014-11-20 14:30:29 +01:00
$ZSNAP -v -s -S -a 1w $dset >> $TEMP_MAIL
2014-11-18 16:02:20 +01:00
done
# Purge snapshots according to TTL
2014-11-20 14:30:29 +01:00
$ZSNAP -v -s -S -d -p ${ PREFIXSNAP } >> $TEMP_MAIL
printf '\n' >> $TEMP_MAIL
# Send email to admin
cat $TEMP_MAIL | mail ${ MAILADMIN } -s " Daily snapshot $( hostname -f) "
# Send the previous log to the main logfile
cat ${ TEMP_MAIL } >> ${ LOGFILE }
rm -f ${ TEMP_MAIL }
2014-11-18 16:02:20 +01:00
; ;
'weekly' )
# take snapshots, keep for one month
for dset in $DATASETS
do
$ZSNAP -v -s -S -a 1m $dset >> $LOGFILE
done
printf '\n' >> $LOGFILE
; ;
'purge' )
# purge snapshots according to TTL
$ZSNAP -v -s -S -d
; ;
* )
usage
; ;
esac
exit 0