Implements the two decoupled backup streams from docs/06 as an idempotent
Ansible role wired into the host playbook:
- Files: sanoid takes/prunes ZFS snapshots per policy (sanoid_datasets) on
its packaged timer; syncoid replicates offsite (heleos-zfs-offsite),
enabled only when zfs_offsite_target is set.
- DB: heleos-db-backup (nightly systemd timer) walks the deployments dir and
dumps each DB-backed site via `docker exec mariadb-dump` into
db-backups/<customer>/<site>/{daily,weekly,monthly} with rotation
(automysqlbackup-style, adapted for the containerized DB; MYSQL_PWD keeps
the password out of the process list). heleos-db-offsite rsyncs offsite
when db_offsite_target is set.
Streams and schedules are configured in group_vars/all.yml; offsite is
opt-in via the two target vars. Updates doc 06 (implementation note), the
ansible README, and CLAUDE.md status. YAML + templates validated by render.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
51 lines
2 KiB
Django/Jinja
Executable file
51 lines
2 KiB
Django/Jinja
Executable file
#!/usr/bin/env bash
|
|
# heleos per-database dumps — automysqlbackup-style rotation, adapted for the
|
|
# containerized shared MariaDB. Managed by Ansible. Iterates the deployments dir
|
|
# (source of truth) and dumps each DB-backed site into
|
|
# db-backups/<customer>/<site>/{daily,weekly,monthly}.
|
|
set -euo pipefail
|
|
|
|
CONTAINER="{{ mariadb_container }}"
|
|
BASE="{{ db_backup_dir }}"
|
|
DEPLOYMENTS="{{ deployments_dir }}"
|
|
KEEP_DAILY={{ db_backup_keep_daily }}
|
|
KEEP_WEEKLY={{ db_backup_keep_weekly }}
|
|
KEEP_MONTHLY={{ db_backup_keep_monthly }}
|
|
|
|
# Root password: env var wins, else read from the mariadb stack .env.
|
|
ROOTPW="${MARIADB_ROOT_PASSWORD:-}"
|
|
if [ -z "$ROOTPW" ] && [ -f "{{ mariadb_env_file }}" ]; then
|
|
ROOTPW="$(grep -E '^MARIADB_ROOT_PASSWORD=' "{{ mariadb_env_file }}" | cut -d= -f2-)"
|
|
fi
|
|
if [ -z "$ROOTPW" ]; then
|
|
echo "no MariaDB root password (env or {{ mariadb_env_file }})" >&2
|
|
exit 1
|
|
fi
|
|
|
|
dow="$(date +%u)" # 7 = Sunday
|
|
dom="$(date +%d)" # 01 = first of month
|
|
ts="$(date +%Y%m%d-%H%M%S)"
|
|
|
|
shopt -s nullglob
|
|
for meta in "$DEPLOYMENTS"/*/*/site.yaml; do
|
|
d="$(dirname "$meta")"
|
|
site="$(basename "$d")"
|
|
customer="$(basename "$(dirname "$d")")"
|
|
grep -qiE '^database:[[:space:]]*true' "$meta" || continue
|
|
|
|
db="db_${customer//-/_}_${site//-/_}"
|
|
dest="$BASE/$customer/$site"
|
|
mkdir -p "$dest/daily" "$dest/weekly" "$dest/monthly"
|
|
|
|
out="$dest/daily/${db}-${ts}.sql.gz"
|
|
# MYSQL_PWD keeps the password out of the container's process list.
|
|
docker exec -e MYSQL_PWD="$ROOTPW" "$CONTAINER" \
|
|
mariadb-dump --single-transaction --databases "$db" -uroot | gzip > "$out"
|
|
|
|
[ "$dow" = "7" ] && cp -f "$out" "$dest/weekly/"
|
|
[ "$dom" = "01" ] && cp -f "$out" "$dest/monthly/"
|
|
|
|
find "$dest/daily" -name '*.sql.gz' -type f -mtime +"$KEEP_DAILY" -delete
|
|
find "$dest/weekly" -name '*.sql.gz' -type f -mtime +"$(( KEEP_WEEKLY * 7 ))" -delete
|
|
find "$dest/monthly" -name '*.sql.gz' -type f -mtime +"$(( KEEP_MONTHLY * 31 ))" -delete
|
|
done
|