chore(sonarr): add migration script and cleanup script for Sonarr
This commit is contained in:
Executable
+58
@@ -0,0 +1,58 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# ==============================================================================
|
||||||
|
# Opruimen van oude standalone Sonarr installatie op vmserver (10.2.0.4)
|
||||||
|
# ==============================================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
CLUSTER_HOST="10.2.0.4"
|
||||||
|
SSH_USER="bart"
|
||||||
|
|
||||||
|
COLOR_GREEN="\033[0;32m"
|
||||||
|
COLOR_YELLOW="\033[1;33m"
|
||||||
|
COLOR_RED="\033[0;31m"
|
||||||
|
COLOR_BLUE="\033[0;34m"
|
||||||
|
COLOR_RESET="\033[0m"
|
||||||
|
|
||||||
|
log_info() { echo -e "${COLOR_GREEN}[INFO]${COLOR_RESET} $1"; }
|
||||||
|
log_step() { echo -e "\n${COLOR_BLUE}==>${COLOR_RESET} ${COLOR_GREEN}$1${COLOR_RESET}"; }
|
||||||
|
log_warn() { echo -e "${COLOR_YELLOW}[WARN]${COLOR_RESET} $1"; }
|
||||||
|
|
||||||
|
echo "========================================================================"
|
||||||
|
echo " OPRUIMEN OUDE STANDALONE SONARR OP $CLUSTER_HOST"
|
||||||
|
echo "========================================================================"
|
||||||
|
echo "Dit stopt en verwijdert de oude standalone bestanden op $CLUSTER_HOST:"
|
||||||
|
echo " - /etc/systemd/system/sonarr.service"
|
||||||
|
echo " - /opt/Sonarr"
|
||||||
|
echo " - /storage/var/lib/sonarr"
|
||||||
|
echo "Er is al een reservekopie gemaakt in /storage/backups/sonarr_complete_backup_2026-10-18.tar.gz"
|
||||||
|
echo "========================================================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
read -p "Weet je zeker dat je de oude Sonarr bestanden wilt verwijderen? (j/N): " -r CONFIRM
|
||||||
|
if [[ ! "$CONFIRM" =~ ^[jJyY]$ ]]; then
|
||||||
|
log_info "Opruimen geannuleerd."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_step "Verwijderen van systemd service en programmabestanden op ${CLUSTER_HOST}..."
|
||||||
|
ssh -t "${SSH_USER}@${CLUSTER_HOST}" "
|
||||||
|
echo '--> Stoppen en uitschakelen van sonarr.service...'
|
||||||
|
sudo systemctl stop sonarr 2>/dev/null || true
|
||||||
|
sudo systemctl disable sonarr 2>/dev/null || true
|
||||||
|
sudo rm -f /etc/systemd/system/sonarr.service
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl reset-failed 2>/dev/null || true
|
||||||
|
|
||||||
|
echo '--> Verwijderen van /opt/Sonarr...'
|
||||||
|
sudo rm -rf /opt/Sonarr
|
||||||
|
|
||||||
|
echo '--> Verwijderen van /storage/var/lib/sonarr...'
|
||||||
|
sudo rm -rf /storage/var/lib/sonarr
|
||||||
|
|
||||||
|
echo '--> Opslagruimte controleren...'
|
||||||
|
df -h / /storage
|
||||||
|
"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_info "De oude standalone Sonarr is succesvol en volledig opgeruimd!"
|
||||||
|
echo "Alle verkeer naar https://thuus.bnhmeijer.nl/sonarr/ loopt nu direct via de Kubernetes pod."
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sqlite3
|
||||||
|
import csv
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
def escape_pg_string(s):
|
||||||
|
if s is None:
|
||||||
|
return "NULL"
|
||||||
|
if isinstance(s, bytes):
|
||||||
|
s = s.decode('utf-8', errors='replace')
|
||||||
|
s = str(s).replace("'", "''")
|
||||||
|
return f"'{s}'"
|
||||||
|
|
||||||
|
def main():
|
||||||
|
sqlite_db_path = "/tmp/sonarr.db"
|
||||||
|
pg_columns_path = "/tmp/pg_sonarr_columns.csv"
|
||||||
|
output_sql_path = "/tmp/migrate_sonarr_data.sql"
|
||||||
|
|
||||||
|
# 1. Lees PG tabellen en kolommen
|
||||||
|
pg_schema = defaultdict(dict)
|
||||||
|
with open(pg_columns_path, mode='r', encoding='utf-8') as f:
|
||||||
|
reader = csv.reader(f)
|
||||||
|
for row in reader:
|
||||||
|
if not row or len(row) < 3:
|
||||||
|
continue
|
||||||
|
table, col, dtype = row[0].strip(), row[1].strip(), row[2].strip()
|
||||||
|
pg_schema[table][col] = dtype
|
||||||
|
|
||||||
|
# 2. Open SQLite
|
||||||
|
conn = sqlite3.connect(f"file:{sqlite_db_path}?mode=ro&immutable=1", uri=True)
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
cur.execute("SELECT name FROM sqlite_master WHERE type='table';")
|
||||||
|
sqlite_tables = set(r[0] for r in cur.fetchall())
|
||||||
|
|
||||||
|
with open(output_sql_path, mode='w', encoding='utf-8') as out:
|
||||||
|
out.write("-- Sonarr SQLite naar PostgreSQL Data Migratie\n")
|
||||||
|
out.write("BEGIN;\n")
|
||||||
|
out.write("SET session_replication_role = 'replica';\n\n")
|
||||||
|
|
||||||
|
# Tabellen die we NIET moeten overschrijven
|
||||||
|
skip_tables = {"VersionInfo"}
|
||||||
|
|
||||||
|
total_rows_imported = 0
|
||||||
|
|
||||||
|
for table, pg_cols in pg_schema.items():
|
||||||
|
if table in skip_tables:
|
||||||
|
continue
|
||||||
|
|
||||||
|
out.write(f"-- Tabel: {table}\n")
|
||||||
|
out.write(f'TRUNCATE TABLE "{table}" CASCADE;\n')
|
||||||
|
|
||||||
|
if table not in sqlite_tables:
|
||||||
|
out.write(f"-- Tabel {table} bestaat niet in SQLite, leeggemaakt en overgeslagen.\n\n")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Haal SQLite kolommen op
|
||||||
|
cur.execute(f'PRAGMA table_info("{table}");')
|
||||||
|
sqlite_col_names = set(r[1] for r in cur.fetchall())
|
||||||
|
|
||||||
|
# Gemeenschappelijke kolommen
|
||||||
|
common_cols = [c for c in pg_cols.keys() if c in sqlite_col_names]
|
||||||
|
if not common_cols:
|
||||||
|
out.write(f"-- Geen gemeenschappelijke kolommen voor {table}\n\n")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Query data uit SQLite
|
||||||
|
cols_quoted = [f'"{c}"' for c in common_cols]
|
||||||
|
cur.execute(f'SELECT {", ".join(cols_quoted)} FROM "{table}";')
|
||||||
|
rows = cur.fetchall()
|
||||||
|
|
||||||
|
if not rows:
|
||||||
|
out.write(f"-- Geen rijen in SQLite voor {table}\n\n")
|
||||||
|
continue
|
||||||
|
|
||||||
|
out.write(f'-- {len(rows)} rijen migreren voor {table}\n')
|
||||||
|
total_rows_imported += len(rows)
|
||||||
|
|
||||||
|
chunk_size = 200
|
||||||
|
for i in range(0, len(rows), chunk_size):
|
||||||
|
chunk = rows[i:i + chunk_size]
|
||||||
|
out.write(f'INSERT INTO "{table}" ({", ".join([f"""\"{c}\"""" for c in common_cols])}) VALUES\n')
|
||||||
|
val_lines = []
|
||||||
|
for row_data in chunk:
|
||||||
|
val_parts = []
|
||||||
|
for val, col_name in zip(row_data, common_cols):
|
||||||
|
dtype = pg_cols[col_name].lower()
|
||||||
|
if val is None:
|
||||||
|
val_parts.append("NULL")
|
||||||
|
elif "bool" in dtype:
|
||||||
|
val_parts.append("TRUE" if str(val) in ("1", "True", "true") else "FALSE")
|
||||||
|
elif dtype in ("integer", "bigint", "smallint", "numeric", "double precision", "real"):
|
||||||
|
val_parts.append(str(val))
|
||||||
|
else:
|
||||||
|
val_parts.append(escape_pg_string(val))
|
||||||
|
val_lines.append(f' ({", ".join(val_parts)})')
|
||||||
|
out.write(",\n".join(val_lines) + ";\n")
|
||||||
|
out.write("\n")
|
||||||
|
|
||||||
|
# Sequences resetten
|
||||||
|
out.write("-- Sequences bijwerken naar MAX(Id)\n")
|
||||||
|
out.write("""DO $$
|
||||||
|
DECLARE
|
||||||
|
r RECORD;
|
||||||
|
has_seq text;
|
||||||
|
BEGIN
|
||||||
|
FOR r IN SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name != 'VersionInfo' LOOP
|
||||||
|
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = r.table_name AND column_name = 'Id') THEN
|
||||||
|
has_seq := pg_get_serial_sequence('"' || r.table_name || '"', 'Id');
|
||||||
|
IF has_seq IS NOT NULL THEN
|
||||||
|
EXECUTE format('SELECT setval(%L, coalesce(max("Id"), 1)) FROM %I', has_seq, r.table_name);
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
END $$;\n\n""")
|
||||||
|
|
||||||
|
out.write("SET session_replication_role = 'origin';\n")
|
||||||
|
out.write("COMMIT;\n")
|
||||||
|
|
||||||
|
print(f"Sonarr SQL dump succesvol gegenereerd: {output_sql_path}")
|
||||||
|
print(f"Totaal aantal rijen klaargezet voor import: {total_rows_imported}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user