From 4c158e940791721e90f017b8da336a4688693063 Mon Sep 17 00:00:00 2001 From: menzelj Date: Sun, 16 Aug 2026 18:29:10 +0000 Subject: [PATCH] Fix NFS backup destinations broken by the 0.40.0 refactor (0.40.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _ensure_helper_image moved to stack_assets_service, but backup_destination_service imports it lazily inside _nfs_run/_nfs_helper, so nothing failed at import time — every NFS destination operation raised ImportError at runtime instead. The helper is now a public ensure_helper_image() and the NFS helpers import it from its new home. Verified: every services/ and routers/ module imports, and both NFS helper paths run through to a Docker call instead of ImportError. Co-Authored-By: Claude Opus 5 --- backend/services/backup_destination_service.py | 8 ++++---- backend/services/stack_assets_service.py | 12 ++++++------ backend/version.py | 2 +- frontend/package.json | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/backend/services/backup_destination_service.py b/backend/services/backup_destination_service.py index 0e163b9..c375594 100644 --- a/backend/services/backup_destination_service.py +++ b/backend/services/backup_destination_service.py @@ -288,10 +288,10 @@ def _nfs_run(volume: str, command: list[str]) -> str: from config import settings from docker_client import DockerError, get_client - from services.backup_service import _ensure_helper_image + from services.stack_assets_service import ensure_helper_image client = get_client() - _ensure_helper_image(client) + ensure_helper_image(client) try: out = client.containers.run( settings.BACKUP_HELPER_IMAGE, @@ -314,10 +314,10 @@ def _nfs_helper(volume: str): from config import settings from docker_client import DockerError, get_client, safe_call - from services.backup_service import _ensure_helper_image + from services.stack_assets_service import ensure_helper_image client = get_client() - _ensure_helper_image(client) + ensure_helper_image(client) try: return safe_call( client.containers.create, diff --git a/backend/services/stack_assets_service.py b/backend/services/stack_assets_service.py index 2b1eff2..8362a31 100644 --- a/backend/services/stack_assets_service.py +++ b/backend/services/stack_assets_service.py @@ -64,7 +64,7 @@ class AssetError(Exception): # --------------------------------------------------------------------------- # -def _ensure_helper_image(client) -> None: +def ensure_helper_image(client) -> None: image = settings.BACKUP_HELPER_IMAGE try: safe_call(client.images.get, image) @@ -104,7 +104,7 @@ def inspect_paths(paths: list[str]) -> dict[str, dict]: if not unique: return {} client = get_client() - _ensure_helper_image(client) + ensure_helper_image(client) mounts = {p: {"bind": f"/m/{i}", "mode": "ro"} for i, p in enumerate(unique)} script_parts = [] for i in range(len(unique)): @@ -149,7 +149,7 @@ def inspect_paths(paths: list[str]) -> dict[str, dict]: def export_path(source: str, kind: str, dest_file: str) -> int: """Tar a host path (dir contents, or a single file) into ``dest_file``.""" client = get_client() - _ensure_helper_image(client) + ensure_helper_image(client) if kind == "file": parent, base = _split(source) if not base: @@ -176,7 +176,7 @@ def export_path(source: str, kind: str, dest_file: str) -> int: def import_path(source: str, kind: str, src_file: str) -> None: """Unpack an archive produced by :func:`export_path` back to its host path.""" client = get_client() - _ensure_helper_image(client) + ensure_helper_image(client) if kind == "file": parent, _base = _split(source) container = _create_helper(client, {parent: {"bind": "/dst", "mode": "rw"}}) @@ -192,7 +192,7 @@ def import_path(source: str, kind: str, src_file: str) -> None: def export_volume(full_name: str, dest_file: str) -> int: """Stream a named volume's contents into ``dest_file`` (never into RAM).""" client = get_client() - _ensure_helper_image(client) + ensure_helper_image(client) container = _create_helper(client, {full_name: {"bind": "/v", "mode": "ro"}}) written = 0 try: @@ -209,7 +209,7 @@ def export_volume(full_name: str, dest_file: str) -> int: def import_volume(full_name: str, labels: dict, src_file: str, wipe: bool = True) -> None: """Restore a volume from an archive, optionally clearing it first.""" client = get_client() - _ensure_helper_image(client) + ensure_helper_image(client) existed = True try: safe_call(client.volumes.get, full_name) diff --git a/backend/version.py b/backend/version.py index e3c867e..0cfe496 100644 --- a/backend/version.py +++ b/backend/version.py @@ -1,3 +1,3 @@ """Single source of truth for the StackPilot release version.""" -APP_VERSION = "0.40.0" +APP_VERSION = "0.40.1" diff --git a/frontend/package.json b/frontend/package.json index 1229127..00078ec 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "stackpilot-frontend", "private": true, - "version": "0.40.0", + "version": "0.40.1", "type": "module", "scripts": { "dev": "vite",