Import postgresql plugin
This commit is contained in:
Executable
+226
@@ -0,0 +1,226 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# postgres_backup.sh
|
||||
# Backup wszystkich baz PostgreSQL na serwerze
|
||||
#
|
||||
# Przeznaczenie: cron (nie interaktywny)
|
||||
# Wymagania: pg_dump, psql, dostęp do pliku poświadczeń (format pgpass)
|
||||
#
|
||||
# Przywracanie pojedynczej bazy:
|
||||
# psql -h localhost -U postgres -d postgres -f nazwa_bazy.sql
|
||||
# gunzip -c nazwa_bazy.sql.gz | psql -h localhost -U postgres -d postgres
|
||||
# =============================================================================
|
||||
|
||||
# =============================================================================
|
||||
# KONFIGURACJA
|
||||
# =============================================================================
|
||||
|
||||
BASE_DIR="/home/admin/postgres_backup"
|
||||
|
||||
# Format daty katalogu backupu (składnia date +FORMAT)
|
||||
DATE_FORMAT="%d-%m-%Y"
|
||||
|
||||
# 1 = dodaj godzinę i minuty do nazwy katalogu (np. 19-02-2026_14-35)
|
||||
ADD_TIME=0
|
||||
|
||||
# Liczba dni przechowywania backupów (0 = bez automatycznego usuwania)
|
||||
RETENTION=7
|
||||
|
||||
# 1 = kompresuj do .sql.gz | 0 = zostawiaj jako .sql
|
||||
ENABLE_COMPRESSION=1
|
||||
|
||||
# Plik poświadczeń w formacie pgpass: host:port:database:user:password
|
||||
# Musi mieć uprawnienia 600 lub 400
|
||||
CREDENTIALS_FILE="/usr/local/directadmin/conf/postgresql.conf"
|
||||
|
||||
# Bazy wykluczone z backupu (oddzielone spacją)
|
||||
EXCLUDE_DBS="template0 template1"
|
||||
|
||||
# =============================================================================
|
||||
# WEWNĘTRZNA KONFIGURACJA – nie zmieniaj
|
||||
# =============================================================================
|
||||
|
||||
LOCK_FILE="/var/run/postgres_backup.lock"
|
||||
LOG_FILE="/var/log/postgres_backup.log"
|
||||
|
||||
# =============================================================================
|
||||
# INICJALIZACJA
|
||||
# =============================================================================
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
# Kolory tylko na terminalu
|
||||
if [[ -t 1 ]]; then
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
||||
else
|
||||
RED=''; GREEN=''; YELLOW=''; NC=''
|
||||
fi
|
||||
|
||||
ts() { date '+%Y-%m-%d %H:%M:%S'; }
|
||||
log() { echo "[$(ts)] $*" | tee -a "$LOG_FILE"; }
|
||||
ok() { echo -e "${GREEN}[OK]${NC} [$(ts)] $*" | tee -a "$LOG_FILE"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} [$(ts)] $*" | tee -a "$LOG_FILE"; }
|
||||
die() { echo -e "${RED}[BŁĄD]${NC} [$(ts)] $*" | tee -a "$LOG_FILE" >&2; cleanup; exit 1; }
|
||||
|
||||
cleanup() { rm -f "$LOCK_FILE"; }
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Blokada przed równoległym uruchomieniem
|
||||
# ---------------------------------------------------------------------------
|
||||
if [[ -f "$LOCK_FILE" ]]; then
|
||||
OLD_PID=$(cat "$LOCK_FILE" 2>/dev/null || echo "")
|
||||
if [[ -n "$OLD_PID" ]] && kill -0 "$OLD_PID" 2>/dev/null; then
|
||||
die "Backup jest już uruchomiony (PID: ${OLD_PID}). Przerywam."
|
||||
fi
|
||||
warn "Stały plik blokady (PID ${OLD_PID} nie istnieje) – usuwam i kontynuuję."
|
||||
rm -f "$LOCK_FILE"
|
||||
fi
|
||||
echo $$ > "$LOCK_FILE"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Weryfikacja pliku poświadczeń
|
||||
# ---------------------------------------------------------------------------
|
||||
[[ -f "$CREDENTIALS_FILE" ]] \
|
||||
|| die "Brak pliku poświadczeń: ${CREDENTIALS_FILE}"
|
||||
|
||||
_perms=$(stat -c '%a' "$CREDENTIALS_FILE")
|
||||
[[ "$_perms" == "600" || "$_perms" == "400" ]] \
|
||||
|| die "Plik ${CREDENTIALS_FILE} ma zbyt otwarte uprawnienia (${_perms}). Wymagane: 600 lub 400."
|
||||
|
||||
# Parsowanie: host:port:database:user:password
|
||||
_line=$(head -1 "$CREDENTIALS_FILE")
|
||||
PGHOST=$(echo "$_line" | cut -d: -f1)
|
||||
PGPORT=$(echo "$_line" | cut -d: -f2)
|
||||
PGUSER=$(echo "$_line" | cut -d: -f4)
|
||||
|
||||
[[ -n "$PGHOST" && -n "$PGPORT" && -n "$PGUSER" ]] \
|
||||
|| die "Nieprawidłowy format pliku poświadczeń. Oczekiwany: host:port:database:user:password"
|
||||
|
||||
# Hasło przekazywane przez PGPASSFILE – nie pojawia się w środowisku ani linii poleceń
|
||||
export PGPASSFILE="$CREDENTIALS_FILE"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Katalog backupu
|
||||
# ---------------------------------------------------------------------------
|
||||
if [[ "$ADD_TIME" == "1" ]]; then
|
||||
DATE_STR=$(date +"${DATE_FORMAT}_%H-%M")
|
||||
else
|
||||
DATE_STR=$(date +"${DATE_FORMAT}")
|
||||
fi
|
||||
|
||||
BACKUP_DIR="${BASE_DIR}/${DATE_STR}"
|
||||
mkdir -p "$BACKUP_DIR" || die "Nie można utworzyć katalogu backupu: ${BACKUP_DIR}"
|
||||
|
||||
# =============================================================================
|
||||
# BACKUP
|
||||
# =============================================================================
|
||||
|
||||
log "================================================================="
|
||||
log "Rozpoczęcie backupu PostgreSQL"
|
||||
log "Host: ${PGHOST}:${PGPORT} Użytkownik: ${PGUSER}"
|
||||
log "Katalog: ${BACKUP_DIR}"
|
||||
log "Kompresja: ${ENABLE_COMPRESSION} Retencja: ${RETENTION} dni"
|
||||
log "================================================================="
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Globals: użytkownicy, role, hasła, przynależności (pg_dumpall --globals-only)
|
||||
# Wymagane do pełnego disaster recovery – przywróć jako pierwsze
|
||||
# ---------------------------------------------------------------------------
|
||||
ERRORS=0
|
||||
BACKED_UP=0
|
||||
GLOBALS_SUCCESS=true
|
||||
|
||||
if [[ "$ENABLE_COMPRESSION" == "1" ]]; then
|
||||
GLOBALS_FILE="${BACKUP_DIR}/_globals.sql.gz"
|
||||
pg_dumpall \
|
||||
-h "$PGHOST" -p "$PGPORT" -U "$PGUSER" \
|
||||
--no-password --globals-only --clean --if-exists \
|
||||
2>>"$LOG_FILE" \
|
||||
| gzip -9 > "$GLOBALS_FILE" \
|
||||
|| GLOBALS_SUCCESS=false
|
||||
else
|
||||
GLOBALS_FILE="${BACKUP_DIR}/_globals.sql"
|
||||
pg_dumpall \
|
||||
-h "$PGHOST" -p "$PGPORT" -U "$PGUSER" \
|
||||
--no-password --globals-only --clean --if-exists \
|
||||
> "$GLOBALS_FILE" 2>>"$LOG_FILE" \
|
||||
|| GLOBALS_SUCCESS=false
|
||||
fi
|
||||
|
||||
if [[ "$GLOBALS_SUCCESS" == "true" ]]; then
|
||||
SIZE=$(du -sh "$GLOBALS_FILE" 2>/dev/null | cut -f1)
|
||||
ok "_globals → ${GLOBALS_FILE##*/} (${SIZE})"
|
||||
else
|
||||
warn "_globals: backup ról i użytkowników nie powiódł się – plik usunięty."
|
||||
rm -f "$GLOBALS_FILE"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
# Lista baz danych
|
||||
DATABASES=$(
|
||||
psql -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" \
|
||||
--no-password -t -A \
|
||||
-c "SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname;" \
|
||||
2>>"$LOG_FILE"
|
||||
) || die "Nie można pobrać listy baz. Sprawdź połączenie i poświadczenia."
|
||||
|
||||
# Zbuduj wzorzec wykluczeń
|
||||
EXCLUDE_PATTERN=$(echo "$EXCLUDE_DBS" | tr ' ' '|')
|
||||
|
||||
for DB in $DATABASES; do
|
||||
# Pomiń wykluczone
|
||||
if echo "$DB" | grep -qE "^(${EXCLUDE_PATTERN})$"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
SUCCESS=true
|
||||
|
||||
if [[ "$ENABLE_COMPRESSION" == "1" ]]; then
|
||||
OUT_FILE="${BACKUP_DIR}/${DB}.sql.gz"
|
||||
pg_dump \
|
||||
-h "$PGHOST" -p "$PGPORT" -U "$PGUSER" \
|
||||
--no-password --create --clean --if-exists \
|
||||
-F p "$DB" 2>>"$LOG_FILE" \
|
||||
| gzip -9 > "$OUT_FILE" \
|
||||
|| SUCCESS=false
|
||||
else
|
||||
OUT_FILE="${BACKUP_DIR}/${DB}.sql"
|
||||
pg_dump \
|
||||
-h "$PGHOST" -p "$PGPORT" -U "$PGUSER" \
|
||||
--no-password --create --clean --if-exists \
|
||||
-F p "$DB" > "$OUT_FILE" 2>>"$LOG_FILE" \
|
||||
|| SUCCESS=false
|
||||
fi
|
||||
|
||||
if [[ "$SUCCESS" == "true" ]]; then
|
||||
SIZE=$(du -sh "$OUT_FILE" 2>/dev/null | cut -f1)
|
||||
ok "${DB} → ${OUT_FILE##*/} (${SIZE})"
|
||||
BACKED_UP=$((BACKED_UP + 1))
|
||||
else
|
||||
warn "${DB}: backup nie powiódł się – plik usunięty."
|
||||
rm -f "$OUT_FILE"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
log "Wynik: ${BACKED_UP} OK, ${ERRORS} błędów."
|
||||
|
||||
# =============================================================================
|
||||
# RETENCJA
|
||||
# =============================================================================
|
||||
|
||||
if [[ "$RETENTION" -gt 0 ]]; then
|
||||
log "Usuwanie backupów starszych niż ${RETENTION} dni..."
|
||||
find "$BASE_DIR" -maxdepth 1 -mindepth 1 -type d -mtime +"$RETENTION" \
|
||||
-exec rm -rf {} + 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# ZAKOŃCZENIE
|
||||
# =============================================================================
|
||||
|
||||
log "Backup zakończony."
|
||||
|
||||
[[ "$ERRORS" -eq 0 ]] || exit 1
|
||||
exit 0
|
||||
Reference in New Issue
Block a user