Skip to content

Commit aede529

Browse files
DAdjadjclaude
andcommitted
Add helper container fallback for users without Watchtower
Try Watchtower first, fall back to spawning a helper container that runs docker compose up -d. This ensures the update button works for old customers who haven't updated their docker-compose.yml yet. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ef92240 commit aede529

File tree

1 file changed

+35
-3
lines changed

1 file changed

+35
-3
lines changed

app/web/server.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,7 @@ def update_check():
772772

773773
@app.route("/update/run", methods=["POST"])
774774
def update_run():
775+
# Try Watchtower first (new setup), fall back to helper container (old setup)
775776
import requests as _requests
776777
try:
777778
resp = _requests.get(
@@ -783,10 +784,41 @@ def update_run():
783784
if resp.status_code == 200:
784785
db.set_setting("update_available", "0")
785786
return jsonify({"updating": True})
786-
return jsonify({"error": "Update service returned an error. Try running: docker compose pull && docker compose up -d"}), 500
787+
except Exception:
788+
logger.info("Watchtower not available, falling back to helper container")
789+
# Fallback: pull image and spawn a helper container to run docker compose
790+
import subprocess, os, json as _json
791+
if not os.path.exists("/var/run/docker.sock"):
792+
return jsonify({"error": "Docker socket not mounted."}), 400
793+
try:
794+
subprocess.run(["docker", "pull", IMAGE_NAME], capture_output=True, text=True, timeout=120)
795+
mounts_json = subprocess.run(
796+
["docker", "inspect", "--format", "{{json .Mounts}}", CONTAINER_NAME],
797+
capture_output=True, text=True, timeout=5
798+
).stdout.strip()
799+
compose_host_path = ""
800+
for m in _json.loads(mounts_json or "[]"):
801+
if m.get("Destination") == "/compose":
802+
compose_host_path = m["Source"]
803+
break
804+
if not compose_host_path:
805+
return jsonify({"error": "Could not update. Try running: docker compose pull && docker compose up -d"}), 400
806+
compose_file = f"{compose_host_path}/docker-compose.yml"
807+
result = subprocess.run([
808+
"docker", "run", "-d", "--rm",
809+
"-v", "/var/run/docker.sock:/var/run/docker.sock",
810+
"-v", f"{compose_host_path}:{compose_host_path}:ro",
811+
IMAGE_NAME, "sh", "-c",
812+
f"sleep 2 && docker compose -f '{compose_file}' up -d --force-recreate",
813+
], capture_output=True, text=True, timeout=15)
814+
if result.returncode != 0:
815+
logger.error("Failed to start update helper: %s", result.stderr.strip())
816+
return jsonify({"error": "Failed to start update. Try running: docker compose pull && docker compose up -d"}), 500
817+
db.set_setting("update_available", "0")
818+
return jsonify({"updating": True})
787819
except Exception as e:
788-
logger.error("Failed to trigger update: %s", e)
789-
return jsonify({"error": "Update service not available. Try running: docker compose pull && docker compose up -d"}), 500
820+
logger.error("Fallback update failed: %s", e)
821+
return jsonify({"error": str(e)}), 500
790822

791823
_banks_cache = None
792824

0 commit comments

Comments
 (0)