backups
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
# {{ ansible_managed }}
|
||||
# Pull application data from the cloud hosts into hardlinked snapshots
|
||||
# rsnapshot-style: rsync --link-dest
|
||||
set -uo pipefail
|
||||
|
||||
ROOT={{ backup_root }}
|
||||
KEY={{ backup_key_path }}
|
||||
RETAIN={{ backup_retain_recent | default(14) }}
|
||||
RETAIN_MONTHLY={{ backup_retain_monthly | default(6) }}
|
||||
SSH="ssh -i $KEY -o StrictHostKeyChecking=accept-new -o BatchMode=yes"
|
||||
STAMP=$(date +%Y-%m-%d_%H%M)
|
||||
|
||||
exec 9> "$ROOT/.lock" || exit 1
|
||||
flock -n 9 || { echo "another backup run is active, aborting"; exit 1; }
|
||||
|
||||
overall_rc=0
|
||||
|
||||
{% raw %}
|
||||
prune() {
|
||||
local host_root=$1
|
||||
local -a snaps
|
||||
mapfile -t snaps < <(find "$host_root" -mindepth 1 -maxdepth 1 -type d -name '20*' | sort)
|
||||
((${#snaps[@]})) || return 0
|
||||
declare -A keep_set month_first
|
||||
# newest RETAIN snapshots
|
||||
local n=${#snaps[@]} start=0
|
||||
((n > RETAIN)) && start=$((n - RETAIN))
|
||||
for s in "${snaps[@]:$start}"; do keep_set[$s]=1; done
|
||||
# oldest snapshot of each month, for the RETAIN_MONTHLY most recent months
|
||||
for s in "${snaps[@]}"; do
|
||||
local m; m=$(basename "$s" | cut -c1-7)
|
||||
[[ -z ${month_first[$m]:-} ]] && month_first[$m]=$s
|
||||
done
|
||||
mapfile -t months < <(printf '%s\n' "${!month_first[@]}" | sort | tail -n "$RETAIN_MONTHLY")
|
||||
for m in "${months[@]}"; do keep_set[${month_first[$m]}]=1; done
|
||||
for s in "${snaps[@]}"; do
|
||||
if [[ -z ${keep_set[$s]:-} ]]; then
|
||||
echo "pruning $s"
|
||||
rm -rf "$s"
|
||||
fi
|
||||
done
|
||||
}
|
||||
{% endraw %}
|
||||
|
||||
{% for host in groups['backup_sources'] %}
|
||||
##### {{ host }} #####
|
||||
host={{ host }}
|
||||
addr={{ hostvars[host].ansible_host }}
|
||||
host_root=$ROOT/$host
|
||||
new=$host_root/incomplete
|
||||
mkdir -p "$host_root"
|
||||
rm -rf "$new"
|
||||
mkdir "$new"
|
||||
link_dest=()
|
||||
[[ -d $host_root/latest/. ]] && link_dest=(--link-dest="$host_root/latest/")
|
||||
host_rc=0
|
||||
{% for path in hostvars[host].backup_paths %}
|
||||
rsync -aR --numeric-ids --delete --delete-excluded \
|
||||
{% for ex in hostvars[host].backup_excludes | default([]) %}--exclude='{{ ex }}' {% endfor %}\
|
||||
-e "$SSH" "${link_dest[@]}" \
|
||||
"backup@$addr:{{ path }}" "$new/"
|
||||
rc=$?
|
||||
if ((rc != 0 && rc != 24)); then
|
||||
echo "ERROR: $host:{{ path }} failed with rsync exit $rc" >&2
|
||||
host_rc=1
|
||||
fi
|
||||
{% endfor %}
|
||||
if ((host_rc == 0)); then
|
||||
mv "$new" "$host_root/$STAMP"
|
||||
ln -sfn "$STAMP" "$host_root/latest"
|
||||
prune "$host_root"
|
||||
echo "$host: snapshot $STAMP complete"
|
||||
else
|
||||
echo "$host: snapshot FAILED, keeping previous 'latest'" >&2
|
||||
overall_rc=1
|
||||
fi
|
||||
|
||||
{% endfor %}
|
||||
exit $overall_rc
|
||||
Reference in New Issue
Block a user