diff --git a/backup.sh b/backup.sh index 173f238..5a5cdd2 100755 --- a/backup.sh +++ b/backup.sh @@ -2,123 +2,160 @@ nodes_file="nodes.txt" ### nodes.txt -# -# -# +# +# +# # ... datasets_file="datasets.txt" ### datasets.txt # -# / -# / -# / +# # # ... -list_active_datasets() +if [ ! -f $nodes_file ]; then echo "No nodes specified."; exit 2; fi +if [ ! -f $datasets_file ]; then echo "No datasets specified."; exit 3; fi + +ZFS_SEND_OPTS="-R" +ZFS_SNAPSHOT_OPTS="-r" +ZFS_RECV_OPTS="-svu" + +read LOCAL_HOST LOCAL_USER LOCAL_PORT LOCAL_TZ SEND_COMPRESSED < $nodes_file +case $SEND_COMPRESSED in + [tTyY]*) ZFS_SEND_OPTS="$ZFS_SEND_OPTS -c" ;; +esac + +ORIGIN_PERMS="send,snapshot,hold" +MIRROR_PERMS="compression,mountpoint,receive,create,mount" + +GRAPH_DATASETS_RAW=`cat $datasets_file` +GRAPH_DATASETS=`for dataset in $GRAPH_DATASETS_RAW; do + case $dataset in + \#*) continue;; + esac + echo -n "$dataset " +done` + +list_datasets() { - zfs list | tail -n +2 | cut -d' ' -f1|grep ${BG_ROOT} + for dataset in $GRAPH_DATASETS; do + zfs list -H $dataset + done } -# compare_datasets() - -create_datasets() { - # should compare_datasets and only create missing or possibly error. - - for dataset in `cat ${datasets_file}`; do - case $dataset in - \#*) continue;; - esac +list_remote_datasets() { + while read addr user ssh_port zroot; do + echo "=== $user@$addr $zroot ===" if [ $BG_TEST_MODE = "TRUE" ]; then - echo zfs create -p ${BG_ROOT}/$dataset - else - zfs create -p ${BG_ROOT}/$dataset + echo ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr\ + "sh -c 'for dataset in $GRAPH_DATASETS; + do zfs list -H $zroot/\$dataset; + done'" + else + ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \ + "sh -c 'for dataset in $GRAPH_DATASETS; + do zfs list -H $zroot/\$dataset; + done';" fi - done + done < sendnodes.tmp } get_latest_snapshot() { - zfs list -t snapshot | - grep ${BG_ROOT} | - tail -n1 | - cut -d'@' -f2 | - cut -d' ' -f 1 + zfs list -t snapshot $dataset | tail -n1 | cut -d'@' -f2 | cut -d' ' -f 1 } -setup_aggregator() +get_latest_remote_snapshot() { - create_datasets - if [ $BG_TEST_MODE = "TRUE" ]; then - echo zfs allow -u ${BG_USER} send,snapshot,hold ${BG_ROOT} - else - zfs allow -u ${BG_USER} send,snapshot,hold ${BG_ROOT} - fi + ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \ + "zfs list -t snapshot $zroot/$dataset | + tail -n1|cut -d'@' -f2|cut -d' ' -f 1" } -setup_mirror() +zfs_allow_origin() { - if [ $BG_TEST_MODE = "TRUE" ]; then - echo zfs allow -u ${BG_USER} send,snapshot,hold ${BG_ROOT} - echo zfs allow -u ${BG_USER} \ - compression,mountpoint,receive,create,mount ${BG_ROOT} - else - zfs allow -u ${BG_USER} send,snapshot,hold ${BG_ROOT} - zfs allow -u ${BG_USER} \ - compression,mountpoint,receive,create,mount ${BG_ROOT} - fi -} - -create_snapshot() -{ - id="`date -I`-`date +%s`" - if [ $BG_TEST_MODE = "TRUE" ]; then - echo zfs snapshot -r ${BG_ROOT}@${id} - else - zfs snapshot -r ${BG_ROOT}@${id} - fi -} - -send_single_snapshot() -{ - BG_NEW_SNAPSHOT=`get_latest_snapshot` - tail -n +2 ${nodes_file} > sendnodes.tmp - while read BG_REMOTE_ADDR BG_REMOTE_PORT BG_REMOTE_ROOT BG_REMOTE_USER; do - case $BG_REMOTE_ADDR in - \#*) continue;; - esac + for dataset in $GRAPH_DATASETS; do if [ $BG_TEST_MODE = "TRUE" ]; then - echo zfs send -R ${BG_ROOT}@${BG_NEW_SNAPSHOT} - echo ssh -i ~/.ssh/id_rsa -o port=${BG_REMOTE_PORT} \ - ${BG_REMOTE_USER}@${BG_REMOTE_ADDR} \ - zfs receive -sdvu ${BG_REMOTE_ROOT} + echo zfs allow -u $LOCAL_USER $ORIGIN_PERMS $dataset else - zfs send -R ${BG_ROOT}@${BG_NEW_SNAPSHOT} | - ssh -i ~/.ssh/id_rsa -o port=${BG_REMOTE_PORT} \ - ${BG_REMOTE_USER}@${BG_REMOTE_ADDR} \ - zfs receive -sdvu ${BG_REMOTE_ROOT} + zfs allow -u $LOCAL_USER $ORIGIN_PERMS $dataset + fi + done +} + +zfs_allow_mirrors() +{ + while read addr user ssh_port zroot; do + echo "=== $user@$addr $zroot ===" + if [ $BG_TEST_MODE = "TRUE" ]; then + echo ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \ + "for dataset in $GRAPH_DATASETS; do + zfs allow -u $user $MIRROR_PERMS $zroot/\$dataset + done" + else + ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \ + "for dataset in $GRAPH_DATASETS; do + zfs allow -u $user $MIRROR_PERMS $zroot/\$dataset + done" fi done < sendnodes.tmp - rm sendnodes.tmp - if [ $BG_TEST_MODE = "TRUE" ]; then - : - else - echo $BG_NEW_SNAPSHOT > "old-snapshot.txt" - fi } -send_incremental_snapshot() +create_snapshots() { - BG_NEW_SNAPSHOT=`get_latest_snapshot` - echo Will send $BG_NEW_SNAPSHOT - #while read BG_REMOTE_ADDR BG_REMOTE_PORT BG_REMOTE_ROOT BG_REMOTE_USER; do - # zfs send -R -i `cat old-snapshot.txt` ${BG_ROOT}@${BG_NEW_SNAPSHOT} | - # ssh -i ~/.ssh/id_rsa -o port=${BG_REMOTE_PORT} \ - # ${BG_REMOTE_USER}@${BG_REMOTE_ADDR} \ - # zfs receive -sdvu ${BG_REMOTE_ROOT}@${BG_NEW_SNAPSHOT} - #done - echo $BG_NEW_SNAPSHOT > "old-snapshot.txt" + snapshot_id="`date -I`-`date +%s`-$LOCAL_TZ" + for dataset in $GRAPH_DATASETS; do + if [ $BG_TEST_MODE = "TRUE" ]; then + echo zfs snapshot $ZFS_SNAPSHOT_OPTS $dataset@$snapshot_id + else + zfs snapshot $ZFS_SNAPSHOT_OPTS $dataset@$snapshot_id + fi + done +} + +send_latest() +{ + while read addr user ssh_port zroot; do + echo "=== $user@$addr $zroot ===" + for dataset in $GRAPH_DATASETS; do + origin_snapshot=`get_latest_snapshot $dataset` + if [ $BG_TEST_MODE = "TRUE" ]; then + echo zfs send $ZFS_SEND_OPTS $dataset@$origin_snapshot \| \ + ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \ + zfs recv $ZFS_RECV_OPTS $zroot/$dataset + else + zfs send $ZFS_SEND_OPTS $dataset@$origin_snapshot | + ssh -i ~/.ssh/id_rsa -o port=$ssh_port \ + $user@$addr \ + zfs recv $ZFS_RECV_OPTS $zroot/$dataset + fi + done + done < sendnodes.tmp +} + +send_increment() +{ + while read addr user ssh_port zroot; do + echo "=== $user@$addr $zroot ===" + for dataset in $GRAPH_DATASETS; do + origin_snapshot=`get_latest_snapshot` + remote_snapshot=`get_latest_remote_snapshot` + if [ $BG_TEST_MODE = "TRUE" ]; then + echo zfs send $ZFS_SEND_OPTS \ + -i $dataset@$remote_snapshot \ + $dataset@$origin_snapshot \| \ + ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \ + zfs recv $ZFS_RECV_OPTS $zroot/$dataset + else + zfs send $ZFS_SEND_OPTS \ + -i $dataset@$remote_snapshot \ + $dataset@$origin_snapshot | + ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \ + zfs recv $ZFS_RECV_OPTS $zroot/$dataset + fi + done + done < sendnodes.tmp } @@ -141,21 +178,18 @@ while :; do shift done -read BG_HOST BG_PORT BG_ROOT BG_USER < ${nodes_file} - -if [ ! -f ${nodes_file} ]; then echo "No nodes specified."; exit 2; fi +tail -n +2 $nodes_file|grep -v '^#' > sendnodes.tmp ### Command case "$1" in - list) list_active_datasets ;; - create) create_snapshot ;; - setup-mirror) setup_mirror ;; - setup-aggregator) setup_aggregator ;; - send) - if [ -f "old-snapshot.txt" ]; then - send_incremental_snapshot - else - send_single_snapshot - fi - ;; + list) list_datasets ;; + list-remote) list_remote_datasets ;; + snapshot) create_snapshots ;; + configure-mirrors) zfs_allow_mirrors ;; + configure-origin) zfs_allow_origin ;; + mirror-reset) send_latest ;; + mirror-increment) send_increment ;; + #mirror-prune) send_increment_with_F ;; esac + +rm sendnodes.tmp \ No newline at end of file