v0.8.05-beta - een onbereikbaar pad liet zich gewoon opslaan
Some checks failed
Deploy server-up (dev) / deploy (push) Has been cancelled
Some checks failed
Deploy server-up (dev) / deploy (push) Has been cancelled
Oorzaak van de lege appslijst: LIBRARY_DIR stond op /srv/serverup/stacks terwijl alleen /opt/serverup gekoppeld is. Dat pad bestaat binnen de container niet, dus geen apps in de lijst en alle containers onder "handmatig gestart" — want beheerd leest dezelfde map. Nergens stond waarom. paden.bereikbaar() bestond al sinds v0.7.92 maar hing alleen aan het veld Hoofdmap en aan het verhuizen. De drie padvelden schrijven rechtstreeks naar PUT /api/settings, en daar stond geen wacht. - PUT /api/settings weigert nu een pad waar Server Up niet bij kan, met de regel voor .env erbij. Een ongewijzigd pad blokkeert niets, anders kun je met een kapotte instelling niets meer wijzigen - een lege appslijst zegt nu waarom in plaats van "Geen apps gevonden" Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
This commit is contained in:
parent
2ce42f507d
commit
e61f90745b
5 changed files with 123 additions and 3 deletions
24
CHANGELOG.md
24
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
|
# 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
|
Drie keer op rij heb ik de verkeerde oorzaak aangewezen voor een lege
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
0.8.04-beta
|
0.8.05-beta
|
||||||
|
|
|
||||||
|
|
@ -2937,6 +2937,26 @@ def api_settings_put():
|
||||||
if "NOTIFY_CHANNEL" in updates:
|
if "NOTIFY_CHANNEL" in updates:
|
||||||
if (updates.get("NOTIFY_CHANNEL") or "") not in notify.KANALEN:
|
if (updates.get("NOTIFY_CHANNEL") or "") not in notify.KANALEN:
|
||||||
return jsonify(ok=False, msg="Onbekend meldingskanaal"), 400
|
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:
|
if "NOTIFY_EVENTS" in updates:
|
||||||
ev = updates["NOTIFY_EVENTS"]
|
ev = updates["NOTIFY_EVENTS"]
|
||||||
if not isinstance(ev, list) or any(e not in notify.EVENTS for e in ev):
|
if not isinstance(ev, list) or any(e not in notify.EVENTS for e in ev):
|
||||||
|
|
|
||||||
|
|
@ -480,7 +480,11 @@ tailwind.config = {
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div x-show="!filteredStacks.length && !filteredLos.length" class="empty"><span class="mdi mdi-server-network"></span><p x-text="t('no_stacks')">Geen apps gevonden</p></div>
|
<div x-show="!filteredStacks.length && !filteredLos.length" class="empty">
|
||||||
|
<span class="mdi" :class="padWaarschuwing ? 'mdi-folder-alert-outline text-wr' : 'mdi-server-network'"></span>
|
||||||
|
<p x-show="!padWaarschuwing" x-text="t('no_stacks')">Geen apps gevonden</p>
|
||||||
|
<p x-show="padWaarschuwing" class="text-wr max-w-xl mx-auto" x-text="padWaarschuwing"></p>
|
||||||
|
</div>
|
||||||
<p x-show="filteredLos.length" class="text-xs text-t2 dark:text-t2-dark mt-4"
|
<p x-show="filteredLos.length" class="text-xs text-t2 dark:text-t2-dark mt-4"
|
||||||
x-text="t('manual_hint')"></p>
|
x-text="t('manual_hint')"></p>
|
||||||
|
|
||||||
|
|
@ -2528,6 +2532,7 @@ function app() {
|
||||||
storeQuery: '', storeTag: '', storeCat: '',
|
storeQuery: '', storeTag: '', storeCat: '',
|
||||||
filterOpen: false, filterTagQuery: '', stackMenu: '', stackFilterOpen: false,
|
filterOpen: false, filterTagQuery: '', stackMenu: '', stackFilterOpen: false,
|
||||||
hoofdmap: '', afgeleidePaden: {}, padCheck: {}, padenVoorWijziging: {},
|
hoofdmap: '', afgeleidePaden: {}, padCheck: {}, padenVoorWijziging: {},
|
||||||
|
padWaarschuwing: '',
|
||||||
padVelden: [
|
padVelden: [
|
||||||
{ sleutel: 'LIBRARY_DIR', label: 'library_dir' },
|
{ sleutel: 'LIBRARY_DIR', label: 'library_dir' },
|
||||||
{ sleutel: 'DATA_DIR', label: 'appdata_dir' },
|
{ sleutel: 'DATA_DIR', label: 'appdata_dir' },
|
||||||
|
|
@ -2869,7 +2874,19 @@ function app() {
|
||||||
},
|
},
|
||||||
async loadDashboard() { await this.loadDocker(); await this.loadStacks(); },
|
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() {
|
async loadCategories() {
|
||||||
const d = await this.rpc('/api/categories?lang=' + (localStorage.getItem('lang') || 'nl'));
|
const d = await this.rpc('/api/categories?lang=' + (localStorage.getItem('lang') || 'nl'));
|
||||||
this.categories = d.categories || [];
|
this.categories = d.categories || [];
|
||||||
|
|
|
||||||
|
|
@ -367,3 +367,62 @@ def test_puid_volgt_het_account_van_server_up(client, env):
|
||||||
velden = {f["name"]: f for f in d["fields"]}
|
velden = {f["name"]: f for f in d["fields"]}
|
||||||
assert velden["puid"]["default"] == os.getuid()
|
assert velden["puid"]["default"] == os.getuid()
|
||||||
assert velden["pgid"]["default"] == os.getgid()
|
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"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue