R-415 fixed on hub main (no duplicate/nested/felhom.eu customer domain; R-138 option B); R-762 closed (9202 proven, catalog eec9a0d); R-905 opened (wger static in backups); decision sheet D10; 130 -> 129
gates / gates (push) Successful in 3m55s
gates / gates (push) Successful in 3m55s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
# R-762 on scratch 9202 (2026-10-08, 09:50–10:09 CEST)
|
||||
|
||||
wger was installed fresh from the drill catalog (commit `bebbac8`: wger un-hidden plus the gunicorn definition, DRILL
|
||||
only; reverted as `95876a3`). The install went through the product's deploy endpoint (`tools/box9202.py install`).
|
||||
`tools/repoint.py` moved 9202's catalog setting to the drill catalog and back.
|
||||
|
||||
| check | result |
|
||||
|---|---|
|
||||
| workers | 2 × „Booting worker" (`wger.log`); env `WGER_USE_GUNICORN=True`, `WEB_CONCURRENCY=2` |
|
||||
| login page | 200 |
|
||||
| CSS (the page's 3 links, through wger-files) | 200 / 200 / 200 (2481 B, 277042 B, 1006 B, `text/css`) |
|
||||
| photo | POST `/api/v2/gallery/` 201; read back 200, 179 B, `image/png` |
|
||||
| control | an unknown `/static/` file 404 |
|
||||
| seed | a weight entry 201, read back 200 |
|
||||
| 600 s watch (10,944 requests: 8,208 × 200, 2,736 × 302) | anon peak 258,273,280 B = 246.3 MiB = 64.1 % of 384M (memory.stat `anon`, every 2 s); oom 0, oom_kill 0; restarts 0, oomkilled false, healthy (wger and wger-files) |
|
||||
| after the watch (`plateau-check.txt`) | anon 246 MiB for 1,200 more login-page loads; oom_kill 0; restarts 0 |
|
||||
|
||||
memory.peak reached the limit (402,657,280 B) because it counts the page cache (`after-watch-memory.txt`: file 22 MiB,
|
||||
kernel 49 MiB). The anon figure is what counts.
|
||||
|
||||
The bench figure was 170 MiB (44 %). The bench load was 302 redirects only. Here the load also rendered the login page
|
||||
and served a photo upload. The cause of the difference was not measured.
|
||||
|
||||
**Removal through the product** (`run.txt`): stop 200, remove (with data) 200, volumes `wger_wger_data`,
|
||||
`wger_wger_media` and `wger_wger_static` removed. Afterwards: no wger container, no wger volume, `deployed=False`.
|
||||
`/opt/docker/stacks/wger` holds only the catalog's synced `.felhom.yml` and `docker-compose.yml`. It held the same two
|
||||
files before the test, because every catalog app has this directory.
|
||||
|
||||
**Put back:** `repo_url` = `https://gitea.dooplex.hu/admin/app-catalog-felhom.eu.git`. `controller.yaml` sha256
|
||||
`7739ad7b…` is the same before and after. The save copy was deleted. Deployed apps are paperless-ngx and privatebin,
|
||||
as before.
|
||||
|
||||
The generated admin password was never written. The image's default password in `wger.log` is redacted.
|
||||
@@ -0,0 +1,14 @@
|
||||
anon 258273280
|
||||
file 23224320
|
||||
kernel 51847168
|
||||
shmem 0
|
||||
peak=402657280
|
||||
wger-files 7.48MiB / 32MiB
|
||||
wger 295.8MiB / 384MiB
|
||||
PID RSS COMMAND
|
||||
1 3804 /bin/bash /home/wger/entrypoint.sh
|
||||
58 132060 /usr/bin/python3 /home/wger/.local/bin/gunicorn wger.wsgi:application --preload --bind 0.0.0.0:8000
|
||||
59 127124 /usr/bin/python3 /home/wger/.local/bin/gunicorn wger.wsgi:application --preload --bind 0.0.0.0:8000
|
||||
60 121560 /usr/bin/python3 /home/wger/.local/bin/gunicorn wger.wsgi:application --preload --bind 0.0.0.0:8000
|
||||
464 4316 ps -o pid,rss,args
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"app": "wger",
|
||||
"venue": "scratch guest 9202 on demo-hp, drill catalog, the product's deploy endpoint",
|
||||
"drill_commit": "bebbac8 DRILL wger: un-hidden + the R-762 gunicorn definition (DRILL only, 2026-10-08)",
|
||||
"pinned": {
|
||||
"wger": "wger/server:2.7",
|
||||
"wger-files": "nginx:1.30.5-alpine"
|
||||
},
|
||||
"seed_read": true,
|
||||
"login_page": "200",
|
||||
"css": {
|
||||
"/static/css/workout-manager.7007d84ce531.css": "200 2481 text/css",
|
||||
"/static/bootstrap-compiled.80a6279921f8.css": "200 277042 text/css",
|
||||
"/static/css/bootstrap-custom.400ad578123c.css": "200 1006 text/css"
|
||||
},
|
||||
"photo_post": "201",
|
||||
"photo_bytes_posted": 179,
|
||||
"photo_path": "/media/gallery/1/f3391508-f895-4fc4-9688-7a42dc158932.png",
|
||||
"photo_read": "200 179 image/png",
|
||||
"control_unknown_static": "404 153 text/html",
|
||||
"container": "cgroup=/sys/fs/cgroup/system.slice/docker-42589be792575b34221f0ff8ab0141f576e21db37a1ce1a4214e7e3385e1da46.scope\nWGER_USE_GUNICORN=True\nWEB_CONCURRENCY=2\nUsing gunicorn on port 8000...\n[2026-10-08 09:54:38 +0200] [58] [INFO] Starting gunicorn 26.1.0\n[2026-10-08 09:54:38 +0200] [58] [INFO] Listening at: http://0.0.0.0:8000 (58)\n[2026-10-08 09:54:38 +0200] [59] [INFO] Booting worker with pid: 59\n[2026-10-08 09:54:38 +0200] [60] [INFO] Booting worker with pid: 60\n402653184\n",
|
||||
"watch_s": 600.1,
|
||||
"watch_requests": 10944,
|
||||
"watch_codes": {
|
||||
"200": 8208,
|
||||
"302": 2736
|
||||
},
|
||||
"watch": "anon_max=258273280\nmemory.max=402653184\noom 0\noom_kill 0\nrestarts=0 oomkilled=false status=running health=healthy started=2026-10-08T07:53:22.480653193Z\nrestarts=0 oomkilled=false status=running health=healthy started=2026-10-08T07:53:22.678387772Z\n2\n",
|
||||
"anon_max_bytes": 258273280,
|
||||
"anon_max_mib": 246.3,
|
||||
"anon_pct_of_384M": 64.1
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
08:06:00 round=1 gets=100 anon_MiB=246
|
||||
08:06:05 round=2 gets=100 anon_MiB=246
|
||||
08:06:10 round=3 gets=100 anon_MiB=246
|
||||
08:06:14 round=4 gets=100 anon_MiB=246
|
||||
08:06:19 round=5 gets=100 anon_MiB=246
|
||||
08:06:23 round=6 gets=100 anon_MiB=246
|
||||
08:06:28 round=7 gets=100 anon_MiB=246
|
||||
08:06:32 round=8 gets=100 anon_MiB=246
|
||||
08:06:37 round=9 gets=100 anon_MiB=246
|
||||
08:06:41 round=10 gets=100 anon_MiB=246
|
||||
08:06:46 round=11 gets=100 anon_MiB=246
|
||||
08:06:50 round=12 gets=100 anon_MiB=246
|
||||
oom_kill 0
|
||||
restarts=0
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
09:50:14 drill: bebbac8 DRILL wger: un-hidden + the R-762 gunicorn definition (DRILL only, 2026-10-08)
|
||||
09:52:49 synced template on the box: 2 18:lifecycle: available
|
||||
09:54:56 wger: POST /api/v2/weightentry/ http=201
|
||||
09:54:56 wger: readback of the seeded weight entry http=200 found=True
|
||||
09:54:56 login page -> 200; CSS {'/static/css/workout-manager.7007d84ce531.css': '200 2481 text/css', '/static/bootstrap-compiled.80a6279921f8.css': '200 277042 text/css', '/static/css/bootstrap-custom.400ad578123c.css': '200 1006 text/css'}
|
||||
09:54:57 POST /api/v2/gallery/ (179 B PNG) -> 201; read back /media/gallery/1/f3391508-f895-4fc4-9688-7a42dc158932.png -> 200 179 image/png; control -> 404 153 text/html
|
||||
09:55:00 container:
|
||||
cgroup=/sys/fs/cgroup/system.slice/docker-42589be792575b34221f0ff8ab0141f576e21db37a1ce1a4214e7e3385e1da46.scope
|
||||
WGER_USE_GUNICORN=True
|
||||
WEB_CONCURRENCY=2
|
||||
Using gunicorn on port 8000...
|
||||
[2026-10-08 09:54:38 +0200] [58] [INFO] Starting gunicorn 26.1.0
|
||||
[2026-10-08 09:54:38 +0200] [58] [INFO] Listening at: http://0.0.0.0:8000 (58)
|
||||
[2026-10-08 09:54:38 +0200] [59] [INFO] Booting worker with pid: 59
|
||||
[2026-10-08 09:54:38 +0200] [60] [INFO] Booting worker with pid: 60
|
||||
402653184
|
||||
|
||||
10:05:10 watch:
|
||||
anon_max=258273280
|
||||
memory.max=402653184
|
||||
oom 0
|
||||
oom_kill 0
|
||||
restarts=0 oomkilled=false status=running health=healthy started=2026-10-08T07:53:22.480653193Z
|
||||
restarts=0 oomkilled=false status=running health=healthy started=2026-10-08T07:53:22.678387772Z
|
||||
2
|
||||
|
||||
10:05:13 RECORD {"app": "wger", "venue": "scratch guest 9202 on demo-hp, drill catalog, the product's deploy endpoint", "drill_commit": "bebbac8 DRILL wger: un-hidden + the R-762 gunicorn definition (DRILL only, 2026-10-08)", "pinned": {"wger": "wger/server:2.7", "wger-files": "nginx:1.30.5-alpine"}, "seed_read": true, "login_page": "200", "css": {"/static/css/workout-manager.7007d84ce531.css": "200 2481 text/css", "/static/bootstrap-compiled.80a6279921f8.css": "200 277042 text/css", "/static/css/bootstrap-custom.400ad578123c.css": "200 1006 text/css"}, "photo_post": "201", "photo_bytes_posted": 179, "photo_path": "/media/gallery/1/f3391508-f895-4fc4-9688-7a42dc158932.png", "photo_read": "200 179 image/png", "control_unknown_static": "404 153 text/html", "watch_s": 600.1, "watch_requests": 10944, "watch_codes": {"200": 8208, "302": 2736}, "anon_max_bytes": 258273280, "anon_max_mib": 246.3, "anon_pct_of_384M": 64.1}
|
||||
10:07:50 remove -> 200
|
||||
10:07:53 after remove:
|
||||
vols:
|
||||
stackdir:
|
||||
total 28
|
||||
drwxr-xr-x 2 root root 4096 Oct 8 08:07 .
|
||||
drwxr-xr-x 65 root root 4096 Oct 2 05:49 ..
|
||||
-rw-r--r-- 1 root root 7619 Oct 8 07:50 .felhom.yml
|
||||
-rw-r--r-- 1 root root 8672 Oct 8 07:50 docker-compose.yml
|
||||
end
|
||||
|
||||
10:07:53 stack: deployed=False state=not_deployed
|
||||
@@ -0,0 +1,30 @@
|
||||
09:50:14 drill: bebbac8 DRILL wger: un-hidden + the R-762 gunicorn definition (DRILL only, 2026-10-08)
|
||||
09:52:49 synced template on the box: 2 18:lifecycle: available
|
||||
09:52:49 [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['ADMIN_PASSWORD']
|
||||
09:52:50 [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
|
||||
09:54:55 [1] deployed, controller state=running, pinned={'wger': 'wger/server:2.7', 'wger-files': 'nginx:1.30.5-alpine'}
|
||||
09:54:56 wger: POST /api/v2/weightentry/ http=201
|
||||
09:54:56 wger: readback of the seeded weight entry http=200 found=True
|
||||
09:54:56 login page -> 200; CSS {'/static/css/workout-manager.7007d84ce531.css': '200 2481 text/css', '/static/bootstrap-compiled.80a6279921f8.css': '200 277042 text/css', '/static/css/bootstrap-custom.400ad578123c.css': '200 1006 text/css'}
|
||||
09:54:57 POST /api/v2/gallery/ (179 B PNG) -> 201; read back /media/gallery/1/f3391508-f895-4fc4-9688-7a42dc158932.png -> 200 179 image/png; control -> 404 153 text/html
|
||||
09:55:00 container:
|
||||
cgroup=/sys/fs/cgroup/system.slice/docker-42589be792575b34221f0ff8ab0141f576e21db37a1ce1a4214e7e3385e1da46.scope
|
||||
WGER_USE_GUNICORN=True
|
||||
WEB_CONCURRENCY=2
|
||||
Using gunicorn on port 8000...
|
||||
[2026-10-08 09:54:38 +0200] [58] [INFO] Starting gunicorn 26.1.0
|
||||
[2026-10-08 09:54:38 +0200] [58] [INFO] Listening at: http://0.0.0.0:8000 (58)
|
||||
[2026-10-08 09:54:38 +0200] [59] [INFO] Booting worker with pid: 59
|
||||
[2026-10-08 09:54:38 +0200] [60] [INFO] Booting worker with pid: 60
|
||||
402653184
|
||||
|
||||
10:05:10 watch:
|
||||
anon_max=258273280
|
||||
memory.max=402653184
|
||||
oom 0
|
||||
oom_kill 0
|
||||
restarts=0 oomkilled=false status=running health=healthy started=2026-10-08T07:53:22.480653193Z
|
||||
restarts=0 oomkilled=false status=running health=healthy started=2026-10-08T07:53:22.678387772Z
|
||||
2
|
||||
|
||||
10:05:13 RECORD {"app": "wger", "venue": "scratch guest 9202 on demo-hp, drill catalog, the product's deploy endpoint", "drill_commit": "bebbac8 DRILL wger: un-hidden + the R-762 gunicorn definition (DRILL only, 2026-10-08)", "pinned": {"wger": "wger/server:2.7", "wger-files": "nginx:1.30.5-alpine"}, "seed_read": true, "login_page": "200", "css": {"/static/css/workout-manager.7007d84ce531.css": "200 2481 text/css", "/static/bootstrap-compiled.80a6279921f8.css": "200 277042 text/css", "/static/css/bootstrap-custom.400ad578123c.css": "200 1006 text/css"}, "photo_post": "201", "photo_bytes_posted": 179, "photo_path": "/media/gallery/1/f3391508-f895-4fc4-9688-7a42dc158932.png", "photo_read": "200 179 image/png", "control_unknown_static": "404 153 text/html", "watch_s": 600.1, "watch_requests": 10944, "watch_codes": {"200": 8208, "302": 2736}, "anon_max_bytes": 258273280, "anon_max_mib": 246.3, "anon_pct_of_384M": 64.1}
|
||||
@@ -0,0 +1,152 @@
|
||||
"""box9202.py — R-762 9202 half (2026-10-08 afternoon). ONE process, through the product.
|
||||
phase install: drill commit (wger un-hidden + the gunicorn definition, DRILL only), sync, deploy, seed, login page,
|
||||
CSS, photo, workers, env; then a ~10-minute watch (anon from memory.stat, oom_kill, restarts) with light load.
|
||||
The removal is a separate phase (remove) so a failure leaves something to look at.
|
||||
Evidence -> $EVD (no secrets: the generated admin password is never written)."""
|
||||
import json, os, re, struct, subprocess, sys, tempfile, time, zlib, secrets
|
||||
sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts")
|
||||
import box_walk as w
|
||||
import upgrade_fixtures_box as fixtures
|
||||
|
||||
APP, SUB = "wger", "fitness"
|
||||
EVD = os.environ["EVD"]; os.makedirs(EVD, exist_ok=True)
|
||||
log = open(f"{EVD}/run.txt", "a", buffering=1)
|
||||
D = "/mnt/5_hdd/felhom.eu/drill/app-catalog-drill"
|
||||
NEWC = "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/templates/wger/docker-compose.yml"
|
||||
REC = {"app": APP, "venue": "scratch guest 9202 on demo-hp, drill catalog, the product's deploy endpoint"}
|
||||
|
||||
|
||||
def say(*a):
|
||||
w.say(*a); log.write(time.strftime("%H:%M:%S ") + " ".join(map(str, a)) + "\n")
|
||||
|
||||
|
||||
def git(*a):
|
||||
return subprocess.run(["git", "-C", D, *a], check=True, capture_output=True, text=True).stdout
|
||||
|
||||
|
||||
def png(path, n=64):
|
||||
rgb = secrets.token_bytes(3)
|
||||
raw = b"".join(b"\x00" + rgb * n for _ in range(n))
|
||||
def chunk(t, d):
|
||||
return struct.pack(">I", len(d)) + t + d + struct.pack(">I", zlib.crc32(t + d) & 0xffffffff)
|
||||
data = (b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", n, n, 8, 2, 0, 0, 0))
|
||||
+ chunk(b"IDAT", zlib.compress(raw)) + chunk(b"IEND", b""))
|
||||
open(path, "wb").write(data)
|
||||
return len(data)
|
||||
|
||||
|
||||
def fetch(path):
|
||||
"""code, bytes, content-type of one GET through the household's route (traefik, gate cookie). Body discarded."""
|
||||
gc = w.GATE.get(SUB) or w.gate_cookie(SUB)
|
||||
args = ["curl", "-sSk", "--max-time", "45", "-H", f"Host: {SUB}.{w.DOMAIN}", "-o", "/dev/null",
|
||||
"-w", "%{http_code} %{size_download} %{content_type}"]
|
||||
if gc:
|
||||
args += ["-H", f"Cookie: {gc}"]
|
||||
r = w.sh(args + [f"{w.BASE}{path}"], timeout=90)
|
||||
return (r.stdout or "").strip()
|
||||
|
||||
|
||||
def css_links():
|
||||
rc, code, page = w.app_curl(SUB, "/en/user/login")
|
||||
links = re.findall(r'(/static/[^"]+\.css)', page or "")[:3]
|
||||
return code, {l: fetch(l) for l in links}
|
||||
|
||||
|
||||
CG = 'ID=$(docker inspect -f "{{.Id}}" wger); CG=$(find /sys/fs/cgroup -maxdepth 6 -type d -name "*$ID*" | head -1)'
|
||||
|
||||
phase = sys.argv[1]
|
||||
w.login()
|
||||
if phase == "install":
|
||||
if w.stack(APP).get("deployed"):
|
||||
sys.exit(say("STOP: wger already deployed on 9202 — not this run's") or 1)
|
||||
git("pull", "-q", "--rebase", "origin", "main")
|
||||
fy = f"{D}/templates/{APP}/.felhom.yml"
|
||||
s = open(fy).read()
|
||||
open(fy, "w").write(s.replace("lifecycle: hidden", "lifecycle: available", 1))
|
||||
open(f"{D}/templates/{APP}/docker-compose.yml", "w").write(open(NEWC).read())
|
||||
git("add", f"templates/{APP}/.felhom.yml", f"templates/{APP}/docker-compose.yml")
|
||||
git("commit", "-q", "-m", "DRILL wger: un-hidden + the R-762 gunicorn definition (DRILL only, 2026-10-08)")
|
||||
git("push", "-q", "origin", "main")
|
||||
REC["drill_commit"] = git("log", "--oneline", "-1").strip()
|
||||
say("drill:", REC["drill_commit"])
|
||||
for _ in range(12):
|
||||
w.sync_rescan(); time.sleep(5)
|
||||
stk = w.guest(f"grep -c WGER_USE_GUNICORN /opt/docker/stacks/{APP}/docker-compose.yml; grep -n lifecycle /opt/docker/stacks/{APP}/.felhom.yml").split()
|
||||
if stk and stk[0] == "1" and "available" in " ".join(stk):
|
||||
break
|
||||
say("synced template on the box:", " ".join(stk))
|
||||
if not w.deploy(APP, SUB):
|
||||
sys.exit(say("RESULT the install did not complete") or 1)
|
||||
REC["pinned"] = (w.stack(APP).get("app_config") or {}).get("pinned_images")
|
||||
fx = fixtures.FIXTURES[APP]
|
||||
tok = fx.seed(w, SUB, say)
|
||||
if tok is None:
|
||||
sys.exit(say(f"RESULT seed failed: {getattr(fx, 'tried', '')}") or 1)
|
||||
REC["seed_read"] = fx.verify(w, SUB, tok, say)
|
||||
REC["login_page"], REC["css"] = css_links()
|
||||
say(f"login page -> {REC['login_page']}; CSS {REC['css']}")
|
||||
jar = tempfile.mktemp(prefix="wger-jar-")
|
||||
hdr, why = fx._login(w, SUB, tok["pw"], jar)
|
||||
pic = tempfile.mktemp(prefix="wger-photo-", suffix=".png")
|
||||
size = png(pic)
|
||||
rc, code, out = w.app_curl(SUB, "/api/v2/gallery/", *hdr, "-F", f"image=@{pic};type=image/png", "-F",
|
||||
"date=2026-10-08", "-F", "description=r762", method="POST")
|
||||
img = None
|
||||
try:
|
||||
img = json.loads(out).get("image")
|
||||
except Exception:
|
||||
say(f" gallery body {out[:200]}")
|
||||
path = re.sub(r"^https?://[^/]+", "", img or "")
|
||||
REC["photo_post"] = code; REC["photo_bytes_posted"] = size; REC["photo_path"] = path
|
||||
REC["photo_read"] = fetch(path) if path else None
|
||||
REC["control_unknown_static"] = fetch("/static/r762-nonexistent.css")
|
||||
say(f"POST /api/v2/gallery/ ({size} B PNG) -> {code}; read back {path} -> {REC['photo_read']}; control -> {REC['control_unknown_static']}")
|
||||
for f in (jar, pic):
|
||||
if os.path.exists(f):
|
||||
os.unlink(f)
|
||||
g = w.guest(CG + '''
|
||||
echo "cgroup=$CG"
|
||||
docker exec wger sh -c 'env | grep -E "^(WGER_USE_GUNICORN|WEB_CONCURRENCY)="'
|
||||
docker logs wger 2>&1 | grep -E "Using gunicorn|Using django|Booting worker|Listening at|Starting gunicorn|Starting development server"
|
||||
cat $CG/memory.max''')
|
||||
say("container:\n" + g)
|
||||
REC["container"] = g
|
||||
# the watch: ~10 min, anon sampled every 2 s in the guest; light load from here (login page + CSS + photo)
|
||||
w.guest(CG + '''
|
||||
rm -f /root/r762w.*; touch /root/r762w.on
|
||||
nohup sh -c 'max=0; while [ -f /root/r762w.on ]; do a=$(awk "\\$1==\\"anon\\"{print \\$2}" '"$CG"'/memory.stat 2>/dev/null); [ -n "$a" ] && [ "$a" -gt "$max" ] && max=$a && echo $max > /root/r762w.max; sleep 2; done' >/dev/null 2>&1 &
|
||||
echo started''')
|
||||
t0 = time.time(); n = 0; codes = {}
|
||||
while time.time() - t0 < 600:
|
||||
for p in ("/en/user/login", list(REC["css"])[0] if REC["css"] else "/en/user/login", path or "/en/user/login"):
|
||||
c = fetch(p).split(" ")[0]; codes[c] = codes.get(c, 0) + 1; n += 1
|
||||
rc, c, _ = w.app_curl(SUB, "/en/dashboard"); codes[c] = codes.get(c, 0) + 1; n += 1
|
||||
REC["watch_s"] = round(time.time() - t0, 1); REC["watch_requests"] = n; REC["watch_codes"] = codes
|
||||
g = w.guest(CG + '''
|
||||
rm -f /root/r762w.on; sleep 3
|
||||
echo "anon_max=$(cat /root/r762w.max)"
|
||||
echo "memory.max=$(cat $CG/memory.max)"
|
||||
grep -E "^(oom|oom_kill) " $CG/memory.events
|
||||
docker inspect -f "restarts={{.RestartCount}} oomkilled={{.State.OOMKilled}} status={{.State.Status}} health={{.State.Health.Status}} started={{.State.StartedAt}}" wger wger-files
|
||||
docker logs wger 2>&1 | grep -c "Booting worker"
|
||||
rm -f /root/r762w.*''')
|
||||
say("watch:\n" + g)
|
||||
REC["watch"] = g
|
||||
m = re.search(r"anon_max=(\d+)", g)
|
||||
if m:
|
||||
a = int(m.group(1)); REC["anon_max_bytes"] = a
|
||||
REC["anon_max_mib"] = round(a / 1048576, 1); REC["anon_pct_of_384M"] = round(100 * a / (384 * 1048576), 1)
|
||||
logs = w.guest("docker logs wger 2>&1 | tail -n 300")
|
||||
pw = tok.get("pw") or ""
|
||||
if pw:
|
||||
logs = logs.replace(pw, "<generated, redacted>")
|
||||
open(f"{EVD}/wger.log", "w").write(logs)
|
||||
json.dump(REC, open(f"{EVD}/box-verdict-wger.json", "w"), indent=2, ensure_ascii=False)
|
||||
say("RECORD", json.dumps({k: REC[k] for k in REC if k not in ("container", "watch")}, ensure_ascii=False))
|
||||
elif phase == "remove":
|
||||
say(f"remove -> {w.remove(APP)}")
|
||||
g = w.guest("docker ps -a --format '{{.Names}}' | grep -i wger; echo vols:; docker volume ls --format '{{.Name}}' | grep -i wger; "
|
||||
"echo stackdir:; ls -la /opt/docker/stacks/wger; echo end")
|
||||
say("after remove:\n" + g)
|
||||
st = w.stack(APP)
|
||||
say(f"stack: deployed={st.get('deployed')} state={st.get('state')}")
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Point 9202 at the drill catalog, or put the saved controller.yaml back. `09` §6.5."""
|
||||
import io, os, re, sys
|
||||
sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts")
|
||||
import box_walk as w
|
||||
VOL = "/var/lib/docker/volumes/felhom-controller-data/_data"
|
||||
SAVE = f"{VOL}/controller.yaml.pre-r762-1008"
|
||||
DRILL = "https://gitea.dooplex.hu/admin/app-catalog-drill.git"
|
||||
def creds():
|
||||
for l in io.open(os.path.expanduser("~/.git-credentials")).read().split("\n"):
|
||||
m = re.match(r"https://(admin):([^@]+)@gitea\.dooplex\.hu", l)
|
||||
if m: return m.group(1), m.group(2)
|
||||
sys.exit("no admin credential")
|
||||
if sys.argv[1] == "drill":
|
||||
u, t = creds()
|
||||
out = w.guest(f"""set -e
|
||||
cp -p {VOL}/controller.yaml {SAVE}
|
||||
python3 - <<'PY'
|
||||
import re
|
||||
p = "{VOL}/controller.yaml"; s = open(p).read()
|
||||
s = re.sub(r'(^\\s+repo_url: ).*$', r'\\g<1>{DRILL}', s, count=1, flags=re.M)
|
||||
s = re.sub(r'(^git:(?:\\n\\s+.*)*?\\n\\s+token: ).*$', r'\\g<1>"{t}"', s, count=1, flags=re.M)
|
||||
s = re.sub(r'(^git:(?:\\n\\s+.*)*?\\n\\s+username: ).*$', r'\\g<1>"{u}"', s, count=1, flags=re.M)
|
||||
open(p, "w").write(s)
|
||||
PY
|
||||
rm -rf {VOL}/catalog-cache {VOL}/data/catalog-cache
|
||||
docker restart felhom-controller >/dev/null
|
||||
grep -n 'repo_url' {VOL}/controller.yaml
|
||||
""")
|
||||
print(out.replace(t, "<token>"))
|
||||
elif sys.argv[1] == "restore":
|
||||
print(w.guest(f"""set -e
|
||||
cp -p {SAVE} {VOL}/controller.yaml
|
||||
rm -rf {VOL}/catalog-cache {VOL}/data/catalog-cache
|
||||
docker restart felhom-controller >/dev/null
|
||||
grep -n 'repo_url' {VOL}/controller.yaml; grep -c 'token: ""' {VOL}/controller.yaml || true
|
||||
cmp {SAVE} {VOL}/controller.yaml && echo RESTORED-IDENTICAL"""))
|
||||
@@ -0,0 +1,300 @@
|
||||
Applying allauth_idp_oidc.0001_initial... OK
|
||||
Applying allauth_idp_oidc.0002_client_default_scopes... OK
|
||||
Applying allauth_idp_oidc.0003_client_allow_uri_wildcards... OK
|
||||
Applying contenttypes.0002_remove_content_type_name... OK
|
||||
Applying auth.0002_alter_permission_name_max_length... OK
|
||||
Applying auth.0003_alter_user_email_max_length... OK
|
||||
Applying auth.0004_alter_user_username_opts... OK
|
||||
Applying auth.0005_alter_user_last_login_null... OK
|
||||
Applying auth.0006_require_contenttypes_0002... OK
|
||||
Applying auth.0007_alter_validators_add_error_messages... OK
|
||||
Applying auth.0008_alter_user_username_max_length... OK
|
||||
Applying auth.0009_alter_user_last_name_max_length... OK
|
||||
Applying auth.0010_alter_group_name_max_length... OK
|
||||
Applying auth.0011_update_proxy_permissions... OK
|
||||
Applying auth.0012_alter_user_first_name_max_length... OK
|
||||
Applying authtoken.0001_initial... OK
|
||||
Applying authtoken.0002_auto_20160226_1747... OK
|
||||
Applying authtoken.0003_tokenproxy... OK
|
||||
Applying authtoken.0004_alter_tokenproxy_options... OK
|
||||
Applying axes.0001_initial... OK
|
||||
Applying axes.0002_auto_20151217_2044... OK
|
||||
Applying axes.0003_auto_20160322_0929... OK
|
||||
Applying axes.0004_auto_20181024_1538... OK
|
||||
Applying axes.0005_remove_accessattempt_trusted... OK
|
||||
Applying axes.0006_remove_accesslog_trusted... OK
|
||||
Applying axes.0007_alter_accessattempt_unique_together... OK
|
||||
Applying axes.0008_accessfailurelog... OK
|
||||
Applying axes.0009_add_session_hash... OK
|
||||
Applying axes.0010_accessattemptexpiration... OK
|
||||
Applying gym.0001_initial... OK
|
||||
Applying core.0001_initial... OK
|
||||
Applying config.0001_initial... OK
|
||||
Applying config.0002_auto_20190618_1617... OK
|
||||
Applying config.0003_delete_languageconfig... OK
|
||||
Applying sessions.0001_initial... OK
|
||||
Applying weight.0001_initial... OK
|
||||
Applying weight.0002_auto_20150604_2139... OK
|
||||
Applying weight.0003_auto_20160416_1030... OK
|
||||
Applying weight.0004_multiple_weight_entries_per_day... OK
|
||||
Applying weight.0005_add_uuid... OK
|
||||
Applying nutrition.0001_initial... OK
|
||||
Applying nutrition.0002_auto_20170101_1538... OK
|
||||
Applying nutrition.0003_auto_20170118_2308... OK
|
||||
Applying nutrition.0004_auto_20200819_2310... OK
|
||||
Applying nutrition.0005_logitem... OK
|
||||
Applying nutrition.0006_auto_20201201_0653... OK
|
||||
Applying nutrition.0007_auto_20201214_0013... OK
|
||||
Applying nutrition.0008_auto_20210102_1446... OK
|
||||
Applying nutrition.0009_meal_name... OK
|
||||
Applying nutrition.0010_logitem_meal... OK
|
||||
Applying nutrition.0011_alter_logitem_datetime... OK
|
||||
Applying nutrition.0012_alter_ingredient_license_author... OK
|
||||
Applying gym.0002_auto_20151003_1944... OK
|
||||
Applying gym.0003_auto_20151003_2008... OK
|
||||
Applying gym.0004_auto_20151003_2357... OK
|
||||
Applying gym.0005_auto_20151023_1522... OK
|
||||
Applying gym.0006_auto_20160214_1013... OK
|
||||
Applying gym.0007_auto_20170123_0920... OK
|
||||
Applying gym.0008_auto_20190618_1617... OK
|
||||
Applying exercises.0001_initial... OK
|
||||
Applying manager.0001_initial... OK
|
||||
Applying manager.0002_auto_20150202_2040... OK
|
||||
Applying manager.0004_auto_20150609_1603... OK
|
||||
Applying core.0002_auto_20141225_1512... OK
|
||||
Applying core.0003_auto_20150217_1554... OK
|
||||
Applying core.0004_auto_20150217_1914... OK
|
||||
Applying core.0005_auto_20151025_2236... OK
|
||||
Applying core.0006_auto_20151025_2237... OK
|
||||
Applying core.0007_repetitionunit... OK
|
||||
Applying core.0008_weightunit... OK
|
||||
Applying core.0009_auto_20160303_2340... OK
|
||||
Applying core.0010_auto_20170403_0144... OK
|
||||
Applying core.0011_auto_20201201_0653... OK
|
||||
Applying core.0012_auto_20210210_1228... OK
|
||||
Applying core.0013_auto_20210726_1729... OK
|
||||
Applying nutrition.0013_ingredient_image... OK
|
||||
Applying nutrition.0014_license_information... OK
|
||||
Applying nutrition.0015_alter_ingredient_creation_date_and_more... OK
|
||||
Applying nutrition.0016_alter_logitem_options_and_more... OK
|
||||
Applying nutrition.0017_remove_nutritionplan_language_alter_logitem_meal... OK
|
||||
Applying nutrition.0018_nutritionplan_goal_carbs_nutritionplan_goal_energy_and_more... OK
|
||||
Applying nutrition.0019_alter_image_license_author_and_more... OK
|
||||
Applying nutrition.0020_full_text_search... OK
|
||||
Applying nutrition.0021_add_fibers_field... OK
|
||||
Applying nutrition.0022_add_remote_id_increase_author_field_length... OK
|
||||
Applying nutrition.0023_fiber_spelling... OK
|
||||
Applying nutrition.0024_remove_ingredient_status... OK
|
||||
Applying nutrition.0025_add_last_image_check... OK
|
||||
Applying nutrition.0026_add_start_and_end_fields... OK
|
||||
Applying nutrition.0027_prefill_end_date... OK
|
||||
Applying nutrition.0028_ingredient_dietary_properties... OK
|
||||
Applying nutrition.0029_ingredient_nutriscore... OK
|
||||
Applying manager.0005_auto_20160303_2008... OK
|
||||
Applying manager.0006_auto_20160303_2138... OK
|
||||
Applying manager.0007_auto_20160311_2258... OK
|
||||
Applying manager.0008_auto_20190618_1617... OK
|
||||
Applying manager.0009_auto_20201202_1559... OK
|
||||
Applying manager.0010_auto_20210102_1446... OK
|
||||
Applying manager.0011_remove_set_exercises... OK
|
||||
Applying manager.0012_auto_20210430_1449... OK
|
||||
Applying manager.0013_set_comment... OK
|
||||
Applying manager.0014_auto_20210717_1858... OK
|
||||
Applying manager.0015_auto_20211028_1113... OK
|
||||
Applying exercises.0002_auto_20150307_1841... OK
|
||||
Applying exercises.0003_auto_20160921_2000... OK
|
||||
Applying exercises.0004_auto_20170404_0114... OK
|
||||
Applying exercises.0005_auto_20190618_1617... OK
|
||||
Applying exercises.0006_auto_20201203_0203... OK
|
||||
Applying exercises.0007_auto_20201203_1042... OK
|
||||
Applying exercises.0008_exercisebase... OK
|
||||
Applying exercises.0009_auto_20201211_0139... OK
|
||||
Applying exercises.0010_auto_20201211_0205... OK
|
||||
Applying exercises.0011_auto_20201214_0033... OK
|
||||
Applying exercises.0012_auto_20210327_1219... OK
|
||||
Applying exercises.0013_auto_20210503_1232... OK
|
||||
Applying exercises.0014_exerciseimage_style... OK
|
||||
Applying exercises.0015_exercise_videos... OK
|
||||
Applying exercises.0016_exercisealias... OK
|
||||
Applying exercises.0017_muscle_name_en... OK
|
||||
Applying core.0013_userprofile_email_verified... OK
|
||||
Applying core.0014_merge_20210818_1735... OK
|
||||
Applying exercises.0018_delete_pending_exercises... OK
|
||||
Applying exercises.0019_exercise_crowdsourcing_changes... OK
|
||||
Applying manager.0016_move_to_exercise_base... OK
|
||||
Applying manager.0017_alter_workoutlog_exercise_base... OK
|
||||
Applying exercises.0020_historicalexerciseimage_historicalexercisevideo... OK
|
||||
Applying exercises.0021_deletionlog... OK
|
||||
Applying exercises.0022_alter_exercise_license_author_and_more... OK
|
||||
Applying exercises.0023_make_uuid_unique... OK
|
||||
Applying exercises.0024_license_information... OK
|
||||
Applying exercises.0025_rename_update_date_exercise_last_update_and_more... OK
|
||||
Applying exercises.0026_deletionlog_replaced_by... OK
|
||||
Applying exercises.0027_alter_deletionlog_replaced_by_and_more... OK
|
||||
Applying exercises.0028_add_uuid_alias_and_comments... OK
|
||||
Applying exercises.0029_full_text_search... OK
|
||||
Applying exercises.0030_increase_author_field_length... OK
|
||||
Applying exercises.0032_rename_exercise... OK
|
||||
Applying core.0015_alter_language_short_name... OK
|
||||
Applying core.0016_alter_language_short_name... OK
|
||||
Applying manager.0018_flexible_routines... OK
|
||||
Applying manager.0019_flexible_routines_migration... OK
|
||||
Applying manager.0021_flexible_routines_cleanup... OK
|
||||
Applying core.0017_language_full_name_en... OK
|
||||
Applying core.0018_rounding... OK
|
||||
Applying core.0019_delete_daysofweek... OK
|
||||
Applying core.0020_add_trophies_enabled_to_userprofile... OK
|
||||
Applying core.0021_add_unit_type_to_repetitionunit... OK
|
||||
Applying nutrition.0030_add_indices... OK
|
||||
Applying nutrition.0031_start_weight_unit_merge... OK
|
||||
Applying nutrition.0032_continue_weight_unit_merge... OK
|
||||
Applying nutrition.0033_finalize_weight_unit_merge... OK
|
||||
Applying nutrition.0034_ingredient_trigram_gin_index... OK
|
||||
Applying nutrition.0035_add_uuids... OK
|
||||
Applying nutrition.0036_alter_image_license_author_and_more... OK
|
||||
Applying nutrition.0037_powersync_synced_ingredient_tables... OK
|
||||
Applying measurements.0001_initial... OK
|
||||
Applying measurements.0002_auto_20210722_1042... OK
|
||||
Applying measurements.0003_alter_measurement_unique_together_and_more... OK
|
||||
Applying measurements.0004_add_uuids... OK
|
||||
Applying measurements.0005_alter_measurement_date... OK
|
||||
Applying trophies.0001_initial... OK
|
||||
Applying trophies.0002_load_initial_trophies... OK
|
||||
Applying manager.0022_alter_rir_type... OK
|
||||
Applying manager.0023_change_validators... OK
|
||||
Applying manager.0024_log_and_session_uuid... OK
|
||||
Applying manager.0025_change_pk_to_uuid... OK
|
||||
Applying trophies.0003_migrate_context_data_uuids... OK
|
||||
Applying manager.0026_change_pk_to_uuid_swap... OK
|
||||
Applying core.0022_move_email_verified_to_emailaddress... OK
|
||||
Applying core.0023_create_publication... OK
|
||||
Applying manager.0027_cleanup_fields... OK
|
||||
Applying manager.0028_backfill_session_day... OK
|
||||
Applying gallery.0001_initial... OK
|
||||
Applying exercises.0033_uniqueness_constraint_translations... OK
|
||||
Applying exercises.0034_add_exercise_image_dimensions... OK
|
||||
Applying exercises.0035_add_is_ai_generated... OK
|
||||
Applying exercises.0036_add_markdown_description_field... OK
|
||||
Applying exercises.0037_replace_variation_with_uuid_field... OK
|
||||
Applying exercises.0038_sync_model_changes... OK
|
||||
Applying exercises.0039_translation_alias_trigram_gin_index... OK
|
||||
Applying exercises.0040_alter_exercise_license_author_and_more... OK
|
||||
Applying core.0024_backfill_emailaddress... OK
|
||||
Applying core.0025_remove_unused_fields_in_userprofile... OK
|
||||
Applying core.0026_alter_userprofile_birthdate_alter_userprofile_height... OK
|
||||
Applying core.0027_powersync_publication... OK
|
||||
Applying core.0028_longlivedsession... OK
|
||||
Applying core.0029_userprofile_timezone... OK
|
||||
Applying easy_thumbnails.0001_initial... OK
|
||||
Applying easy_thumbnails.0002_thumbnaildimensions... OK
|
||||
Applying mailer.0001_initial... OK
|
||||
Applying mailer.0002_auto_20190618_1617... OK
|
||||
Applying mailer.0003_auto_20201201_0653... OK
|
||||
Applying manager.0029_alter_workoutsession_options_and_more... OK
|
||||
Applying measurements.0006_health_sync... OK
|
||||
Applying measurements.0007_migrate_weight... OK
|
||||
Applying measurements.0008_dynamic_type... OK
|
||||
Applying mfa.0001_initial... OK
|
||||
Applying mfa.0002_authenticator_timestamps... OK
|
||||
Applying mfa.0003_authenticator_type_uniq... OK
|
||||
Applying sites.0001_initial... OK
|
||||
Applying sites.0002_alter_domain_unique... OK
|
||||
Applying socialaccount.0001_initial... OK
|
||||
Applying socialaccount.0002_token_max_lengths... OK
|
||||
Applying socialaccount.0003_extra_data_default_dict... OK
|
||||
Applying socialaccount.0004_app_provider_id_settings... OK
|
||||
Applying socialaccount.0005_socialtoken_nullable_app... OK
|
||||
Applying socialaccount.0006_alter_socialaccount_extra_data... OK
|
||||
Applying token_blacklist.0001_initial... OK
|
||||
Applying token_blacklist.0002_outstandingtoken_jti_hex... OK
|
||||
Applying token_blacklist.0003_auto_20171017_2007... OK
|
||||
Applying token_blacklist.0004_auto_20171017_2013... OK
|
||||
Applying token_blacklist.0005_remove_outstandingtoken_jti... OK
|
||||
Applying token_blacklist.0006_auto_20171017_2113... OK
|
||||
Applying token_blacklist.0007_auto_20171017_2214... OK
|
||||
Applying token_blacklist.0008_migrate_to_bigautofield... OK
|
||||
Applying token_blacklist.0010_fix_migrate_to_bigautofield... OK
|
||||
Applying token_blacklist.0011_linearizes_history... OK
|
||||
Applying token_blacklist.0012_alter_outstandingtoken_user... OK
|
||||
Applying token_blacklist.0013_alter_blacklistedtoken_options_and_more... OK
|
||||
Applying weight.0006_delete_weightentry... OK
|
||||
*** Using settings from env: settings.main
|
||||
Installed 1 object(s) from 1 fixture(s)
|
||||
Installed 33 object(s) from 1 fixture(s)
|
||||
Installed 7 object(s) from 1 fixture(s)
|
||||
Installed 3 object(s) from 1 fixture(s)
|
||||
Installed 5 object(s) from 1 fixture(s)
|
||||
Installed 8 object(s) from 1 fixture(s)
|
||||
Installed 6 object(s) from 1 fixture(s)
|
||||
Installed 1 object(s) from 1 fixture(s)
|
||||
Installed 12 object(s) from 1 fixture(s)
|
||||
Installed 16 object(s) from 1 fixture(s)
|
||||
Installed 8 object(s) from 1 fixture(s)
|
||||
Installed 872 object(s) from 1 fixture(s)
|
||||
Installed 2429 object(s) from 1 fixture(s)
|
||||
Installed 1 object(s) from 1 fixture(s)
|
||||
Installed 1 object(s) from 1 fixture(s)
|
||||
Installed 1 object(s) from 1 fixture(s)
|
||||
*** Using settings from env: settings.main
|
||||
*** Password for user admin was reset to '<image-default, redacted>'
|
||||
Installed 3 object(s) from 1 fixture(s)
|
||||
Running in production mode, running collectstatic now
|
||||
level=INFO ts=2026-10-08 09:54:12,682 module=apps path=/home/wger/.local/lib/python3.12/site-packages/axes/apps.py line=53 message=AXES: BEGIN version 8.3.1, blocking by username
|
||||
|
||||
11362 static files copied to '/home/wger/static', 11362 post-processed.
|
||||
Performing database migrations
|
||||
level=INFO ts=2026-10-08 09:54:32,571 module=apps path=/home/wger/.local/lib/python3.12/site-packages/axes/apps.py line=53 message=AXES: BEGIN version 8.3.1, blocking by username
|
||||
System check identified some issues:
|
||||
|
||||
WARNINGS:
|
||||
?: (axes.W006) AXES_LOCKOUT_PARAMETERS does not contain 'ip_address'. This configuration allows attackers to bypass rate limits by rotating User-Agents or Cookies.
|
||||
HINT: Add 'ip_address' to AXES_LOCKOUT_PARAMETERS.
|
||||
Operations to perform:
|
||||
Apply all migrations: account, actstream, allauth_idp_oidc, auth, authtoken, axes, config, contenttypes, core, easy_thumbnails, exercises, gallery, gym, mailer, manager, measurements, mfa, nutrition, sessions, sites, socialaccount, token_blacklist, trophies, weight
|
||||
Running migrations:
|
||||
No migrations to apply.
|
||||
Your models in app(s): 'exercises', 'gallery' have changes that are not yet reflected in a migration, and so won't be applied.
|
||||
Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.
|
||||
level=INFO ts=2026-10-08 09:54:35,564 module=apps path=/home/wger/.local/lib/python3.12/site-packages/axes/apps.py line=53 message=AXES: BEGIN version 8.3.1, blocking by username
|
||||
System check identified some issues:
|
||||
|
||||
WARNINGS:
|
||||
?: (axes.W006) AXES_LOCKOUT_PARAMETERS does not contain 'ip_address'. This configuration allows attackers to bypass rate limits by rotating User-Agents or Cookies.
|
||||
HINT: Add 'ip_address' to AXES_LOCKOUT_PARAMETERS.
|
||||
Set site URL to fitness.enkisfelhom.hu
|
||||
Using gunicorn on port 8000...
|
||||
level=INFO ts=2026-10-08 09:54:38,089 module=apps path=/home/wger/.local/lib/python3.12/site-packages/axes/apps.py line=53 message=AXES: BEGIN version 8.3.1, blocking by username
|
||||
[2026-10-08 09:54:38 +0200] [58] [INFO] Starting gunicorn 26.1.0
|
||||
[2026-10-08 09:54:38 +0200] [58] [INFO] Listening at: http://0.0.0.0:8000 (58)
|
||||
[2026-10-08 09:54:38 +0200] [58] [INFO] Using worker: sync
|
||||
[2026-10-08 09:54:38 +0200] [59] [INFO] Booting worker with pid: 59
|
||||
[2026-10-08 09:54:38 +0200] [60] [INFO] Booting worker with pid: 60
|
||||
[2026-10-08 09:54:38 +0200] [58] [INFO] Control socket listening at /home/wger/.gunicorn/gunicorn.ctl
|
||||
level=WARNING ts=2026-10-08 09:54:53,158 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=INFO ts=2026-10-08 09:54:56,132 module=database path=/home/wger/.local/lib/python3.12/site-packages/axes/handlers/database.py line=295 message=AXES: Successful login by {username: "********************", ip_address: "********************", user_agent: "curl/8.14.1", path_info: "/en/user/login"}.
|
||||
level=INFO ts=2026-10-08 09:54:56,134 module=database path=/home/wger/.local/lib/python3.12/site-packages/axes/handlers/database.py line=425 message=AXES: Cleaned up 0 expired access attempts from database that were older than 2026-10-08 07:49:56.005561+00:00
|
||||
level=WARNING ts=2026-10-08 09:54:56,295 module=log path=/home/wger/.local/lib/python3.12/site-packages/django/utils/log.py line=249 message=Forbidden: /api/v2/weightentry/
|
||||
level=INFO ts=2026-10-08 09:54:56,491 module=database path=/home/wger/.local/lib/python3.12/site-packages/axes/handlers/database.py line=295 message=AXES: Successful login by {username: "********************", ip_address: "********************", user_agent: "curl/8.14.1", path_info: "/en/user/login"}.
|
||||
level=INFO ts=2026-10-08 09:54:56,492 module=database path=/home/wger/.local/lib/python3.12/site-packages/axes/handlers/database.py line=425 message=AXES: Cleaned up 0 expired access attempts from database that were older than 2026-10-08 07:49:56.371620+00:00
|
||||
level=INFO ts=2026-10-08 09:54:57,028 module=database path=/home/wger/.local/lib/python3.12/site-packages/axes/handlers/database.py line=295 message=AXES: Successful login by {username: "********************", ip_address: "********************", user_agent: "curl/8.14.1", path_info: "/en/user/login"}.
|
||||
level=INFO ts=2026-10-08 09:54:57,029 module=database path=/home/wger/.local/lib/python3.12/site-packages/axes/handlers/database.py line=425 message=AXES: Cleaned up 0 expired access attempts from database that were older than 2026-10-08 07:49:56.907310+00:00
|
||||
level=WARNING ts=2026-10-08 09:55:23,254 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 09:55:53,725 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 09:56:23,813 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 09:56:53,908 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 09:57:24,005 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 09:57:54,097 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 09:58:24,191 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 09:58:54,279 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 09:59:24,378 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 09:59:54,478 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 10:00:24,571 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 10:00:54,667 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 10:01:24,758 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 10:01:54,852 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 10:02:24,938 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 10:02:55,018 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 10:03:25,106 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 10:03:55,203 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 10:04:25,294 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
level=WARNING ts=2026-10-08 10:04:55,381 module=wsgi path=/home/wger/.local/lib/python3.12/site-packages/gunicorn/http/wsgi.py line=450 message=WSGI app sent body bytes on a no-body response (method=HEAD status=200); dropping per RFC 9110.
|
||||
@@ -32,6 +32,8 @@ The full text of every row below: `git show b2dce901b2:documentation/backlog/OPE
|
||||
|
||||
| Row | What | Closed | Evidence |
|
||||
|---|---|---|---|
|
||||
| **R-415** | **The hub enforced uniqueness on `customer_id` only: two customers could be given the same or a nested domain.** (P3) | CLOSED 2026-10-08 — FIXED on hub main (ships with the next hub release): create and edit refuse a domain equal to, containing or under another customer's, or under felhom.eu | `hub/internal/store/domain_conflict.go`, `TestR415_CreateAndEditRefuseConflictingDomain` (red-proved); re-filed the same day after the 2026-10-03 triage lost it; full text `git show 78121aa475:documentation/backlog/OPEN-ITEMS.md`. |
|
||||
| **R-762** | **wger served no CSS, no JavaScript and no uploaded photo; and ran Django's development server.** (P3) | CLOSED 2026-10-08 — both halves proven and pushed: the files (catalog `cf1ed43`, 2026-10-06) and gunicorn with 2 workers (catalog `eec9a0d`, CI job 1546 success; operator ruling 3, decision 182, for the drill-catalog write) | Bench 9401: anon 170 MiB = 44 % of 384M, 0 kills, 0 restarts over 606 s; 9202 (drill catalog, fresh install through the product): 2 × „Booting worker", anon 246 MiB = 64 %, 0 kills, 0 restarts over 600 s / 10,944 requests, login 200, 3 CSS 200, photo 201 → 200, unknown static 404 (control). No ladder step applies (images unchanged; `ladder.check_entry` refuses a same-digest re-test; `09` §5.4 renders the catalog template). Evidence `audits/day-2026-10-08/r762/`. Follow-ups: R-905 (static files in backups); `mem_request` decision D10. wger stays `lifecycle: hidden`. |
|
||||
| **R-177** | **There was no operator-triggerable „run the fill check now" path.** (P4) | CLOSED 2026-10-08 — NO LONGER TRUE: since controller v0.297.0 (R-363) the fill check also runs every 10 minutes, so no door is needed for it | `felhom-controller/controller/cmd/controller/main.go:1579` (`sched.Every("fill-watch-interval", …)`), `:2478` (`fillWatchInterval = 10 * time.Minute`), pinned by `cmd/controller/r363_fillwatch_interval_test.go`; each run logs „checked N filesystem(s)" (readable through the hub's controller-log pull). Design `audits/day-2026-10-08/design-R-314-279-177.md`. |
|
||||
| **R-298** | **The `/storage` page's unregistered list filtered on `role==='user-data'`, so a drive that is also the backup target could never be registered.** (P3) | CLOSED 2026-10-08 — NOT REPRODUCIBLE / NOT TRUE: the agent's role comes from the storage type and backing disk and never from being the backup target, so a backup-target drive on a non-system disk IS user-data | `felhom-agent/internal/storage/role.go:172-186` (unchanged since 2026-07-13); `internal/localapi/disks.go:212-233` and `:1239-1249`; August topology `audits/evidence-rehearsal-2026-08-09/GATE0-demo-hp-before.txt:47-84` → user-data; read-only today: demo-felhom `felhom-backup` on `sdb` (root on `sda`). Side fix on controller main `a40729a`: no eject/format button on a backup-target drive (the agent refuses the eject, 403). |
|
||||
| **R-900** | **The website's FAQ said the household's data is not with a third party, while copies and traffic go to processors.** (P2) | CLOSED 2026-10-08 — PUBLISHED: the GDPR answer on `gyik.html` and `en/faq.html` (visible text and structured data) now names the box, the encrypted copies at Hetzner in the EU, and Cloudflare's view of remote-access traffic; text approved by the operator in chat (`09` §3 decision 180) | website commit `b2dce901`; live read-back 2026-10-08: the new sentence 2× on each page (visible + JSON-LD), the old „nem harmadik félnél" 0×; rest of the site searched (ASCII fragments, positive control) — no other page makes the claim. Left for R-813: the contact form's consent line „harmadik félnek nem adjuk ki", which the consent draft already replaces. |
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user