211 lines
5.5 KiB
Bash
Executable File
211 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
#######################################
|
|
# Configuration
|
|
#######################################
|
|
DBS=("sirh" "inventory" "ferme")
|
|
|
|
PGHOST="localhost"
|
|
PGPORT="5432"
|
|
PGUSER="backup_liot"
|
|
PGPASSWORD="backup_liot"
|
|
|
|
IA_SSH="malio-b@192.168.0.179"
|
|
IA_BASE_DIR="/home/malio-b/backups"
|
|
|
|
SSH_KEY="/home/malio/.ssh/id_ed25519_backup"
|
|
SSH_OPTS=(-i "$SSH_KEY" -o IdentitiesOnly=yes -o BatchMode=yes -o ConnectTimeout=10)
|
|
|
|
LOG_DIR="/var/log/pg_backup"
|
|
mkdir -p "$LOG_DIR"
|
|
|
|
TS="$(date +'%Y-%m-%d_%H-%M-%S')"
|
|
BACKUP_DIR_NAME="backup_${TS}"
|
|
LOG_FILE="${LOG_DIR}/${BACKUP_DIR_NAME}.log"
|
|
|
|
TMP_DIR="/tmp/pg_dump_${BACKUP_DIR_NAME}"
|
|
mkdir -p "$TMP_DIR"
|
|
|
|
exec > >(tee -a "$LOG_FILE") 2>&1
|
|
log() { echo "---- $(date +'%Y-%m-%d %H:%M:%S') ---- $*"; }
|
|
|
|
export PGPASSWORD
|
|
|
|
#######################################
|
|
# Discord (Webhook)
|
|
#######################################
|
|
DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/1478503102888935506/YCtJM09QZiKNMiCe5u7vCQb52VcLjHAd9wwEsKNltlJVcy7sKvoMTOJkvEKOOrk-Wpkh"
|
|
|
|
discord_ping() {
|
|
local details="${1:-}"
|
|
|
|
[[ -z "${DISCORD_WEBHOOK_URL:-}" ]] && return 0
|
|
|
|
local color dumps_display users_display
|
|
if [[ -n "${DUMPS_OK:-}" && -n "${USERS_OK:-}" ]]; then
|
|
color="🟢"
|
|
else
|
|
color="🔴"
|
|
fi
|
|
|
|
dumps_display=$([[ -n "${DUMPS_OK:-}" ]] && echo "✅" || echo "❌")
|
|
users_display=$([[ -n "${USERS_OK:-}" ]] && echo "✅" || echo "❌")
|
|
|
|
local msg="**@here BACKUP BDD RECETTE ${color}**\n"
|
|
msg+="Name: ${BACKUP_DIR_NAME}\n"
|
|
msg+="Dumps transfer: ${dumps_display}\n"
|
|
msg+="Users transfer: ${users_display}\n"
|
|
[[ -n "$details" ]] && msg+="Details: $details"
|
|
|
|
curl -fsS -H "Content-Type: application/json" \
|
|
-d "{\"content\":\"$msg\"}" \
|
|
"$DISCORD_WEBHOOK_URL" >/dev/null || true
|
|
}
|
|
|
|
#######################################
|
|
# Statuts init
|
|
#######################################
|
|
DUMPS_OK=true
|
|
USERS_OK=true
|
|
DUMP_ERRORS=""
|
|
USER_ERRORS=""
|
|
|
|
#######################################
|
|
# Lock (évite 2 backups en même temps)
|
|
#######################################
|
|
LOCK_DIR="/tmp/pg_multi_dump_stream.lock.d"
|
|
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
|
|
log "ERROR: Backup déjà en cours (lock: $LOCK_DIR)"
|
|
DUMPS_OK=
|
|
USERS_OK=
|
|
discord_ping "Lock exists: $LOCK_DIR"
|
|
exit 1
|
|
fi
|
|
trap 'rm -rf "$LOCK_DIR"' EXIT
|
|
|
|
#######################################
|
|
# Remote dir
|
|
#######################################
|
|
REMOTE_DIR="${IA_BASE_DIR}/${BACKUP_DIR_NAME}"
|
|
|
|
log "Starting backup process"
|
|
log "Remote directory: ${REMOTE_DIR}"
|
|
|
|
log "Creating remote directory"
|
|
if ! ssh "${SSH_OPTS[@]}" "$IA_SSH" "mkdir -p '${REMOTE_DIR}'"; then
|
|
log "ERROR: Création dossier distant impossible: ${REMOTE_DIR}"
|
|
DUMPS_OK=
|
|
USERS_OK=
|
|
discord_ping "Remote mkdir KO: ${REMOTE_DIR}"
|
|
exit 1
|
|
fi
|
|
|
|
#######################################
|
|
# Export PostgreSQL roles (no passwords)
|
|
#######################################
|
|
ROLES_FILE="${TMP_DIR}/roles_${TS}.sql"
|
|
log "Exporting PostgreSQL roles"
|
|
|
|
set +e
|
|
psql -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" -d postgres -Atq <<'SQL' > "$ROLES_FILE"
|
|
SELECT
|
|
format(
|
|
'DO $$ BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = %L) THEN
|
|
CREATE ROLE %I;
|
|
END IF;
|
|
END $$;',
|
|
rolname, rolname
|
|
)
|
|
FROM pg_roles
|
|
WHERE rolname !~ '^pg_'
|
|
ORDER BY rolname;
|
|
|
|
SELECT
|
|
format(
|
|
'ALTER ROLE %I WITH %s%s%s%s%s%s%s%s;',
|
|
rolname,
|
|
CASE WHEN rolsuper THEN 'SUPERUSER ' ELSE 'NOSUPERUSER ' END,
|
|
CASE WHEN rolinherit THEN 'INHERIT ' ELSE 'NOINHERIT ' END,
|
|
CASE WHEN rolcreaterole THEN 'CREATEROLE ' ELSE 'NOCREATEROLE ' END,
|
|
CASE WHEN rolcreatedb THEN 'CREATEDB ' ELSE 'NOCREATEDB ' END,
|
|
CASE WHEN rolcanlogin THEN 'LOGIN ' ELSE 'NOLOGIN ' END,
|
|
CASE WHEN rolreplication THEN 'REPLICATION ' ELSE 'NOREPLICATION ' END,
|
|
CASE WHEN rolbypassrls THEN 'BYPASSRLS ' ELSE 'NOBYPASSRLS ' END,
|
|
'CONNECTION LIMIT ' || rolconnlimit
|
|
)
|
|
FROM pg_roles
|
|
WHERE rolname !~ '^pg_'
|
|
ORDER BY rolname;
|
|
SQL
|
|
RET=$?
|
|
if [[ $RET -ne 0 ]]; then
|
|
USERS_OK=
|
|
USER_ERRORS+="roles_export "
|
|
log "ERROR: Users export failed"
|
|
else
|
|
log "Roles export completed: $ROLES_FILE"
|
|
fi
|
|
set -e
|
|
|
|
log "Sending roles file to IA server"
|
|
set +e
|
|
scp "${SSH_OPTS[@]}" "$ROLES_FILE" "$IA_SSH:${REMOTE_DIR}/"
|
|
RET=$?
|
|
if [[ $RET -ne 0 ]]; then
|
|
USERS_OK=
|
|
USER_ERRORS+="roles_scp "
|
|
log "ERROR: Users transfer failed (roles file)"
|
|
else
|
|
log "Roles transfer completed"
|
|
fi
|
|
set -e
|
|
|
|
#######################################
|
|
# Dump des bases + transfert (continue même si KO)
|
|
#######################################
|
|
set +e
|
|
for DB in "${DBS[@]}"; do
|
|
FILE="${TMP_DIR}/${DB}_${TS}.dump"
|
|
|
|
log "Dumping database: $DB"
|
|
pg_dump -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" -Fc --no-owner --no-acl -d "$DB" -f "$FILE"
|
|
RET=$?
|
|
if [[ $RET -ne 0 ]]; then
|
|
DUMPS_OK=
|
|
DUMP_ERRORS+="${DB} "
|
|
log "ERROR: Dump failed for $DB"
|
|
continue
|
|
fi
|
|
log "Dump completed: $FILE"
|
|
|
|
log "Sending dump to IA server"
|
|
scp "${SSH_OPTS[@]}" "$FILE" "$IA_SSH:${REMOTE_DIR}/"
|
|
RET=$?
|
|
if [[ $RET -ne 0 ]]; then
|
|
DUMPS_OK=
|
|
DUMP_ERRORS+="${DB}(scp) "
|
|
log "ERROR: Transfer failed for $DB"
|
|
continue
|
|
fi
|
|
log "Transfer completed for $DB"
|
|
done
|
|
set -e
|
|
|
|
#######################################
|
|
# Nettoyage
|
|
#######################################
|
|
log "Cleaning temporary files"
|
|
rm -rf "$TMP_DIR"
|
|
|
|
#######################################
|
|
# Envoi message Discord (final)
|
|
#######################################
|
|
DETAILS=""
|
|
[[ -z "${DUMPS_OK:-}" ]] && DETAILS+="Dumps KO: ${DUMP_ERRORS} "
|
|
[[ -z "${USERS_OK:-}" ]] && DETAILS+="Users KO: ${USER_ERRORS} "
|
|
discord_ping "$DETAILS"
|
|
|
|
log "Backup finished"
|