platform/platform-infra/ansible/roles/backup/templates/heleos-db-backup.sh.j2
Bart Van Geyt 0ade1c740f Phase 5: backup/DR automation (backup Ansible role)
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>
2026-07-07 18:04:41 +02:00

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