From 7300351bb9fb147f4de81a60423c4561a4924c21 Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Sat, 21 Feb 2026 16:53:38 +0100
Subject: [PATCH] fix: Run backup/restore on host via nsenter for Python venv compatibility
---
app/routers/restore.py | 16 ++++++++++------
1 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/app/routers/restore.py b/app/routers/restore.py
index b487952..d03428e 100644
--- a/app/routers/restore.py
+++ b/app/routers/restore.py
@@ -6,7 +6,7 @@
from fastapi.responses import StreamingResponse
from app.auth import verify_token
-from app.ops_runner import _BACKUP_TIMEOUT, stream_ops
+from app.ops_runner import _BACKUP_TIMEOUT, stream_ops_host
router = APIRouter()
@@ -22,18 +22,22 @@
source: str,
dry_run: bool,
) -> AsyncGenerator[str, None]:
- """Async generator that drives the restore workflow and yields SSE events."""
+ """Async generator that drives the restore workflow and yields SSE events.
+
+ Runs on the host via nsenter because ops restore delegates to project CLIs
+ that use host Python venvs incompatible with the container's Python.
+ """
base_args = ["restore", project, env]
if dry_run:
base_args.append("--dry-run")
if source == "offsite":
- # ops offsite restore <project> <env> — downloads from offsite storage
+ # ops offsite restore <project> <env>
download_args = ["offsite", "restore", project, env]
yield _sse_line({"line": f"Downloading {project}/{env} from offsite...", "timestamp": _now()})
download_ok = True
- async for line in stream_ops(download_args, timeout=_BACKUP_TIMEOUT):
+ async for line in stream_ops_host(download_args, timeout=_BACKUP_TIMEOUT):
yield _sse_line({"line": line, "timestamp": _now()})
if line.startswith("[error]"):
download_ok = False
@@ -45,7 +49,7 @@
yield _sse_line({"line": "Download complete. Starting restore...", "timestamp": _now()})
success = True
- async for line in stream_ops(base_args, timeout=_BACKUP_TIMEOUT):
+ async for line in stream_ops_host(base_args, timeout=_BACKUP_TIMEOUT):
yield _sse_line({"line": line, "timestamp": _now()})
if line.startswith("[error]"):
success = False
@@ -69,7 +73,7 @@
Restore a backup for the given project/env.
Uses Server-Sent Events (SSE) to stream real-time progress.
- Parameters are passed as query strings since EventSource only supports GET.
+ Runs on the host via nsenter for Python venv compatibility.
"""
return StreamingResponse(
_restore_generator(project, env, source, dry_run),
--
Gitblit v1.3.1