Inspired by:
See Also:
Inspired by:
See Also:
#!/usr/bin/env bash | |
set -euo pipefail | |
# dataset to backup | |
dataset="my-pool/data" | |
# destroy leftover snapshots, usually already cleaned up by | |
for snap in $(zfs list -rt snap -Ho name "${dataset}"); do | |
if [[ "${snap}" =~ @restic-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$ ]]; then | |
zfs destroy "${snap}" && echo "leftover zfs snapshot '${snap}' destroyed" | |
fi | |
done | |
# create temporary snapshot for backup | |
snapshot="restic-$(cat /proc/sys/kernel/random/uuid)" | |
zfs snap -r "${dataset}@$snapshot" | |
# clean up temporary snapshot | |
_clean() { | |
zfs destroy -r "${dataset}@$snapshot" && echo "zfs snapshot '${dataset}@$snapshot' destroyed" | |
} | |
trap _clean EXIT | |
# get snapshot mountpoints of (sub) datasets | |
restic_args=() | |
for ds in $(zfs list -r -Ho name "${dataset}"); do | |
if [[ "$(zfs get -Ho value mountpoint "$ds")" == "none" ]]; then | |
continue | |
fi | |
path=$(findmnt -nr -o target -S "$ds") | |
snap="${path}/.zfs/snapshot/$snapshot" | |
restic_args+=( "${snap}" ) | |
done | |
# backup temporary snapshot | |
restic backup \ | |
--exclude-caches \ | |
"${restic_args[@]}" |
#!/usr/bin/env bash | |
set -euo pipefail | |
# dataset to backup | |
export ZFS_DATASET="my-pool/data" | |
# destroy leftover snapshots, usually already cleaned up | |
if [ -z "${EXEC_UNSHARED:-}" ]; then | |
for snap in $(zfs list -rt snap -Ho name "${ZFS_DATASET}"); do | |
if [[ "${snap}" =~ @restic-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$ ]]; then | |
zfs destroy "${snap}" && echo "leftover zfs snapshot '${snap}' destroyed" | |
fi | |
done | |
fi | |
# create temporary snapshot for backup | |
if [[ -z "${ZFS_SNAP:-}" ]]; then | |
ZFS_SNAP="restic-$(cat /proc/sys/kernel/random/uuid)" | |
zfs snap -r "${ZFS_DATASET}@${ZFS_SNAP}" | |
# clean up temporary snapshot on exit | |
_clean_snap() { | |
zfs destroy -r "${ZFS_DATASET}@${ZFS_SNAP}" && echo "zfs snapshot '${ZFS_DATASET}@${ZFS_SNAP}' destroyed" | |
} | |
trap _clean_snap EXIT | |
export ZFS_SNAP | |
fi | |
# mount snapshot and backup within private mount namespace | |
if [ -z "${EXEC_UNSHARED:-}" ]; then | |
export EXEC_UNSHARED=1 | |
echo "re-executing '$0' in new private mount namespace.." | |
unshare --mount --propagation private "$0" | |
exit 0 | |
fi | |
# use tmpfs for further mountpoints | |
root_mnt="${TMPDIR:-/var/tmp}/zsnapmounts" | |
mount -t tmpfs -o X-mount.mkdir tmpfs "${root_mnt}" | |
# mount snapshot of (sub) datasets | |
snap_mnts=() | |
for ds in $(zfs list -r -Ho name "${ZFS_DATASET}"); do | |
if [[ "$(zfs get -Ho value mountpoint "$ds")" == "none" ]]; then | |
continue | |
fi | |
mount -t zfs -o X-mount.mkdir "$ds@${ZFS_SNAP}" "${root_mnt}/$ds" | |
snap_mnts+=( "$ds" ) | |
echo "mounted dataset '$ds@${ZFS_SNAP}'" | |
done | |
# backup temporary snapshot | |
echo -e "start restic backup\n" | |
pushd "${root_mnt}" > /dev/null | |
restic backup -v \ | |
--exclude-caches \ | |
"${snap_mnts[@]}" | |
echo -e "\nrestic backup done" |
@awehrfritz I wanted to strip away \var\tmp\zsnapmounts
from the path recognized by restic. There's a pushd
in line 59, so the paths passed to restic are relative.
There's a
pushd
in line 59, so the paths passed to restic are relative.
Arrrg, I missed that one. Good point, it’s nice to strip away the tmp path!
Thanks for clarifying!
Thanks for this script @stackcoder! I was wondering if line 49 is indeed correct, or if it should rather be
snap_mnts+=( "${root_mnt}/$ds" )
instead of
snap_mnts+=( "$ds" )
I might be missing something here though.