Store SQLite DB on remote host via SCP for persistence

Instead of syncing JSON files back, the SQLite DB itself is now
the persistent store on the remote HAProxy host:
- Startup: download remote DB via SCP (skip migration if exists)
- After writes: upload local DB via SCP (WAL checkpoint first)
- JSON sync removed (sync_servers_json, sync_certs_json deleted)

New functions:
- ssh_ops: remote_download_file(), remote_upload_file() via SCP
- db: sync_db_to_remote(), _try_download_remote_db()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-02-08 11:46:36 +09:00
parent b86ba5d994
commit 12fd3b5e8f
5 changed files with 108 additions and 35 deletions

View File

@@ -125,6 +125,58 @@ def remote_file_exists(path: str) -> bool:
return result.stdout.strip() == "yes"
def _scp_base_cmd() -> list[str]:
"""Build base SCP command with options."""
cmd = [
"scp",
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=/dev/null",
"-o", "LogLevel=ERROR",
"-o", "BatchMode=yes",
"-o", "ConnectTimeout=10",
"-P", str(SSH_PORT),
]
if SSH_KEY:
cmd.extend(["-i", SSH_KEY])
return cmd
def remote_download_file(remote_path: str, local_path: str) -> bool:
"""Download a binary file from the remote host via SCP.
Args:
remote_path: Absolute file path on remote host
local_path: Absolute local file path to write to
Returns:
True if downloaded successfully, False if file doesn't exist
"""
cmd = _scp_base_cmd() + [f"{SSH_USER}@{SSH_HOST}:{remote_path}", local_path]
logger.debug("SCP download: %s -> %s", remote_path, local_path)
result = subprocess.run(cmd, capture_output=True, text=True, timeout=SUBPROCESS_TIMEOUT)
if result.returncode != 0:
logger.debug("SCP download failed: %s", result.stderr.strip())
return False
return True
def remote_upload_file(local_path: str, remote_path: str) -> None:
"""Upload a binary file to the remote host via SCP.
Args:
local_path: Absolute local file path to upload
remote_path: Absolute file path on remote host
Raises:
IOError: If upload fails
"""
cmd = _scp_base_cmd() + [local_path, f"{SSH_USER}@{SSH_HOST}:{remote_path}"]
logger.debug("SCP upload: %s -> %s", local_path, remote_path)
result = subprocess.run(cmd, capture_output=True, text=True, timeout=SUBPROCESS_TIMEOUT)
if result.returncode != 0:
raise IOError(f"SCP upload failed: {result.stderr.strip()}")
def run_command(args: list[str], timeout: int = SUBPROCESS_TIMEOUT) -> subprocess.CompletedProcess:
"""Execute a command locally or remotely based on REMOTE_MODE.