Merge pull request #232 from naturallaw777/copilot/fix-upgrade-to-server-desktop
Fix node→server+desktop upgrade: defer rebuild until after onboarding collects domains/SSL/ports
This commit is contained in:
@@ -1683,6 +1683,27 @@ async def api_onboarding_complete():
|
|||||||
f.write("")
|
f.write("")
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
raise HTTPException(status_code=500, detail=f"Could not write flag file: {exc}")
|
raise HTTPException(status_code=500, detail=f"Could not write flag file: {exc}")
|
||||||
|
|
||||||
|
# Trigger a NixOS rebuild now that domains/ports/SSL are configured.
|
||||||
|
# This is especially important after a role upgrade (Node → Server+Desktop)
|
||||||
|
# where the rebuild was deferred until onboarding collected all required config.
|
||||||
|
try:
|
||||||
|
open(REBUILD_LOG, "w").close()
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
await asyncio.create_subprocess_exec(
|
||||||
|
"systemctl", "reset-failed", REBUILD_UNIT,
|
||||||
|
stdout=asyncio.subprocess.DEVNULL,
|
||||||
|
stderr=asyncio.subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
proc = await asyncio.create_subprocess_exec(
|
||||||
|
"systemctl", "start", "--no-block", REBUILD_UNIT,
|
||||||
|
stdout=asyncio.subprocess.DEVNULL,
|
||||||
|
stderr=asyncio.subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
await proc.wait()
|
||||||
|
|
||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|
||||||
@@ -1748,7 +1769,7 @@ ROLE_STATE_NIX = """\
|
|||||||
|
|
||||||
@app.post("/api/role/upgrade-to-server")
|
@app.post("/api/role/upgrade-to-server")
|
||||||
async def api_upgrade_to_server():
|
async def api_upgrade_to_server():
|
||||||
"""Upgrade from Node role to Server+Desktop role by writing role-state.nix and rebuilding."""
|
"""Upgrade from Node role to Server+Desktop role."""
|
||||||
cfg = load_config()
|
cfg = load_config()
|
||||||
if cfg.get("role", "server_plus_desktop") != "node":
|
if cfg.get("role", "server_plus_desktop") != "node":
|
||||||
raise HTTPException(status_code=400, detail="Upgrade is only available for the Node role.")
|
raise HTTPException(status_code=400, detail="Upgrade is only available for the Node role.")
|
||||||
@@ -1765,25 +1786,14 @@ async def api_upgrade_to_server():
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Clear stale rebuild log
|
# Don't rebuild yet — the user needs to configure domains, SSL email,
|
||||||
|
# and ports first via the onboarding wizard. Reboot so onboarding runs.
|
||||||
try:
|
try:
|
||||||
open(REBUILD_LOG, "w").close()
|
await asyncio.create_subprocess_exec(*REBOOT_COMMAND)
|
||||||
except OSError:
|
except Exception as exc:
|
||||||
pass
|
raise HTTPException(status_code=500, detail=f"Failed to initiate reboot: {exc}")
|
||||||
|
|
||||||
await asyncio.create_subprocess_exec(
|
return {"ok": True, "status": "rebooting_to_onboarding"}
|
||||||
"systemctl", "reset-failed", REBUILD_UNIT,
|
|
||||||
stdout=asyncio.subprocess.DEVNULL,
|
|
||||||
stderr=asyncio.subprocess.DEVNULL,
|
|
||||||
)
|
|
||||||
proc = await asyncio.create_subprocess_exec(
|
|
||||||
"systemctl", "start", "--no-block", REBUILD_UNIT,
|
|
||||||
stdout=asyncio.subprocess.DEVNULL,
|
|
||||||
stderr=asyncio.subprocess.DEVNULL,
|
|
||||||
)
|
|
||||||
await proc.wait()
|
|
||||||
|
|
||||||
return {"ok": True, "status": "rebuilding"}
|
|
||||||
|
|
||||||
|
|
||||||
# ── Bitcoin IBD sync helper ───────────────────────────────────────
|
# ── Bitcoin IBD sync helper ───────────────────────────────────────
|
||||||
|
|||||||
@@ -59,13 +59,27 @@ async function doUpgradeToServer() {
|
|||||||
if (confirmBtn) { confirmBtn.disabled = true; confirmBtn.textContent = "Upgrading…"; }
|
if (confirmBtn) { confirmBtn.disabled = true; confirmBtn.textContent = "Upgrading…"; }
|
||||||
closeUpgradeModal();
|
closeUpgradeModal();
|
||||||
|
|
||||||
// Reuse the rebuild modal to show progress
|
// Reuse the rebuild modal to show reboot progress
|
||||||
_rebuildFeatureName = "Server + Desktop";
|
_rebuildFeatureName = "Server + Desktop";
|
||||||
_rebuildIsEnabling = true;
|
_rebuildIsEnabling = true;
|
||||||
openRebuildModal();
|
openRebuildModal();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await apiFetch("/api/role/upgrade-to-server", { method: "POST" });
|
await apiFetch("/api/role/upgrade-to-server", { method: "POST" });
|
||||||
|
// Server is rebooting — show message and wait for it to come back
|
||||||
|
if ($rebuildStatus) $rebuildStatus.textContent = "Rebooting — the setup wizard will guide you through domain and port configuration…";
|
||||||
|
if ($rebuildSpinner) $rebuildSpinner.classList.add("spinning");
|
||||||
|
|
||||||
|
// Poll until server comes back, then redirect to onboarding
|
||||||
|
var pollInterval = setInterval(async function() {
|
||||||
|
try {
|
||||||
|
await apiFetch("/api/ping");
|
||||||
|
clearInterval(pollInterval);
|
||||||
|
window.location.href = "/onboarding";
|
||||||
|
} catch (_) {
|
||||||
|
// Server still down — keep polling
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if ($rebuildStatus) $rebuildStatus.textContent = "✗ Upgrade failed: " + err.message;
|
if ($rebuildStatus) $rebuildStatus.textContent = "✗ Upgrade failed: " + err.message;
|
||||||
if ($rebuildSpinner) $rebuildSpinner.classList.remove("spinning");
|
if ($rebuildSpinner) $rebuildSpinner.classList.remove("spinning");
|
||||||
|
|||||||
Reference in New Issue
Block a user