#!/usr/bin/env python3 """Measure `wger` — the last unmeasured candidate in R-618. The static sweep convicts three templates and two were confirmed live (tandoor: wrong PORT; zipline: wrong PATH). `wger` is the third: its `.felhom.yml` probes `type: http, port: 80` while `wger/server` serves **8000** and the template's own traefik label says 8000. If that is right, a household running wger sees it as permanently UNHEALTHY and — worse, per tonight's escalation — a SUCCESSFUL update of it would be stopped by its own health wait. This does not walk the whole edge. It answers ONE question with a control on each side: does the container listen on the port the probe names, and what does the box then say? The app is then removed. Deliberately narrow: the point is to turn a suspicion into a fact or to clear it, not to add a fourteenth edge at midnight. """ import json, os, sys, time HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) import walk as w # noqa: E402 OUT = os.path.join(HERE, "22-wger-probe-measured.txt") APP, SUB = "wger", "fitness" def main(): w.login() lines = [] def say(s): w.say(s) lines.append(s) say("=== wger — R-618's last unmeasured candidate") say(f" template probe : type=http port=80 (.felhom.yml)") say(f" traefik label : loadbalancer.server.port=8000 (the SAME template's compose)") sub = w.guest("grep -m1 '^subdomain:' /dev/null 2>/dev/null") or "" st = w.stack(APP) if not st.get("deployed"): if not w.deploy(APP, SUB): say(" wger never came up — the candidate stays UNMEASURED, and that is the result") open(OUT, "w").write("\n".join(lines) + "\n") return # give the app time to actually serve, not merely to run w.wait_app(SUB, "/", want=("200", "302", "301"), tries=90) probe = w.guest(""" echo "--- what wger actually LISTENS on, asked inside its own container:" docker exec wger sh -c 'netstat -ltn 2>/dev/null || ss -ltn 2>/dev/null' | head -8 echo "--- the container's own docker healthcheck, if it has one:" docker inspect wger --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}(no docker healthcheck){{end}}' echo "--- port 80 from inside (the port the probe names):" docker exec wger sh -c 'wget --spider -q -T 4 http://127.0.0.1:80/ 2>&1 && echo "ANSWERED on 80" || echo "refused on 80"' echo "--- port 8000 from inside (the port the compose says):" docker exec wger sh -c 'wget --spider -q -T 4 http://127.0.0.1:8000/ 2>&1 && echo "ANSWERED on 8000" || echo "refused on 8000"' """, timeout=420) for ln in probe.strip().split("\n"): if ln.strip(): say(" " + ln) rc, code, _ = w.app_curl(SUB, "/", timeout=25) say(f" the household's own front door: http={code}") st = w.stack(APP) say(f" the box's own verdict: state={st.get('state')!r}") verdict = ("CONFIRMED DEFECT — the same shape as tandoor" if st.get("state") == "unhealthy" and code in ("200", "302", "301") else "NOT a defect on this measurement" if st.get("state") == "running" else "INCONCLUSIVE — see the lines above") say(f" VERDICT: {verdict}") open(OUT, "w").write("\n".join(lines) + "\n") w.say(f" written -> {OUT}") if st.get("deployed"): w.remove(APP) if __name__ == "__main__": main()