diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c677d1..9bed7f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,27 @@ +# v0.8.05-beta — Een onbereikbaar pad liet zich gewoon opslaan + +Dit is de oorzaak van de lege appslijst waar de vorige vier uitgaven omheen +hebben gezocht. + +`LIBRARY_DIR` stond op `/srv/serverup/stacks`, terwijl alleen `/opt/serverup` in +de container gekoppeld is. Dat pad bestaat binnen de container niet eens — dus +geen enkele app in de lijst, en alle containers onder "handmatig gestart", want +`beheerd` leest dezelfde map. Nergens stond waarom. + +De controle daarop bestond al sinds v0.7.92: `paden.bereikbaar()` weet dat de +container alleen bij paden onder `BASE_DIR` kan, en geeft de exacte regel die je +in `.env` moet zetten. Hij hing alleen aan het veld **Hoofdmap** en aan het +**verhuizen**. De drie padvelden eronder schrijven rechtstreeks naar +`PUT /api/settings` — en daar stond geen wacht. Een pad buiten de koppeling liet +zich dus gewoon opslaan, waarna alles stilviel. + +- `PUT /api/settings` weigert nu een `LIBRARY_DIR`, `DATA_DIR` of `BACKUP_DIR` + waar Server Up niet bij kan, met dezelfde uitleg: welke regel in `.env`, en + welk commando erna. Een ongewijzigd pad blokkeert niets, anders kun je met een + al kapotte instelling niets meer wijzigen. +- Is de lijst leeg, dan zegt het scherm nu **waarom**: niet "Geen apps + gevonden", maar dat Server Up er niet bij kan en wat eraan te doen is. + # v0.8.04-beta — `--doctor` vraagt het de app in plaats van het af te leiden Drie keer op rij heb ik de verkeerde oorzaak aangewezen voor een lege diff --git a/VERSION b/VERSION index d909f80..9344553 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.8.04-beta +0.8.05-beta diff --git a/server-up/app.py b/server-up/app.py index cfd99c8..8c6c357 100644 --- a/server-up/app.py +++ b/server-up/app.py @@ -2937,6 +2937,26 @@ def api_settings_put(): if "NOTIFY_CHANNEL" in updates: if (updates.get("NOTIFY_CHANNEL") or "") not in notify.KANALEN: return jsonify(ok=False, msg="Onbekend meldingskanaal"), 400 + # Kan Server Up bij de mappen die je opgeeft? De container ziet alleen wat + # via BASE_DIR gekoppeld is. Een pad daarbuiten laat zich hier prima + # opslaan, en daarna kijkt de app in een map die binnen de container niet + # bestaat: lege appslijst, alle containers onder "handmatig gestart", en + # nergens een melding. + # + # Deze controle bestond al voor de hoofdmap en voor het verhuizen, maar de + # drie velden schrijven rechtstreeks hierheen — dus liep het langs de wacht. + for sleutel in ("LIBRARY_DIR", "DATA_DIR", "BACKUP_DIR"): + if sleutel not in updates: + continue + nieuw_pad = str(updates[sleutel] or "").strip().rstrip("/") + if not nieuw_pad or nieuw_pad == (current.get(sleutel) or "").rstrip("/"): + continue + controle = paden.bereikbaar(nieuw_pad) + if not controle.get("ok"): + return jsonify(**{**controle, "veld": sleutel, + "msg": _padfout_tekst(controle)}), 400 + updates[sleutel] = nieuw_pad + if "NOTIFY_EVENTS" in updates: ev = updates["NOTIFY_EVENTS"] if not isinstance(ev, list) or any(e not in notify.EVENTS for e in ev): diff --git a/server-up/templates/index.html b/server-up/templates/index.html index 23c7cdc..28ab5f2 100644 --- a/server-up/templates/index.html +++ b/server-up/templates/index.html @@ -480,7 +480,11 @@ tailwind.config = { -

Geen apps gevonden

+
+ +

Geen apps gevonden

+

+

@@ -2528,6 +2532,7 @@ function app() { storeQuery: '', storeTag: '', storeCat: '', filterOpen: false, filterTagQuery: '', stackMenu: '', stackFilterOpen: false, hoofdmap: '', afgeleidePaden: {}, padCheck: {}, padenVoorWijziging: {}, + padWaarschuwing: '', padVelden: [ { sleutel: 'LIBRARY_DIR', label: 'library_dir' }, { sleutel: 'DATA_DIR', label: 'appdata_dir' }, @@ -2869,7 +2874,19 @@ function app() { }, async loadDashboard() { await this.loadDocker(); await this.loadStacks(); }, - async loadStacks() { const d = await this.rpc('/api/stacks'); this.stacks = Array.isArray(d) ? d : (d.stacks || []); }, + async loadStacks() { + const d = await this.rpc('/api/stacks'); + this.stacks = Array.isArray(d) ? d : (d.stacks || []); + // Geen apps? Dan is de vraag of dat klopt of dat Server Up er niet bij + // kan. Een lege lijst met "Geen apps gevonden" liet dat verschil weg, en + // een pad buiten de gekoppelde map ziet er in de instellingen prima uit. + this.padWaarschuwing = ''; + if (!this.stacks.length && this.settings.LIBRARY_DIR) { + const p = await this.rpc('/api/paths/check?path=' + + encodeURIComponent(this.settings.LIBRARY_DIR)); + if (p && !p.ok) this.padWaarschuwing = p.msg || ''; + } + }, async loadCategories() { const d = await this.rpc('/api/categories?lang=' + (localStorage.getItem('lang') || 'nl')); this.categories = d.categories || []; diff --git a/tests/test_paden.py b/tests/test_paden.py index 2cfa6b7..1247d45 100644 --- a/tests/test_paden.py +++ b/tests/test_paden.py @@ -367,3 +367,62 @@ def test_puid_volgt_het_account_van_server_up(client, env): velden = {f["name"]: f for f in d["fields"]} assert velden["puid"]["default"] == os.getuid() assert velden["pgid"]["default"] == os.getgid() + + +# ── Een pad opslaan dat de app niet kan bereiken ───────────────────────────── +# De controle bestond al voor de hoofdmap en voor het verhuizen, maar de drie +# padvelden schrijven rechtstreeks naar PUT /api/settings — dus liep het langs +# de wacht. Sla je daar /srv/... op terwijl alleen /opt/serverup gekoppeld is, +# dan kijkt de app in een map die binnen de container niet bestaat: lege +# appslijst, alle containers onder "handmatig gestart", nergens een melding. + +def test_onbereikbaar_pad_wordt_niet_opgeslagen(client, env, monkeypatch): + from core import paden + csrf = login(client) + # De testomgeving zet LIBRARY_DIR als omgevingsvariabele, en die wint van + # het configuratiebestand — dan zou je niet zien of er iets is opgeslagen. + monkeypatch.delenv("LIBRARY_DIR", raising=False) + monkeypatch.setattr(paden, "_in_container", lambda: True) + monkeypatch.setattr(paden, "_mountpunten", lambda: ["/opt/serverup", "/data"]) + + r = client.put("/api/settings", json={"LIBRARY_DIR": "/srv/serverup/stacks"}, + headers={"X-CSRF-Token": csrf}) + assert r.status_code == 400, r.get_json() + d = r.get_json() + assert d["veld"] == "LIBRARY_DIR" + assert "BASE_DIR=/srv/serverup" in d["msg"], d["msg"] + + import core + assert core.load()["LIBRARY_DIR"] != "/srv/serverup/stacks", \ + "het pad is toch opgeslagen" + + +def test_een_pad_binnen_de_koppeling_mag_gewoon(client, env, monkeypatch, tmp_path): + from core import paden + csrf = login(client) + monkeypatch.delenv("LIBRARY_DIR", raising=False) + monkeypatch.setattr(paden, "_in_container", lambda: True) + monkeypatch.setattr(paden, "_mountpunten", lambda: [str(tmp_path)]) + + doel = tmp_path / "serverup" / "stacks" + r = client.put("/api/settings", json={"LIBRARY_DIR": str(doel)}, + headers={"X-CSRF-Token": csrf}) + assert r.status_code == 200, r.get_json() + import core + assert core.load()["LIBRARY_DIR"] == str(doel) + + +def test_ongewijzigde_paden_blokkeren_het_opslaan_niet(client, env, monkeypatch): + """Anders kun je met een al kapot pad geen enkele instelling meer wijzigen.""" + from core import paden + import core + csrf = login(client) + huidig = core.load()["LIBRARY_DIR"] + monkeypatch.setattr(paden, "_in_container", lambda: True) + monkeypatch.setattr(paden, "_mountpunten", lambda: ["/nergens"]) + + r = client.put("/api/settings", + json={"LIBRARY_DIR": huidig, "TIMEZONE": "Europe/Amsterdam"}, + headers={"X-CSRF-Token": csrf}) + assert r.status_code == 200, r.get_json() + assert core.load()["TIMEZONE"] == "Europe/Amsterdam"