From a41c0e09995c5d887ffbfd4e1cd15ceb8be52edd Mon Sep 17 00:00:00 2001 From: Chasqui Date: Fri, 9 Oct 2026 03:34:47 +0000 Subject: [PATCH] feat: add backup and restore support --- .env.sample | 3 ++ abra.sh | 2 ++ compose.yml | 14 ++++++++ pg_backup.sh | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100755 pg_backup.sh diff --git a/.env.sample b/.env.sample index 19d30be..42524ef 100644 --- a/.env.sample +++ b/.env.sample @@ -203,3 +203,6 @@ DEFAULT_LOCALE=en # OMNIAUTH_ONLY=true # ONE_CLICK_SSO_LOGIN=true # SECRET_OIDC_CLIENT_SECRET_VERSION=v1 + +# Backup Bot Two +ENABLE_BACKUPS=true diff --git a/abra.sh b/abra.sh index 28d631f..6345edb 100644 --- a/abra.sh +++ b/abra.sh @@ -150,3 +150,5 @@ secrets_activerecord() { rm -rf /tmp/activerecord.txt } + +export PG_BACKUP_VERSION=v1 diff --git a/compose.yml b/compose.yml index 95f19df..9ecf334 100644 --- a/compose.yml +++ b/compose.yml @@ -21,6 +21,8 @@ services: - "traefik.http.routers.${STACK_NAME}_web.entrypoints=web-secure" - "traefik.http.routers.${STACK_NAME}_web.tls.certresolver=${LETS_ENCRYPT_ENV}" - "coop-cloud.${STACK_NAME}.version=3.0.9+v4.5.20" + - "backupbot.backup=${ENABLE_BACKUPS:-true}" + - "backupbot.backup.volumes.redis=false" configs: &configs - source: entrypoint_sh target: /usr/local/bin/entrypoint.sh @@ -169,6 +171,15 @@ services: - internal volumes: - postgres:/var/lib/postgresql + configs: + - source: pg_backup + target: /pg_backup.sh + mode: 0555 + deploy: + labels: + - "backupbot.backup.pre-hook=/pg_backup.sh backup" + - "backupbot.backup.volumes.postgres.path=backup.sql" + - "backupbot.restore.post-hook=/pg_backup.sh restore" secrets: - db_password @@ -222,6 +233,9 @@ networks: external: true configs: + pg_backup: + name: ${STACK_NAME}_pg_backup_${PG_BACKUP_VERSION} + file: pg_backup.sh entrypoint_sh: name: ${STACK_NAME}_entrypoint_conf_${ENTRYPOINT_CONF_VERSION} file: entrypoint.sh.tmpl diff --git a/pg_backup.sh b/pg_backup.sh new file mode 100755 index 0000000..7d446b4 --- /dev/null +++ b/pg_backup.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +set -Eeuo pipefail + +BACKUP_FILE="/var/lib/postgresql/backup.sql" +TMP_BACKUP_FILE="${BACKUP_FILE}.tmp" + +export PGPASSWORD="$(cat "$POSTGRES_PASSWORD_FILE")" + +backup() { + rm -f "$TMP_BACKUP_FILE" + + pg_dump \ + -U "$POSTGRES_USER" \ + "$POSTGRES_DB" \ + > "$TMP_BACKUP_FILE" + + mv "$TMP_BACKUP_FILE" "$BACKUP_FILE" + chmod 600 "$BACKUP_FILE" +} + +restore() { + [ -s "$BACKUP_FILE" ] || exit 1 + + HBA_FILE="$( + psql \ + -U "$POSTGRES_USER" \ + -d postgres \ + -Atc "SHOW hba_file;" + )" + + HBA_BACKUP="$(mktemp /tmp/pg_hba.backupbot.XXXXXX)" + + restore_hba() { + if [ -f "$HBA_BACKUP" ]; then + cat "$HBA_BACKUP" > "$HBA_FILE" + + psql \ + -U "$POSTGRES_USER" \ + -d postgres \ + -c "SELECT pg_reload_conf();" \ + >/dev/null + + rm -f "$HBA_BACKUP" + fi + } + + cp "$HBA_FILE" "$HBA_BACKUP" + + trap restore_hba EXIT INT TERM + + printf 'local all all trust\n' > "$HBA_FILE" + + psql \ + -U "$POSTGRES_USER" \ + -d postgres \ + -c "SELECT pg_reload_conf();" \ + >/dev/null + + dropdb \ + --force \ + -U "$POSTGRES_USER" \ + "$POSTGRES_DB" + + createdb \ + -U "$POSTGRES_USER" \ + "$POSTGRES_DB" + + psql \ + -v ON_ERROR_STOP=1 \ + -U "$POSTGRES_USER" \ + -d "$POSTGRES_DB" \ + -1 \ + -f "$BACKUP_FILE" + + trap - EXIT INT TERM + restore_hba +} + +case "${1:-}" in + backup) + backup + ;; + restore) + restore + ;; + *) + exit 1 + ;; +esac