Template
Add explicit database import UI and harden SQL restore.
This commit is contained in:
+23
-2
@@ -2,12 +2,13 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import gzip
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from .connection import get_pg_connection_params
|
||||
from .connection import close_pool, get_pg_connection_params
|
||||
from .store import invalidate_data_cache
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -25,6 +26,18 @@ def backup_filename() -> str:
|
||||
return f'amnezia_panel_backup_{stamp}.sql'
|
||||
|
||||
|
||||
def _decode_backup_bytes(data: bytes) -> bytes:
|
||||
"""Accept plain .sql or gzip-compressed dumps (.sql.gz / gzip magic)."""
|
||||
if not data:
|
||||
return data
|
||||
if data[:2] == b'\x1f\x8b':
|
||||
try:
|
||||
return gzip.decompress(data)
|
||||
except OSError as e:
|
||||
raise ValueError(f'Invalid gzip backup: {e}') from e
|
||||
return data
|
||||
|
||||
|
||||
def export_database_sql() -> bytes:
|
||||
"""Create a plain SQL dump of the panel PostgreSQL database."""
|
||||
params = get_pg_connection_params()
|
||||
@@ -54,8 +67,16 @@ def export_database_sql() -> bytes:
|
||||
|
||||
def restore_database_sql(data: bytes) -> None:
|
||||
"""Restore panel data from a plain SQL dump produced by pg_dump."""
|
||||
data = _decode_backup_bytes(data)
|
||||
if not data or not data.strip():
|
||||
raise ValueError('Empty backup file')
|
||||
|
||||
# Drop live pool connections so --clean DROP TABLE is not blocked.
|
||||
try:
|
||||
close_pool()
|
||||
except Exception as e:
|
||||
logger.warning('close_pool before restore failed: %s', e)
|
||||
|
||||
params = get_pg_connection_params()
|
||||
proc = subprocess.run(
|
||||
[
|
||||
@@ -72,9 +93,9 @@ def restore_database_sql(data: bytes) -> None:
|
||||
check=False,
|
||||
env=_pg_cli_env(params['password']),
|
||||
)
|
||||
invalidate_data_cache()
|
||||
if proc.returncode != 0:
|
||||
err = proc.stderr.decode('utf-8', errors='replace').strip()
|
||||
out = proc.stdout.decode('utf-8', errors='replace').strip()
|
||||
raise RuntimeError(err or out or 'psql restore failed')
|
||||
invalidate_data_cache()
|
||||
logger.info('PostgreSQL backup restored successfully')
|
||||
|
||||
Reference in New Issue
Block a user