Skip to content

Commit

Permalink
Implement snapshot replication.
Browse files Browse the repository at this point in the history
  • Loading branch information
FransUrbo committed Apr 3, 2015
1 parent d5cb31a commit df8667b
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 4 deletions.
14 changes: 10 additions & 4 deletions src/zfs-auto-snapshot.8
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,17 @@ PRE is 'zfs\-auto\-snap' by default.
\fB\-q\fR, \fB\-\-quiet\fR
Suppress warnings and notices at the console.
.TP
\fB\-\-send\-full\fR=\fIF\fR
Send zfs full backup. Unimplemented.
\fB\-\-send\-full\fR=\fIhost|ip address\fR
Send zfs full backup to \fIhost\fR (or \fIip address\fR).
.TP
\fB\-\-send\-incr\fR=\fIF\fR
Send zfs incremental backup. Unimplemented.
\fB\-\-send\-incr\fR=\fIhost\fR
Send zfs incremental backup to \fIhost\fR (or \fIip address\fR).
.TP
\fB\-\-send\-opts\fR=\fIOPTS\fR
Option(s) passed to 'zfs send'.
.TP
\fB\-\-recv\-opts\fR=\fIOPTS\fR
Option(s) passed to 'zfs receive'.
.TP
\fB\-\-sep\fR=\fICHAR\fR
Use CHAR to separate date stamps in snapshot names.
Expand Down
110 changes: 110 additions & 0 deletions src/zfs-auto-snapshot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ opt_keep=''
opt_label=''
opt_prefix='zfs-auto-snap'
opt_recursive=''
opt_send_type=''
opt_send_host=''
opt_recv_pool=''
opt_send_opts=''
opt_recv_opts=''
opt_sep='_'
opt_setauto=''
opt_syslog=''
Expand Down Expand Up @@ -68,6 +73,8 @@ print_usage ()
-q, --quiet Suppress warnings and notices at the console.
--send-full=F Send zfs full backup. Unimplemented.
--send-incr=F Send zfs incremental backup. Unimplemented.
--send-opts=F Option(s) passed to 'zfs send'.
--recv-opts=F Option(s) passed to 'zfs receive'.
--sep=CHAR Use CHAR to separate date stamps in snapshot names.
-g, --syslog Write messages into the system log.
-r, --recursive Snapshot named filesystem and all descendants.
Expand Down Expand Up @@ -159,6 +166,8 @@ do_snapshots () # properties, flags, snapname, oldglob, [targets...]
# global WARNING_COUNT
# global SNAPSHOTS_OLD

SNAPS_DONE=''

for ii in $TARGETS
do
if [ -n "$opt_do_snapshots" ]
Expand All @@ -170,6 +179,8 @@ do_snapshots () # properties, flags, snapname, oldglob, [targets...]
if [ $RUNSNAP -eq 1 ] && do_run "zfs snapshot $PROPS $FLAGS '$ii@$NAME'"
then
[ "$opt_post_snapshot" != "" ] && do_run "$opt_post_snapshot $ii $NAME"
[ -n "$opt_send_host" ] && SNAPS_DONE="$SNAPS_DONE
$ii@$NAME"
SNAPSHOT_COUNT=$(( $SNAPSHOT_COUNT + 1 ))
else
WARNING_COUNT=$(( $WARNING_COUNT + 1 ))
Expand Down Expand Up @@ -203,6 +214,78 @@ do_snapshots () # properties, flags, snapname, oldglob, [targets...]
done
}

do_send () # snapname, oldglob
{
local NAME="$1"
local GLOB="$2"
local remote="ssh $opt_send_host zfs receive $opt_recv_opts $opt_recv_pool"
local ii

# STEP 1: Go throug all snapshots we've created
for ii in $SNAPS_DONE
do
opts=''
SNAPS_SEND=''

dset=${ii%@*}

# STEP 2: Go through ALL snapshots that exist, look for exact
# match on dataset/volume (with snapshot matching 'GLOB').
for jj in $SNAPSHOTS_OLD
do
# Check whether this is an old snapshot of the filesystem.
if [ -z "${jj#$dset@$GLOB}" ]; then
# We want the FIRST one (which is the last in time
# before the one we just created in do_snapshot()).
# Also, here we just need the snapshot name.
last_snap="${jj#*@}"
break
fi
done

# NOTE: If we don't have any previous snapshots (for example, we've
# just created the first one) we can end up with last_snap=''
# here.
# If we're called with '--send-incr' we have to options:
# 1: We change from incremental to full.
# 2: We accept that the user have said INCR, and stick with
# it.
if [ "$opt_send_type" = "incr" -a -z "$last_snap" ]; then
if [ -n "$opt_verbose" ]; then
echo "WARNING: No previous snapshots exist but we where called"
echo " with --send-incr. Can not continue."
echo " Please rerun with --send-full."
fi
return 1
fi

if [ -n "$opt_recursive" -a -n "$last_snap" ]; then
# STEP 3: Again, go through ALL snapshots that exists, but this
# time only look for the snapshots that 'starts with'
# the dataset/volume in question AND 'ends with'
# the exact snapshot name/date in step 2.
for jj in $SNAPSHOTS_OLD
do
if echo "$jj" | grep -qE "^$dset.*@$last_snap"; then
SNAPS_SEND="$SNAPS_SEND
$jj"
fi
done
else
SNAPS_SEND="$ii"
fi

# STEP 4: Go through all snapshots that is to be transfered and send them.
for jj in $SNAPS_SEND
do
if [ "$opt_send_type" = "incr" ]; then
do_run "zfs send $opt_send_opts -i $jj $ii | $remote"
else
do_run "zfs send $opt_send_opts -R $jj | $remote"
fi
done
done
}

# main ()
# {
Expand All @@ -212,6 +295,7 @@ GETOPT=$(getopt \
--longoptions=event:,keep:,label:,prefix:,sep: \
--longoptions=debug,help,quiet,syslog,verbose \
--longoptions=pre-snapshot:,post-snapshot:,destroy-only \
--longoptions=send-full:,send-incr:,send-opts:,recv-opts: \
--options=dnshe:l:k:p:rs:qgv \
-- "$@" ) \
|| exit 128
Expand Down Expand Up @@ -296,6 +380,30 @@ do
opt_recursive='1'
shift 1
;;
(--send-full)
opt_send_type='full'

opt_send_host=$(echo "$2" | sed 's,:.*,,')
opt_recv_pool=$(echo "$2" | sed 's,.*:,,')

opt_send_opts="$opt_send_opts -R"
shift 2
;;
(--send-incr)
opt_send_type='incr'

opt_send_host=$(echo "$2" | sed 's,:.*,,')
opt_recv_pool=$(echo "$2" | sed 's,.*:,,')
shift 2
;;
(--send-opts)
opt_send_opts="$2"
shift 2
;;
(--recv-opts)
opt_recv_opts="$2"
shift 2
;;
(--sep)
case "$2" in
([[:alnum:]_.:\ -])
Expand Down Expand Up @@ -567,6 +675,8 @@ test -n "$opt_dry_run" \
do_snapshots "$SNAPPROP" "" "$SNAPNAME" "$SNAPGLOB" "$TARGETS_REGULAR"
do_snapshots "$SNAPPROP" "-r" "$SNAPNAME" "$SNAPGLOB" "$TARGETS_RECURSIVE"

do_send "$SNAPNAME" "$SNAPGLOB"

print_log notice "@$SNAPNAME," \
"$SNAPSHOT_COUNT created," \
"$DESTRUCTION_COUNT destroyed," \
Expand Down

0 comments on commit df8667b

Please sign in to comment.