notebookvb

This commit is contained in:
Administrator
2026-05-23 09:38:53 +02:00
parent 13065aab94
commit 916ab42bcc
13 changed files with 1085 additions and 194 deletions
+108 -34
View File
@@ -1,68 +1,142 @@
# PostgreSQL Backup - Tower
PostgreSQL 18 (Docker: `postgresql18`) na Tower (192.168.1.76).
Dva samostatné PostgreSQL Docker kontejnery na Tower (192.168.1.76).
## Konfigurace
---
## Instance 1 — postgresql18 (hlavní)
| Parametr | Hodnota |
|----------|---------|
| Server | Tower (192.168.1.76) |
| Container | `postgresql18` |
| Port | 5432 |
| Docker kontejner | `postgresql18` |
| Image | `postgres:18` |
| Port | `5432` (host) → `5432` (container) |
| User | `vladimir.buzalka` |
| Metoda | `pg_dumpall` (všechny DB najednou) |
| Záloha | `/mnt/user/Backup/Critical/PostgreSQLBackup/tower/YYYY-MM-DD_HHMM/` |
| Password | `Vlado7309208104++` |
| Data path (Unraid) | `/mnt/user/appdata/postgresql18` |
| Obsah | Hlavní aplikační databáze |
| Záloha | `/mnt/user/Backup/Critical/PostgreSQLBackup/tower/YYYY-MM-DD_HHMM/all_databases.sql.gz` |
| Retence | 7 dní / posledních 7 záloh |
| User Script (Unraid) | `PostgreSQLBackup` |
| Skript | `postgresqlbackup_with_gzip.sh` |
| První test | 2026-05-23 06:59:51 → 07:03:12 (cca 3 min), dump **3.3 GB** |
---
## Instance 2 — PostgreSQL_Immich (Immich)
| Parametr | Hodnota |
|----------|---------|
| Docker kontejner | `PostgreSQL_Immich` |
| Image | `tensorchord/pgvecto-rs:pg16-v0.2.0` (PG 16 + pgvecto-rs extension) |
| Port | `5433` (host) → `5432` (container) |
| User | `postgres` |
| Password | `postgres` |
| DB | `immich` |
| Data path (Unraid) | `/mnt/user/appdata/PostgreSQL_Immich` |
| Obsah | Metadata Immich (fotky, alba, uživatelé) — bez samotných fotek |
| Záloha | `/mnt/user/Backup/Critical/PostgreSQLImmichBackup/tower/YYYY-MM-DD_HHMM/immich_all.sql.gz` |
| Retence | 7 dní / posledních 7 záloh |
| User Script (Unraid) | `PostgreSQLImmichBackup` |
| Skript | `postgresqlimmichbackup_with_gzip.sh` |
| První test | 2026-05-23 07:25:31 → 07:25:49 (18 sekund), dump **52 MB** |
> **Poznámka:** `pgvecto-rs` je specializovaná extension pro vektorové vyhledávání (používá Immich pro AI similarity search). Dump obsahuje i extension definice, takže restore vyžaduje stejný image (`tensorchord/pgvecto-rs`), ne čistý `postgres`.
---
## Skripty
### `postgresqlbackup_with_gzip.sh`
Provede `pg_dumpall` všech databází, rolí a tablespaces. Výstup je komprimovaný gzip soubor `all_databases.sql.gz`.
| Soubor | Popis |
|--------|-------|
| `postgresqlbackup_with_gzip.sh` | Backup postgresql18 (pg_dumpall → gzip) |
| `postgresqlimmichbackup_with_gzip.sh` | Backup PostgreSQL_Immich (pg_dumpall → gzip) |
| `postgresqlrestore_from_backup.sh` | Restore postgresql18 z nejnovější / zadané zálohy |
| `verify_backup_integrity.sh` | Ověření DB, tabulek, indexů, rolí po restore |
### Backup (spuštění ručně na Tower)
```bash
bash postgresqlbackup_with_gzip.sh
bash /boot/config/plugins/user.scripts/scripts/PostgreSQLBackup/script
bash /boot/config/plugins/user.scripts/scripts/PostgreSQLImmichBackup/script
```
Výsledná struktura:
```
/mnt/user/Backup/Critical/PostgreSQLBackup/tower/
└── 2026-05-23_0200/
└── all_databases.sql.gz
```
### `postgresqlrestore_from_backup.sh`
Obnoví všechny databáze z nejnovější zálohy (nebo ze zadané cesty).
### Restore postgresql18 (nejnovější záloha)
```bash
# Nejnovější záloha (automaticky)
bash postgresqlrestore_from_backup.sh
# Konkrétní záloha
bash postgresqlrestore_from_backup.sh /mnt/user/Backup/Critical/PostgreSQLBackup/tower/2026-05-23_0200
```
> **POZOR:** Dump obsahuje `--clean --if-exists`, takže restore přepíše existující data.
### Restore postgresql18 (konkrétní záloha)
### `verify_backup_integrity.sh`
Ověří po restore že jsou všechny DB, tabulky, indexy a role přítomny a funkční.
```bash
bash postgresqlrestore_from_backup.sh /mnt/user/Backup/Critical/PostgreSQLBackup/tower/2026-05-23_0659
```
> **POZOR:** Dump je vytvořen s `--clean --if-exists` → restore dropne a znovu vytvoří všechny objekty. Existující data budou přepsána.
### Verify po restore
```bash
bash verify_backup_integrity.sh
```
## Nastavení Unraid User Script
---
Na Tower přidat User Script `POSTGRESQL_BACKUP`:
## Metoda zálohy
```bash
#!/bin/bash
bash /boot/config/plugins/user.scripts/scripts/POSTGRESQL_BACKUP/postgresqlbackup_with_gzip.sh
- **pg_dumpall** — jeden soubor obsahující všechny DB, role, tablespaces, grants, extensions
- Streamuje přes `stdout | gzip` přímo na disk → žádný dočasný soubor uvnitř kontejneru
- Restore: `gunzip -c file.sql.gz | psql`
- Validace: EXIT_CODE z `${PIPESTATUS[0]}` + kontrola velikosti souboru + prázdný .err soubor
---
## Struktura záloh na disku
```
/mnt/user/Backup/Critical/
├── PostgreSQLBackup/
│ └── tower/
│ └── 2026-05-23_0659/
│ └── all_databases.sql.gz (3.3 GB)
└── PostgreSQLImmichBackup/
└── tower/
└── 2026-05-23_0725/
└── immich_all.sql.gz (52 MB)
```
Schedule: **Daily**
## Windows přístup k zálohám
### Windows přístup
```
\\tower\Backup\Critical\PostgreSQLBackup\
\\tower\Backup\Critical\PostgreSQLImmichBackup\
```
---
## Unraid User Scripts (Tower)
Skripty jsou nasazeny v:
```
/boot/config/plugins/user.scripts/scripts/PostgreSQLBackup/
/boot/config/plugins/user.scripts/scripts/PostgreSQLImmichBackup/
```
Nastavit schedule: **Settings → User Scripts → Daily**
---
## SSH přístup na Tower (z Windows/Python)
Heslo pro SSH se liší od ostatních hesel!
```python
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("192.168.1.76", username="root", password="7309208104",
look_for_keys=False, allow_agent=False)
```
> Standardní `ssh root@192.168.1.76` z Windows selže kvůli "Too many authentication failures" (nabízí klíče před heslem). Použít `look_for_keys=False, allow_agent=False`.
+77 -27
View File
@@ -1,24 +1,60 @@
#!/bin/bash
# ==============================================================================
# PostgreSQLBackup — záloha PostgreSQL 18 (hlavní instance) na Tower
# ==============================================================================
#
# CO DĚLÁ:
# Zálohuje celý PostgreSQL 18 server pomocí pg_dumpall — jeden SQL soubor
# obsahuje všechny databáze, role, tablespaces a grants. Výstup je komprimován
# gzip přímo ve streamu (bez mezičlánku na disku).
#
# TECHNICKÉ DETAILY:
# - pg_dumpall: záloha celého serveru (ne jen jedné DB) — zahrnuje i role/uživatele
# - --clean --if-exists: generuje DROP příkazy před CREATE (bezpečný re-restore)
# - Stream přes stdout: docker exec → pipe → gzip → soubor na hostiteli
# → žádný volume mount, žádná dočasná kopie uvnitř kontejneru
# - ${PIPESTATUS[0]}: exit kód pg_dumpall (ne gzip) — gzip by jinak maskoval chybu
# - PGPASSWORD: předáváme jako env var do kontejneru přes -e (ne jako argument)
#
# SCHEDULE:
# Unraid User Script "PostgreSQLBackup" — daily (4:40 ráno)
#
# STRUKTURA ZÁLOHY:
# /mnt/user/Backup/Critical/PostgreSQLBackup/tower/
# YYYY-MM-DD_HHMM/
# all_databases.sql.gz ← komprimovaný pg_dumpall výstup
# all_databases.err ← dočasný soubor chyb (smazán při úspěchu)
#
# VELIKOST / ČAS:
# Dump: ~3.3 GB, záloha trvá ~3 minuty
#
# ROTACE:
# Dvoustupňová — nejprve dle stáří (KEEP_DAYS), pak oříznutí na KEEP_COUNT.
#
# RESTORE:
# Viz postgresqlrestore_from_backup.sh
# gunzip -c all_databases.sql.gz | docker exec -i postgresql18 psql ...
# ==============================================================================
set -x
# ==========================================================
# CONFIGURATION
# ==========================================================
CONTAINER_NAME="postgresql18"
PG_HOST="localhost"
PG_PORT="5432"
PG_USER="vladimir.buzalka"
export PGPASSWORD="Vlado7309208104++"
# ==============================================================================
# KONFIGURACE
# ==============================================================================
CONTAINER_NAME="postgresql18" # Docker kontejner s PostgreSQL 18
PG_HOST="localhost" # uvnitř kontejneru
PG_PORT="5432" # výchozí PG port
PG_USER="vladimir.buzalka" # superuser s právy pro pg_dumpall
export PGPASSWORD="Vlado7309208104++" # heslo jako env var (pg_dumpall čte PGPASSWORD)
UNRAID_NAME="tower"
BASE_PATH="/mnt/user/Backup/Critical/PostgreSQLBackup"
KEEP_DAYS=7
KEEP_COUNT=7 # počet posledních záloh k udržení (mimo time-based)
KEEP_DAYS=7 # zálohy starší než 7 dní se smažou v prvním průchodu
KEEP_COUNT=7 # z toho co zbyde, ponech vždy alespoň 7 záloh
# ==========================================================
# ==============================================================================
# START
# ==========================================================
# ==============================================================================
echo "Starting PostgreSQL full backup (pg_dumpall)"
START_TS=$(date '+%Y-%m-%d %H:%M:%S')
@@ -26,14 +62,19 @@ DATE=$(date +%Y-%m-%d_%H%M)
FINAL_PATH="$BASE_PATH/$UNRAID_NAME/$DATE"
mkdir -p "$FINAL_PATH"
DUMP_FILE="$FINAL_PATH/all_databases.sql.gz"
ERR_FILE="$FINAL_PATH/all_databases.err"
DUMP_FILE="$FINAL_PATH/all_databases.sql.gz" # výsledný komprimovaný dump
ERR_FILE="$FINAL_PATH/all_databases.err" # stderr pg_dumpall
# ==========================================================
# ==============================================================================
# DUMP + GZIP
# pg_dumpall zachovává: všechny DB, role, tablespaces, grants
# Streamuje přes stdout, nepotřebuje volume mount
# ==========================================================
# docker exec spustí pg_dumpall uvnitř kontejneru.
# -e PGPASSWORD: předá heslo jako env var do kontejneru (bez -e by pg_dumpall
# nemohl autentizovat a skončil by promptem na stdin).
# Pipe na gzip: komprimuje stream v reálném čase — na disku nikdy není
# nekomprimovaný dump (úspora místa a I/O).
# > "$DUMP_FILE": výstup gzip jde do souboru na hostiteli.
# 2> "$ERR_FILE": stderr pg_dumpall (warnings, errory) jde do .err souboru.
# ==============================================================================
docker exec \
-e PGPASSWORD="$PGPASSWORD" \
"$CONTAINER_NAME" \
@@ -45,11 +86,17 @@ docker exec \
--if-exists \
| gzip > "$DUMP_FILE" 2> "$ERR_FILE"
# PIPESTATUS[0] = exit kód prvního příkazu v pipe (pg_dumpall).
# Prostý $? by vrátil exit kód gzip — i když pg_dumpall selže, gzip může skončit 0.
EXIT_CODE=${PIPESTATUS[0]}
# ==========================================================
# VALIDATION
# ==========================================================
# ==============================================================================
# VALIDACE
# Tři podmínky pro úspěch:
# 1. EXIT_CODE=0 — pg_dumpall skončil bez chyby
# 2. -s "$DUMP_FILE" — soubor existuje a není prázdný
# 3. ! -s "$ERR_FILE" — žádné chybové hlášky (prázdný .err)
# ==============================================================================
if [ $EXIT_CODE -eq 0 ] && [ -s "$DUMP_FILE" ] && [ ! -s "$ERR_FILE" ]; then
echo "SUCCESS: Full PostgreSQL backup completed"
echo "Dump size: $(du -h "$DUMP_FILE" | cut -f1)"
@@ -63,17 +110,20 @@ else
[ -s "$ERR_FILE" ] && cat "$ERR_FILE" || echo " (no stderr output)"
fi
# ==========================================================
# CLEANUP OLD BACKUPS
# 1. Smaž zálohy starší než KEEP_DAYS dnů
# 2. Z toho co zbyde, ponech jen posledních KEEP_COUNT
# ==========================================================
# ==============================================================================
# ROTACE STARÝCH ZÁLOH — dvoustupňová
#
# Krok 1: Smaž adresáře starší než KEEP_DAYS dní.
# -mindepth/-maxdepth 1: jen přímé podadresáře (ne rekurzivně)
#
# Krok 2: Z toho co zbyde, ponech jen posledních KEEP_COUNT.
# Důvod dvou kroků: i při přerušeném schedule garantuje min. KEEP_COUNT záloh.
# ==============================================================================
echo "Cleaning up old backups..."
find "$BASE_PATH/$UNRAID_NAME" \
-mindepth 1 -maxdepth 1 -type d -mtime +$KEEP_DAYS \
-exec rm -rf {} \;
# Nech jen posledních KEEP_COUNT záloh
ls -td "$BASE_PATH/$UNRAID_NAME"/*/ 2>/dev/null \
| tail -n +$((KEEP_COUNT + 1)) \
| xargs -r rm -rf
@@ -0,0 +1,125 @@
#!/bin/bash
# ==============================================================================
# PostgreSQLImmichBackup — záloha PostgreSQL Immich instance na Tower
# ==============================================================================
#
# CO DĚLÁ:
# Zálohuje celý PostgreSQL server pro Immich (foto server) pomocí pg_dumpall.
# Stejný princip jako hlavní PostgreSQL záloha, ale jiný kontejner a přihlašovací údaje.
#
# DŮLEŽITÉ — SPECIÁLNÍ IMAGE:
# PostgreSQL_Immich běží na nestandardním image tensorchord/pgvecto-rs:pg16-v0.2.0,
# který obsahuje pgvecto-rs extension pro vektorové operace (embedding fotek).
# Při RESTORE je NUTNÉ použít stejný image — standardní postgres:16 nebude fungovat,
# protože dump obsahuje CREATE EXTENSION pro pgvecto-rs.
#
# TECHNICKÉ DETAILY:
# - Kontejner: PostgreSQL_Immich (port 5433 na hostiteli → 5432 uvnitř)
# - pg_dumpall: záloha celého serveru incl. role, extensions (pgvecto-rs), grants
# - --clean --if-exists: DROP + CREATE = idempotentní restore
# - Stream přes stdout → pipe → gzip → soubor na hostiteli
# - ${PIPESTATUS[0]}: exit kód pg_dumpall (gzip by jinak maskoval chybu)
#
# SCHEDULE:
# Unraid User Script "PostgreSQLImmichBackup" — daily (4:40 ráno)
#
# STRUKTURA ZÁLOHY:
# /mnt/user/Backup/Critical/PostgreSQLImmichBackup/tower/
# YYYY-MM-DD_HHMM/
# immich_all.sql.gz ← komprimovaný pg_dumpall výstup
# immich_all.err ← dočasný soubor chyb (smazán při úspěchu)
#
# VELIKOST / ČAS:
# Dump: ~52 MB, záloha trvá ~18 sekund
#
# ROTACE:
# Dvoustupňová — nejprve dle stáří (KEEP_DAYS), pak oříznutí na KEEP_COUNT.
#
# RESTORE POSTUP:
# 1. Ujisti se, že běží správný image (tensorchord/pgvecto-rs:pg16-v0.2.0)
# 2. gunzip -c immich_all.sql.gz | docker exec -i PostgreSQL_Immich psql -U postgres postgres
# 3. Restartuj Immich kontejner
# ==============================================================================
set -x
# ==============================================================================
# KONFIGURACE
# ==============================================================================
CONTAINER_NAME="PostgreSQL_Immich" # Docker kontejner s PG pro Immich (jiný než postgresql18!)
PG_HOST="localhost" # uvnitř kontejneru
PG_PORT="5432" # port uvnitř kontejneru (na hostiteli je 5433)
PG_USER="postgres" # výchozí postgres superuser
export PGPASSWORD="postgres" # jednoduché heslo (interní kontejner, není exponován)
UNRAID_NAME="tower"
BASE_PATH="/mnt/user/Backup/Critical/PostgreSQLImmichBackup"
KEEP_DAYS=7 # zálohy starší než 7 dní se smažou
KEEP_COUNT=7 # vždy ponech alespoň 7 záloh
# ==============================================================================
# START
# ==============================================================================
echo "Starting PostgreSQL Immich full backup (pg_dumpall)"
START_TS=$(date '+%Y-%m-%d %H:%M:%S')
DATE=$(date +%Y-%m-%d_%H%M)
FINAL_PATH="$BASE_PATH/$UNRAID_NAME/$DATE"
mkdir -p "$FINAL_PATH"
DUMP_FILE="$FINAL_PATH/immich_all.sql.gz" # výsledný komprimovaný dump
ERR_FILE="$FINAL_PATH/immich_all.err" # stderr pg_dumpall
# ==============================================================================
# DUMP + GZIP
# Stejný princip jako u hlavního PostgreSQL:
# docker exec → pg_dumpall (stdout) → gzip → soubor na hostiteli
# PGPASSWORD předáváme jako -e env var do kontejneru.
# Uvnitř kontejneru pg_dumpall komunikuje přes localhost:5432 (interní port).
# ==============================================================================
docker exec \
-e PGPASSWORD="$PGPASSWORD" \
"$CONTAINER_NAME" \
pg_dumpall \
--host="$PG_HOST" \
--port="$PG_PORT" \
--username="$PG_USER" \
--clean \
--if-exists \
| gzip > "$DUMP_FILE" 2> "$ERR_FILE"
# PIPESTATUS[0] = exit kód pg_dumpall (ne gzip)
EXIT_CODE=${PIPESTATUS[0]}
# ==============================================================================
# VALIDACE
# ==============================================================================
if [ $EXIT_CODE -eq 0 ] && [ -s "$DUMP_FILE" ] && [ ! -s "$ERR_FILE" ]; then
echo "SUCCESS: Immich PostgreSQL backup completed"
echo "Dump size: $(du -h "$DUMP_FILE" | cut -f1)"
rm -f "$ERR_FILE"
else
echo "ERROR: Backup failed"
echo "Exit code: $EXIT_CODE"
echo "Dump file:"
ls -lh "$DUMP_FILE" 2>/dev/null || echo " (not created)"
echo "Error output:"
[ -s "$ERR_FILE" ] && cat "$ERR_FILE" || echo " (no stderr output)"
fi
# ==============================================================================
# ROTACE STARÝCH ZÁLOH — dvoustupňová (viz postgresqlbackup_with_gzip.sh)
# ==============================================================================
echo "Cleaning up old backups..."
find "$BASE_PATH/$UNRAID_NAME" \
-mindepth 1 -maxdepth 1 -type d -mtime +$KEEP_DAYS \
-exec rm -rf {} \;
ls -td "$BASE_PATH/$UNRAID_NAME"/*/ 2>/dev/null \
| tail -n +$((KEEP_COUNT + 1)) \
| xargs -r rm -rf
echo "------------------------------------------"
echo "Backup task completed at $(date)"
echo "Started at: $START_TS"
set +x
@@ -1,27 +1,56 @@
#!/bin/bash
# ==============================================================================
# PostgreSQLRestore — obnovení PostgreSQL 18 ze zálohy
# ==============================================================================
#
# CO DĚLÁ:
# Obnoví celý PostgreSQL 18 server z pg_dumpall zálohy.
# Pokud není zadán konkrétní adresář, automaticky najde nejnovější zálohu.
#
# POUŽITÍ:
# bash postgresqlrestore_from_backup.sh [cesta_k_záloze]
#
# Bez argumentu — použije nejnovější zálohu:
# bash postgresqlrestore_from_backup.sh
#
# S konkrétním adresářem:
# bash postgresqlrestore_from_backup.sh /mnt/user/Backup/Critical/PostgreSQLBackup/tower/2026-05-23_0440
#
# TECHNICKÉ DETAILY:
# - gunzip -c: dekomprimuje na stdout (nezahazuje archiv)
# - pipe → docker exec -i psql: stream SQL příkazů do PostgreSQL
# - --dbname=postgres: psql se musí připojit k existující DB (postgres je vždy)
# - --clean + --if-exists v dumpu: DROP objekty před jejich vytvoření
# - ${PIPESTATUS[1]}: exit kód psql (ne gunzip)
#
# POZOR:
# Restore přepíše všechna stávající data! Spouštět vědomě, ne automaticky.
# Chybové hlášky jako "role already exists" jsou normální — dump je idempotentní.
# ==============================================================================
set -x
# ==========================================================
# CONFIGURATION
# ==========================================================
# ==============================================================================
# KONFIGURACE
# ==============================================================================
CONTAINER_NAME="postgresql18"
PG_HOST="localhost"
PG_PORT="5432"
PG_USER="vladimir.buzalka"
export PGPASSWORD="Vlado7309208104++"
# Cesta k záloze kterou chceš obnovit
# Lze předat jako argument, nebo nechá najít nejnovější
# Např: $0 /mnt/user/Backup/Critical/PostgreSQLBackup/tower/2026-05-23_0200
# Volitelný argument — konkrétní adresář zálohy.
# Pokud není zadán, skript sám najde nejnovější.
BACKUP_DIR="$1"
BASE_PATH="/mnt/user/Backup/Critical/PostgreSQLBackup/tower"
# ==========================================================
# FIND BACKUP
# ==========================================================
# ==============================================================================
# NALEZENÍ ZÁLOHY
# ==============================================================================
if [ -z "$BACKUP_DIR" ]; then
echo "No backup path specified - using latest available backup"
# ls -td: seřadit adresáře dle mtime, nejnovější první
# head -1: vzít jen nejnovější
BACKUP_DIR=$(ls -td "$BASE_PATH"/*/ 2>/dev/null | head -1)
if [ -z "$BACKUP_DIR" ]; then
@@ -49,11 +78,15 @@ START_TS=$(date '+%Y-%m-%d %H:%M:%S')
ERR_FILE="$BACKUP_DIR/all_databases.restore.err"
# ==========================================================
# ==============================================================================
# RESTORE
# pg_dumpall dump se obnovuje přes psql
# --clean + --if-exists v dumpu zajišťuje drop před recreate
# ==========================================================
# gunzip -c: dekomprimuje all_databases.sql.gz na stdout (soubor zůstane)
# pipe → docker exec -i psql: SQL streamed přímo do PostgreSQL
# -i: nutné pro stdin stream (bez -i by psql nedostával vstup)
# --dbname=postgres: psql se musí připojit k nějaké DB — postgres vždy existuje
# Záloha obsahuje příkazy pro všechny DB, role a grants — psql je postupně vykoná.
# 2> "$ERR_FILE": stderr psql (chyby, warnings) — "role already exists" je normální
# ==============================================================================
echo "Restoring all databases to PostgreSQL..."
gunzip -c "$BACKUP_FILE" \
| docker exec -i \
@@ -66,11 +99,12 @@ gunzip -c "$BACKUP_FILE" \
--dbname="postgres" \
2> "$ERR_FILE"
# PIPESTATUS[1] = exit kód docker exec / psql (index 1 = druhý prvek pipe)
RESTORE_EXIT=${PIPESTATUS[1]}
# ==========================================================
# VALIDATION
# ==========================================================
# ==============================================================================
# VALIDACE
# ==============================================================================
if [ $RESTORE_EXIT -eq 0 ]; then
echo "SUCCESS: All databases restored successfully"
rm -f "$ERR_FILE"
+65 -24
View File
@@ -1,12 +1,28 @@
#!/bin/bash
# ==============================================================================
# PostgreSQL Verify Backup Integrity — ověření konzistence po restore
# ==============================================================================
#
# CO DĚLÁ:
# Připojí se k PostgreSQL 18 a pro každou databázi zkontroluje:
# 1. Konektivitu k serveru
# 2. Seznam všech databází
# 3. Pro každou DB: počet tabulek, počty řádků, velikosti, počet indexů
# 4. PostgreSQL role a uživatele
#
# KDY POUŽÍT:
# Po provedení postgresqlrestore_from_backup.sh — ověří, že data jsou v pořádku.
# Spouštět ručně, není součástí automatizovaného schedule.
#
# VÝSTUP:
# OK / ERROR indikátory, tabulky se statistikami.
# Skript vrátí exit code 1 pokud cokoliv selže.
# ==============================================================================
set -x
# ==========================================================
# VERIFY BACKUP INTEGRITY
# Kontroluje že se všechny DB, tabulky a data
# správně obnovily po restore
# ==========================================================
# ==============================================================================
# KONFIGURACE
# ==============================================================================
CONTAINER_NAME="postgresql18"
PG_HOST="localhost"
PG_PORT="5432"
@@ -18,9 +34,11 @@ echo "=========================================="
ALL_OK=true
# ==========================================================
# 1. CONNECTIVITY CHECK
# ==========================================================
# ==============================================================================
# 1. KONEKTIVITA
# Jednoduchý SELECT 'connected' — pokud selže, PostgreSQL není dostupný
# a nemá smysl pokračovat.
# ==============================================================================
echo ""
echo "Checking PostgreSQL connectivity..."
docker exec \
@@ -40,9 +58,12 @@ if [ $? -ne 0 ]; then
fi
echo "OK: Connected to PostgreSQL"
# ==========================================================
# 2. LIST ALL DATABASES
# ==========================================================
# ==============================================================================
# 2. SEZNAM DATABÁZÍ
# pg_database: systémová tabulka s metadaty databází.
# datistemplate=false: vynechá šablonové DB (template0, template1).
# Výsledek jde nejdřív na stdout (pro přehled), pak do proměnné pro iteraci.
# ==============================================================================
echo ""
echo "Databases present:"
docker exec \
@@ -56,7 +77,8 @@ docker exec \
--tuples-only \
--command="SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname;"
# Ulož seznam DB do proměnné pro iteraci
# Znovu spustíme dotaz pro iteraci — ukládáme do proměnné.
# tr -d ' ': odstraní bílé znaky z výstupu psql (odsazení sloupce).
DATABASES=$(docker exec \
-e PGPASSWORD="$PGPASSWORD" \
"$CONTAINER_NAME" \
@@ -69,17 +91,21 @@ DATABASES=$(docker exec \
--command="SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname;" \
| tr -d ' ')
# ==========================================================
# 3. PER-DATABASE CHECKS
# ==========================================================
# ==============================================================================
# 3. KONTROLA KAŽDÉ DATABÁZE
# ==============================================================================
for DB_NAME in $DATABASES; do
[ -z "$DB_NAME" ] && continue
[ -z "$DB_NAME" ] && continue # přeskoč prázdné řádky z výstupu psql
echo ""
echo "Verifying database: $DB_NAME"
echo "------------------------------------------"
# Počet tabulek
# --------------------------------------------------------------------------
# Počet tabulek v public schema
# information_schema.tables: standardní SQL pohled, table_schema='public'
# filtruje jen uživatelské tabulky (ne systémové views).
# --------------------------------------------------------------------------
TABLE_COUNT=$(docker exec \
-e PGPASSWORD="$PGPASSWORD" \
"$CONTAINER_NAME" \
@@ -94,7 +120,12 @@ for DB_NAME in $DATABASES; do
echo "OK: Tables in public schema: $TABLE_COUNT"
# Seznam tabulek s počtem řádků
# --------------------------------------------------------------------------
# Tabulky s počtem řádků a velikostí
# pg_stat_user_tables: statistiky o uživatelských tabulkách (live tuples, dead tuples).
# n_live_tup: odhadovaný počet živých řádků (ANALYZE musí být aktuální).
# pg_total_relation_size: celková velikost incl. indexy a TOAST.
# --------------------------------------------------------------------------
echo " Table row counts:"
docker exec \
-e PGPASSWORD="$PGPASSWORD" \
@@ -113,7 +144,11 @@ SELECT
FROM pg_stat_user_tables
ORDER BY relname;"
# Počet indexů
# --------------------------------------------------------------------------
# Počet indexů v public schema
# pg_indexes: systémový katalog indexů. Slouží jako ověření, že
# pg_dumpall správně obnovil i CREATE INDEX příkazy (ne jen data).
# --------------------------------------------------------------------------
INDEX_COUNT=$(docker exec \
-e PGPASSWORD="$PGPASSWORD" \
"$CONTAINER_NAME" \
@@ -128,7 +163,10 @@ ORDER BY relname;"
echo "OK: Indexes in public schema: $INDEX_COUNT"
# Celková velikost DB
# --------------------------------------------------------------------------
# Celková velikost databáze
# pg_database_size: vrátí velikost v bytech, pg_size_pretty ji naformátuje.
# --------------------------------------------------------------------------
DB_SIZE=$(docker exec \
-e PGPASSWORD="$PGPASSWORD" \
"$CONTAINER_NAME" \
@@ -145,9 +183,12 @@ ORDER BY relname;"
done
# ==========================================================
# 4. CHECK ROLES / USERS
# ==========================================================
# ==============================================================================
# 4. ROLE A UŽIVATELÉ
# pg_roles: systémový katalog všech rolí.
# Filtrujeme pryč built-in pg_* role (pg_monitor, pg_read_all_settings, atd.)
# aby výstup byl přehledný — zajímají nás jen uživatelské role.
# ==============================================================================
echo ""
echo "PostgreSQL roles:"
docker exec \