Compare commits
10
Commits
a101e73c0e
...
v1.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff70668f38 | ||
|
|
fbe431555e | ||
|
|
bd4c4f8716 | ||
|
|
201cdb5bf9 | ||
|
|
7ba4adb376 | ||
|
|
a4fc880c38 | ||
|
|
edf6294315 | ||
|
|
b4dd074894 | ||
|
|
e81f6643fc | ||
|
|
afe51c4abd |
@@ -1219,7 +1219,7 @@ def _generate_qr_base64(data: str) -> str | None:
|
||||
# ── Update helpers (file-based, no systemctl) ────────────────────
|
||||
|
||||
def _read_update_status() -> str:
|
||||
"""Read the status file. Returns RUNNING, SUCCESS, FAILED, or IDLE."""
|
||||
"""Read the status file. Returns RUNNING, SUCCESS, REBOOT_REQUIRED, FAILED, or IDLE."""
|
||||
try:
|
||||
with open(UPDATE_STATUS, "r") as f:
|
||||
return f.read().strip()
|
||||
@@ -4755,17 +4755,21 @@ def _recover_stale_status(status_file: str, log_file: str, unit_name: str) -> bo
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
new_status = "SUCCESS" if unit_result == "success" else "FAILED"
|
||||
if unit_result == "success":
|
||||
new_status = "REBOOT_REQUIRED" if unit_name == UPDATE_UNIT else "SUCCESS"
|
||||
else:
|
||||
new_status = "FAILED"
|
||||
try:
|
||||
with open(status_file, "w") as f:
|
||||
f.write(new_status)
|
||||
except OSError:
|
||||
pass
|
||||
msg = (
|
||||
"\n[Update completed successfully while the server was restarting.]\n"
|
||||
if new_status == "SUCCESS"
|
||||
else "\n[Update encountered an error. See log above for details.]\n"
|
||||
)
|
||||
if new_status == "REBOOT_REQUIRED":
|
||||
msg = "\n[Update staged successfully while the server was restarting. Reboot required.]\n"
|
||||
elif new_status == "SUCCESS":
|
||||
msg = "\n[Update completed successfully while the server was restarting.]\n"
|
||||
else:
|
||||
msg = "\n[Update encountered an error. See log above for details.]\n"
|
||||
try:
|
||||
with open(log_file, "a") as f:
|
||||
f.write(msg)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
HUB_NIX = Path(__file__).resolve().parents[2] / "modules" / "core" / "sovran-hub.nix"
|
||||
|
||||
|
||||
def _section(source: str, start: str, end: str) -> str:
|
||||
start_idx = source.find(start)
|
||||
if start_idx == -1:
|
||||
raise AssertionError(f"Expected section start not found: {start!r}")
|
||||
end_idx = source.find(end, start_idx)
|
||||
if end_idx == -1:
|
||||
raise AssertionError(f"Expected section end not found: {end!r}")
|
||||
return source[start_idx:end_idx]
|
||||
|
||||
|
||||
class HubUpdateBootStagingTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.source = HUB_NIX.read_text()
|
||||
self.update_section = _section(
|
||||
self.source,
|
||||
'update-script = pkgs.writeShellScript "sovran-hub-update.sh" \'\'',
|
||||
"# ── Rebuild wrapper script",
|
||||
)
|
||||
self.rebuild_section = _section(
|
||||
self.source,
|
||||
'rebuild-script = pkgs.writeShellScript "sovran-hub-rebuild.sh" \'\'',
|
||||
"# ── Brave launcher wrapper",
|
||||
)
|
||||
|
||||
def test_full_update_uses_boot_not_switch(self):
|
||||
self.assertIn("nixos-rebuild boot --flake /etc/nixos", self.update_section)
|
||||
self.assertNotIn("nixos-rebuild switch --flake /etc/nixos", self.update_section)
|
||||
|
||||
def test_full_update_marks_reboot_required(self):
|
||||
self.assertIn('echo "REBOOT_REQUIRED" > "$STATUS"', self.update_section)
|
||||
|
||||
def test_rebuild_path_keeps_switch_semantics(self):
|
||||
self.assertIn("nixos-rebuild switch --flake /etc/nixos", self.rebuild_section)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Generated
+21
-21
@@ -5,11 +5,11 @@
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1781968640,
|
||||
"narHash": "sha256-ySgKs6YZRJRsBVoMnmOBGQiNRaX7M9FxMnHA29kovqA=",
|
||||
"lastModified": 1783086783,
|
||||
"narHash": "sha256-NxXpNF/9tq2nI+SxFHUxjro3u11SF3l4vs7bawdMKkQ=",
|
||||
"owner": "emmanuelrosa",
|
||||
"repo": "btc-clients-nix",
|
||||
"rev": "3959faadf6c9d3148e1d819ae85b7f32da5b005b",
|
||||
"rev": "4f6d07cae877ef58f0fbc9e731c99800ddb80859",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -52,11 +52,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1778716662,
|
||||
"narHash": "sha256-m1Yf0wZ8j1OHjTc2UwHwyQRSnNeSgLJOd7q5Y45hzi4=",
|
||||
"lastModified": 1782949081,
|
||||
"narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "f7c1a2d347e4c52d5fb8d10cb4d94b5884e546fb",
|
||||
"rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -108,11 +108,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1780218263,
|
||||
"narHash": "sha256-T/f0pPDrH3Qc1VXyQXbK7yfHWRn90l3xwplc/nsxin4=",
|
||||
"lastModified": 1782911660,
|
||||
"narHash": "sha256-PbR+tJ5E/Ux+01UtdFKqblccVA4/FgWbkym4ev3VHHQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7fc393d1b46fa000d48ff14e8b6a3c9985f03af0",
|
||||
"rev": "cf720c15e108d432d29041cc5a185630809acefb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -139,11 +139,11 @@
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1782691344,
|
||||
"narHash": "sha256-i5nw9BYYsMDAaOC4J+JmTof6b2GhlyH076awYRNrTV8=",
|
||||
"lastModified": 1782999065,
|
||||
"narHash": "sha256-5Dgj5+pIQYZKrXUGaLCk7CKfN3MmpwIhO94++WVxvng=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1f01958ffb5b3545c96d9ef2f4e24c5e5e1eb846",
|
||||
"rev": "80d591ed473cfc46329932c2aadac9b435342c7c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -187,11 +187,11 @@
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1782723713,
|
||||
"narHash": "sha256-oPXCU/SSUokcGaJREHibG1CBX3+s/W7orDWQOZDsEeQ=",
|
||||
"lastModified": 1782959384,
|
||||
"narHash": "sha256-xnJJk+ct+D2+wdRxj1wk36w5zV9RVESwRqcklPdt3fM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b5aa0fbd538984f6e3d201be0005b4463d8b09f8",
|
||||
"rev": "65179426c83bb3f6bc14898b42ea1c6f01d374b0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -203,11 +203,11 @@
|
||||
},
|
||||
"nixpkgs_4": {
|
||||
"locked": {
|
||||
"lastModified": 1781607440,
|
||||
"narHash": "sha256-rxO+uc/KFbSJp+pgyXRuAX6QlG9hJdnt0BXpEQRXY+U=",
|
||||
"lastModified": 1782948114,
|
||||
"narHash": "sha256-AXmz9ho4Lud5CsbrZsuSVwpQZ4o5FgZ1chxBn5cJ8+0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3e41b24abd260e8f71dbe2f5737d24122f972158",
|
||||
"rev": "9e92285f211dad236540fd617d7e30e0b99bc0e1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -224,11 +224,11 @@
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1782706849,
|
||||
"narHash": "sha256-b2ODGxKD3hgrwuesLtDomp2DKF3UiOn3+EBTDXpcqGo=",
|
||||
"lastModified": 1783173302,
|
||||
"narHash": "sha256-nlnOw/zsD2H2NHSZ5oNWwcjuM17vipyAapfXsO78GjY=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixvim",
|
||||
"rev": "c6a99bb41fb0f37e03ca38b1d81b006e98e3bf1a",
|
||||
"rev": "a402fdf2a1ef297d8ea7c95b90d6af0dbe90ab11",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -16,7 +16,10 @@ let
|
||||
in
|
||||
{
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
# Only enable Caddy when at least one domain-based service needs it or
|
||||
# the operator has defined custom vhosts. This prevents Caddy from
|
||||
# running on Desktop Only installs that have no web services configured.
|
||||
enable = needsHttpsPorts || extraVhosts != "";
|
||||
user = "caddy";
|
||||
group = "root";
|
||||
};
|
||||
|
||||
@@ -3,6 +3,13 @@
|
||||
{
|
||||
config = lib.mkMerge [
|
||||
|
||||
# nix-bitcoin is globally imported by the flake (nixosModules.Sovran_SystemsOS).
|
||||
# This default satisfies nix-bitcoin's generateSecrets assertion so that Desktop
|
||||
# Only systems can evaluate without enabling any Bitcoin services.
|
||||
{
|
||||
nix-bitcoin.generateSecrets = lib.mkDefault true;
|
||||
}
|
||||
|
||||
# ── Server+Desktop Role (default) ─────────────────────────
|
||||
(lib.mkIf config.sovran_systemsOS.roles.server_plus_desktop {
|
||||
sovran_systemsOS.web.btcpayserver = lib.mkDefault true;
|
||||
@@ -12,15 +19,24 @@
|
||||
(lib.mkIf config.sovran_systemsOS.roles.desktop {
|
||||
services.desktopManager.gnome.enable = true;
|
||||
|
||||
# Force all server/node services and features off so they cannot be
|
||||
# accidentally enabled via custom.nix or option defaults on Desktop Only.
|
||||
sovran_systemsOS.services = {
|
||||
synapse = lib.mkDefault false;
|
||||
bitcoin = lib.mkDefault false;
|
||||
vaultwarden = lib.mkDefault false;
|
||||
wordpress = lib.mkDefault false;
|
||||
nextcloud = lib.mkDefault false;
|
||||
synapse = lib.mkForce false;
|
||||
bitcoin = lib.mkForce false;
|
||||
vaultwarden = lib.mkForce false;
|
||||
wordpress = lib.mkForce false;
|
||||
nextcloud = lib.mkForce false;
|
||||
};
|
||||
|
||||
sovran_systemsOS.web.btcpayserver = lib.mkDefault false;
|
||||
sovran_systemsOS.features = {
|
||||
haven = lib.mkForce false;
|
||||
mempool = lib.mkForce false;
|
||||
element-calling = lib.mkForce false;
|
||||
bitcoin-core = lib.mkForce false;
|
||||
};
|
||||
|
||||
sovran_systemsOS.web.btcpayserver = lib.mkForce false;
|
||||
})
|
||||
|
||||
# ── Bitcoin Node Only Role ────────────────────────────────
|
||||
|
||||
@@ -146,33 +146,16 @@ let
|
||||
echo ""
|
||||
|
||||
if [ "$RC" -eq 0 ]; then
|
||||
echo "── Step 2/3: nixos-rebuild ──────────────────────────"
|
||||
SWITCH_OUT=$(nixos-rebuild switch --flake /etc/nixos --print-build-logs \
|
||||
echo "── Step 2/3: nixos-rebuild boot (stage next reboot) ──"
|
||||
BOOT_OUT=$(nixos-rebuild boot --flake /etc/nixos --print-build-logs \
|
||||
--option connect-timeout 10 \
|
||||
--option stalled-download-timeout 90 \
|
||||
--option download-attempts 7 \
|
||||
--option fallback true 2>&1)
|
||||
SWITCH_RC=$?
|
||||
echo "$SWITCH_OUT"
|
||||
if [ "$SWITCH_RC" -eq 0 ]; then
|
||||
echo "[OK] switch succeeded"
|
||||
elif echo "$SWITCH_OUT" | grep -q "switchInhibitors\|Pre-switch checks failed"; then
|
||||
echo ""
|
||||
echo " ✓ Build succeeded — a reboot is required to apply this update"
|
||||
echo " (Critical system components changed; running nixos-rebuild boot instead)"
|
||||
if nixos-rebuild boot --flake /etc/nixos --print-build-logs \
|
||||
--option connect-timeout 10 \
|
||||
--option stalled-download-timeout 90 \
|
||||
--option download-attempts 7 \
|
||||
--option fallback true 2>&1; then
|
||||
echo "REBOOT_REQUIRED" > "$STATUS"
|
||||
exit 0
|
||||
else
|
||||
echo "[ERROR] nixos-rebuild boot also failed"
|
||||
RC=1
|
||||
fi
|
||||
else
|
||||
echo "[ERROR] nixos-rebuild switch failed"
|
||||
BOOT_RC=$?
|
||||
echo "$BOOT_OUT"
|
||||
if [ "$BOOT_RC" -ne 0 ]; then
|
||||
echo "[ERROR] nixos-rebuild boot failed"
|
||||
RC=1
|
||||
fi
|
||||
echo ""
|
||||
@@ -188,9 +171,10 @@ let
|
||||
|
||||
if [ "$RC" -eq 0 ]; then
|
||||
echo "══════════════════════════════════════════════════"
|
||||
echo " ✓ Update completed successfully"
|
||||
echo " ✓ Update staged successfully"
|
||||
echo " Reboot required to activate the new system"
|
||||
echo "══════════════════════════════════════════════════"
|
||||
echo "SUCCESS" > "$STATUS"
|
||||
echo "REBOOT_REQUIRED" > "$STATUS"
|
||||
else
|
||||
echo "══════════════════════════════════════════════════"
|
||||
echo " ✗ Update failed — see errors above"
|
||||
|
||||
Reference in New Issue
Block a user