diff --git a/bundles/zfs-mirror/files/zfs-mirror b/bundles/zfs-mirror/files/zfs-mirror new file mode 100644 index 0000000..3908d9a --- /dev/null +++ b/bundles/zfs-mirror/files/zfs-mirror @@ -0,0 +1,43 @@ +#!/bin/bash + +set -exu + +ssh="ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@${server_ip}" +bookmark_prefix="auto-mirror_" +new_bookmark="$bookmark_prefix$(date +"%Y-%m-%d_%H:%M:%S")" + +for dataset in $(zfs list -t filesystem -H -o name) +do + echo "MIRRORING $dataset" + + if ! $ssh sudo zfs list -t filesystem -H -o name | grep -q "^$dataset$" + then + echo "CREATING PARENT DATASET..." + $ssh sudo zfs create -p -o mountpoint=none "$dataset" + fi + + zfs snap "$dataset@$new_bookmark" + + if zfs list -t bookmark -H -o name | grep "^$dataset#$bookmark_prefix" | wc -l | grep -q "^0$" + then + echo "INITIAL BACKUP" + # do in subshell, otherwise ctr+c will lead to 0 exitcode + $(zfs send -v "$dataset@$new_bookmark" | $ssh sudo zfs recv -F "$dataset" -o mountpoint=none) + else + echo "INCREMENTAL BACKUP" + last_bookmark=$(zfs list -t bookmark -H -o name | grep "^$dataset#$bookmark_prefix" | sort | tail -1 | cut -d '#' -f 2) + [[ -z "$last_bookmark" ]] && echo "ERROR - last_bookmark is empty" && exit 98 + $(zfs send -v -i "#$last_bookmark" "$dataset@$new_bookmark" | $ssh sudo zfs recv "$dataset" -o mountpoint=none) + fi + + if [[ "$?" == "0" ]] + then + zfs bookmark "$dataset@$new_bookmark" "$dataset#$new_bookmark" + zfs destroy "$dataset@$new_bookmark" + echo "SUCCESS $dataset" + else + zfs destroy "$dataset@$new_bookmark" + echo "ERROR $dataset" + exit 99 + fi +done diff --git a/bundles/zfs-mirror/items.py b/bundles/zfs-mirror/items.py new file mode 100644 index 0000000..de3c61a --- /dev/null +++ b/bundles/zfs-mirror/items.py @@ -0,0 +1,13 @@ +from ipaddress import ip_interface + +files = { + '/opt/zfs-mirror': { + 'mode': '550', + 'content_type': 'mako', + 'context': { + 'server_ip': ip_interface( + repo.get_node(node.metadata.get('zfs-mirror/server')).metadata.get('network/internal/ipv4') + ).ip, + }, + } +} diff --git a/bundles/zfs-mirror/metadata.py b/bundles/zfs-mirror/metadata.py new file mode 100644 index 0000000..ccb93b2 --- /dev/null +++ b/bundles/zfs-mirror/metadata.py @@ -0,0 +1,8 @@ +defaults = { + 'systemd-timers': { + 'zfs-mirror': { + 'command': '/opt/zfs-mirror', + 'when': 'daily', + }, + }, +} diff --git a/nodes/home.backups.py b/nodes/home.backups.py index ffe982d..5bd8af5 100644 --- a/nodes/home.backups.py +++ b/nodes/home.backups.py @@ -7,6 +7,7 @@ ], 'bundles': [ 'zfs', + 'zfs-mirror', ], 'metadata': { 'id': '9cf52515-63a1-4659-a8ec-6c3c881727e5', @@ -20,6 +21,9 @@ 'backup-server': { 'hostname': 'backups.sublimity.de', }, + 'zfs-mirror': { + 'server': 'wb.offsite-backups', + }, 'zfs': { 'pools': { 'tank': { diff --git a/nodes/home.server.py b/nodes/home.server.py index aa0946a..0b28065 100644 --- a/nodes/home.server.py +++ b/nodes/home.server.py @@ -65,6 +65,7 @@ '10.0.10.0/24', '10.0.11.0/24', '10.0.20.0/24', + '192.168.178.0/24', ], }, }, diff --git a/nodes/wb.offsite-backups.py b/nodes/wb.offsite-backups.py index c02ca40..0d6a3a4 100644 --- a/nodes/wb.offsite-backups.py +++ b/nodes/wb.offsite-backups.py @@ -35,6 +35,13 @@ }, }, }, + 'users': { + 'root': { + 'authorized_users': { + 'root@home.backups', + }, + }, + }, 'zfs': { 'pools': { 'tank': {