#!/bin/bash
#
# Nightly encrypted backup for every install on this server.
#
# One cron line instead of one per site. It finds the installs rather than
# being told about them, so a tenant added next month is backed up the same
# night without anyone remembering to edit a crontab.
#
# That last part is the whole reason this exists. ft-backup.sh was hardcoded to
# a single database, so every install after the first had no nightly backup at
# all. The only sign was the panel showing "Unknown, not reporting" on a card
# nobody reads until the day it matters.
#
# Install:
#   chmod 700 /root/ft-backup-all.sh /root/ft-backup.sh
#   openssl rand -base64 32 > /root/.backup-pass && chmod 600 /root/.backup-pass
#   # put that passphrase in your password manager. Without it none of these
#   # can be restored by anyone, including you.
#   0 3 * * * /root/ft-backup-all.sh >> /var/log/ft-backup.log 2>&1
#
# Dry run, lists what it would do and touches nothing:
#   APPLY=0 /root/ft-backup-all.sh
#
set -uo pipefail

APPLY="${APPLY:-1}"
BACKUP_SCRIPT="${BACKUP_SCRIPT:-/root/ft-backup.sh}"

# Installs that predate the <user>_db / <user>_app convention. Add a line here
# rather than renaming a live database.
# e.g.  [oldsite]="oldsite"
declare -A DB_USER_OVERRIDE=()

# Sites to leave alone. A scratch install does not need thirty days of
# encrypted history.
SKIP="paneltest"

echo "$(date '+%F %T') ── nightly backup sweep ──────────────────────────────"

[ -x "$BACKUP_SCRIPT" ] || { echo "  $BACKUP_SCRIPT missing or not executable"; exit 1; }

found=0; ran=0; failed=0

for manage in /home/*/public_html/backend/manage.py; do
    [ -f "$manage" ] || continue
    backend="$(dirname "$manage")"
    user="$(echo "$backend" | cut -d/ -f3)"
    found=$((found + 1))

    case " $SKIP " in *" $user "*)
        echo "  skip     $user"
        continue ;;
    esac

    db="${user}_db"
    if ! sudo -u postgres psql -lqt 2>/dev/null | cut -d'|' -f1 | grep -qw "$db"; then
        echo "  no db    $user  (expected $db)"
        continue
    fi

    if [ "$APPLY" != "1" ]; then
        echo "  would do $user  -> $db"
        continue
    fi

    echo "  backing up $user"
    if DB_USER="${DB_USER_OVERRIDE[$user]:-}" "$BACKUP_SCRIPT" "$user"; then
        ran=$((ran + 1))
    else
        echo "  FAILED   $user"
        failed=$((failed + 1))
    fi
done

echo "$(date '+%F %T') installs found $found, backed up $ran, failed $failed"

# A sweep that backs up nothing is a failure even though every command in it
# succeeded. Exit non-zero so cron mail and any monitor notice.
if [ "$APPLY" = "1" ] && [ "$ran" -eq 0 ]; then
    echo "  nothing was backed up. Check the paths and the database names."
    exit 1
fi
[ "$failed" -eq 0 ] || exit 1
exit 0
