Gate 0.0.27: de statuskaart loog na elke herstart. Relay 0.5.4: Status naar rechts
De melding van de gebruiker was "Not answering" met [Errno 111] Connection refused, terwijl de gateway van buiten gewoon werkte. Het was een startvolgorde en geen storing: 1. de compose laat `server` ná de agent starten (depends_on: [agent]), want nginx lost http://agent:8000 bij het starten op en breekt af op een onbekende naam; 2. build_status draait meteen bij het opstarten, vóór de eerste WAKE.wait; 3. de branch die de meting uitstelt hing alleen aan `reloaded`, en die is bij een herstart met een ongewijzigd certificaat False, dus er werd gemeten; 4. nginx luisterde toen nog niet op 50022; 5. en het bleef staan, want de volgende meting kwam pas na SELF_CHECK_INTERVAL. Twee reparaties, elk voor een helft. De eerste ronde van een proces meet niet maar zet `pending` (die toestand heeft geen `at`, dus de ronde daarna meet gewoon), en na een mislukking wordt er na GATE_SELF_CHECK_RETRY (60s) opnieuw gemeten in plaats van na 300. Een geslaagde meting blijft op 300, want dat is de waarde die zelden verandert en die het activiteitenlog belast. De fout zat er sinds de zelfcontrole bestaat (27-08-2026) en was alleen binnen vijf minuten na een herstart te zien. Mutatie-getest: de eerste-rondebranch uitschakelen laat twee tests omvallen, de snelle herhaling uitschakelen precies één. Relay: de statuswidget staat nu rechts in de bovenste rij en heet Status in plaats van Relay, gelijk aan Electrum Gate. De twee pagina's zijn één app store en horen op dezelfde manier te lezen, en dit is de widget die als enige begrijpelijk is zonder buur. De id's relay-state en relay-sub blijven. Suite groen: 54 + 28 + 65 + 39 + 43 + 22 + 115. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ import sys
|
||||
# Zelfde reden als in test_agent_certificates.py: geen .pyc naast de app-map.
|
||||
sys.dont_write_bytecode = True
|
||||
|
||||
import json # noqa: E402
|
||||
import os # noqa: E402
|
||||
import socket # noqa: E402
|
||||
import ssl # noqa: E402
|
||||
@@ -315,6 +316,106 @@ def test_ronde_meet_niet_elke_keer(agent, u):
|
||||
server.close()
|
||||
|
||||
|
||||
def test_eerste_ronde_en_snelle_herhaling(agent, u):
|
||||
"""De startrace, en de rem die een mislukking vasthield.
|
||||
|
||||
AANLEIDING (gemeld door de gebruiker, 31-08-2026): na elke herstart of update
|
||||
las de statuskaart vijf minuten lang "Not answering" met
|
||||
`[Errno 111] Connection refused`, terwijl de gateway van buiten gewoon werkte.
|
||||
|
||||
De oorzaak was een startvolgorde en geen storing. De compose laat `server` ná
|
||||
de agent starten (`depends_on: [agent]`), en `build_status` draait meteen bij
|
||||
het opstarten. De allereerste meting valt dus gegarandeerd in het gat waarin
|
||||
nginx nog niet luistert. Dat was op zichzelf te verdragen; het probleem was dat
|
||||
de volgende meting pas na SELF_CHECK_INTERVAL kwam.
|
||||
|
||||
Twee dingen worden hier vastgelegd, en ze repareren allebei een helft:
|
||||
|
||||
1. de eerste ronde van een proces meet niet, ook niet als het certificaat
|
||||
ongewijzigd is (dus met `reloaded` op False, en dát is het geval dat de
|
||||
bestaande toets hierboven NIET raakt: daar is de eerste ronde `pending`
|
||||
omdat het certificaat net gekozen is);
|
||||
2. na een mislukking wordt er na SELF_CHECK_RETRY opnieuw gemeten en niet pas
|
||||
na SELF_CHECK_INTERVAL.
|
||||
"""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
bron = os.path.join(tmp, "certs")
|
||||
os.makedirs(bron)
|
||||
paar = openssl_paar(bron, "gate", "gate.example.org")
|
||||
if not paar:
|
||||
print("OVERGESLAGEN: geen openssl, dus de startrace is niet getoetst")
|
||||
return
|
||||
cert, key = paar
|
||||
|
||||
agent.SOURCES = [("Own folder", bron)]
|
||||
agent.ELECTRUM_HOST = ""
|
||||
agent.STATE_DIR = tmp
|
||||
agent.CONFIG_DIR = os.path.join(tmp, "config")
|
||||
agent.SELECTED_FILE = os.path.join(agent.CONFIG_DIR, "selected-cert")
|
||||
agent.STATUS_FILE = os.path.join(tmp, "status.json")
|
||||
agent.CERT_CONF = os.path.join(tmp, "cert.conf")
|
||||
agent.RELOAD_FLAG = os.path.join(tmp, "reload")
|
||||
agent.STREAM_LOG = os.path.join(tmp, "stream.log")
|
||||
agent.SESSIONS_FILE = os.path.join(tmp, "sessions")
|
||||
agent.SELF_CHECK_INTERVAL = 300
|
||||
agent.SELF_CHECK_RETRY = 60
|
||||
|
||||
server = TlsServer(cert, key)
|
||||
try:
|
||||
richt(agent, server.port)
|
||||
|
||||
def ronde():
|
||||
status = agent.build_status([])
|
||||
agent.write_status(status)
|
||||
return status
|
||||
|
||||
ronde() # certificaat gekozen: pending via reloaded
|
||||
tweede = ronde()["tls"]["self_check"]
|
||||
u.check("de meting lukt zodra het certificaat staat",
|
||||
tweede.get("state") == "ok", "gaf %r" % tweede)
|
||||
|
||||
# Nu doen alsof het proces opnieuw begint, met een ONGEWIJZIGD
|
||||
# certificaat. Vóór de reparatie mat hij hier gewoon door.
|
||||
agent.EERSTE_RONDE = True
|
||||
herstart = ronde()["tls"]["self_check"]
|
||||
u.check("de eerste ronde na een herstart meet niet",
|
||||
herstart.get("state") == "pending", "gaf %r" % herstart)
|
||||
u.check("en zonder `at`, zodat de volgende ronde wél meet",
|
||||
"at" not in herstart, "gaf %r" % herstart)
|
||||
|
||||
derde = ronde()["tls"]["self_check"]
|
||||
u.check("de ronde daarna meet wel",
|
||||
derde.get("state") == "ok", "gaf %r" % derde)
|
||||
|
||||
# De tweede helft: een mislukking mag niet vijf minuten blijven staan.
|
||||
# De opgeslagen meting met de hand op 'failed' zetten, 90 seconden oud:
|
||||
# dat is meer dan SELF_CHECK_RETRY en minder dan SELF_CHECK_INTERVAL.
|
||||
def zet_vorige(state, ouderdom):
|
||||
with open(agent.STATUS_FILE, "r", encoding="utf-8") as f:
|
||||
status = json.load(f)
|
||||
status["tls"]["self_check"] = {
|
||||
"at": int(time.time()) - ouderdom, "state": state,
|
||||
}
|
||||
with open(agent.STATUS_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(status, f)
|
||||
|
||||
zet_vorige("failed", 90)
|
||||
na_fout = ronde()["tls"]["self_check"]
|
||||
u.check("na een mislukking wordt er binnen een minuut opnieuw gemeten",
|
||||
na_fout.get("state") == "ok", "gaf %r" % na_fout)
|
||||
|
||||
# En de tegenproef, want anders toetst het bovenstaande alleen dat er
|
||||
# ooit gemeten wordt: een GESLAAGDE meting van dezelfde ouderdom hoort
|
||||
# juist te blijven staan.
|
||||
zet_vorige("ok", 90)
|
||||
na_goed = ronde()["tls"]["self_check"]
|
||||
u.check("een geslaagde meting van 90 seconden oud blijft staan",
|
||||
na_goed.get("at") == int(time.time()) - 90,
|
||||
"gaf %r" % na_goed)
|
||||
finally:
|
||||
server.close()
|
||||
|
||||
|
||||
def main():
|
||||
u = Uitslag()
|
||||
agent = load_agent()
|
||||
@@ -325,6 +426,7 @@ def main():
|
||||
test_eigen_sessies_uit_het_log(agent, u)
|
||||
# Als laatste, want deze verzet de module-instellingen naar een tijdelijke map.
|
||||
test_ronde_meet_niet_elke_keer(agent, u)
|
||||
test_eerste_ronde_en_snelle_herhaling(agent, u)
|
||||
return u.rapport()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user