hub v0.172.0 RELEASED (13:08 UTC); felhom-tenantsync v1.4.0 INSTALLED on ep0 (operator yes); R-1292 live on Tester 1 (PASS; run 1 was an instrument failure, kept).
gates / gates (push) Successful in 13m17s
gates / gates (push) Successful in 13m17s
This commit is contained in:
1 parent
a90a9745a8
commit
69443d3c4e
6 files changed
+137
-3
No files matched your search
+17
@@ -0,0 +1,17 @@
|
||||
rc=0
|
||||
[1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'QBT_ADMIN_PASSWORD']
|
||||
[1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
|
||||
[1] deployed, controller state=running, pinned={'qbittorrent': 'qbittorrentofficial/qbittorrent-nox:5.2.4-1'}
|
||||
1. qBittorrent installed: True
|
||||
before: {'error': 'unreadable'}
|
||||
2. alternative speed ON, alternative limit 500 KiB/s (the household's): ok ok
|
||||
now: {'error': 'unreadable'}
|
||||
[3. first tick] rule lines: 2026/10/26 12:18:53 [INFO] [upwatch] qBittorrent upload limit set to 5892096 B/s (50 % of the tested line, 94.3 Mbit/s) | record: (none)
|
||||
after the first tick: {'error': 'unreadable'}
|
||||
4. the household switches back to normal speed: ok {'error': 'unreadable'}
|
||||
after the next tick: {'error': 'unreadable'} | record: | lines: (none at INFO)
|
||||
VERDICT: FAIL
|
||||
[7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'qbittorrent', 'volumes_removed': ['qbittorrent_qbittorrent_config'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': ['/mnt/felhom-driv
|
||||
5. leftovers: {'containers': '', 'volumes': '', 'appyaml': '', 'appdata': '', 'kept': '', 'subdomain': '404'}
|
||||
|
||||
[exited with code 0]
|
||||
@@ -0,0 +1,14 @@
|
||||
[1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'QBT_ADMIN_PASSWORD']
|
||||
[1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
|
||||
[1] deployed, controller state=running, pinned={'qbittorrent': 'qbittorrentofficial/qbittorrent-nox:5.2.4-1'}
|
||||
1. qBittorrent installed: True
|
||||
before: {'up_limit': 0, 'alt_up_limit': 10240, 'mode_alt': False}
|
||||
2. alternative speed ON, alternative limit 500 KiB/s (the household's): ok ok
|
||||
now: {'up_limit': 0, 'alt_up_limit': 512000, 'mode_alt': True}
|
||||
[3. first tick] rule lines: 2026/10/26 12:53:06 [INFO] [upwatch] qBittorrent upload limit set to 5892096 B/s (50 % of the tested line, 94.3 Mbit/s) | record: {'box_set_bytes': 5892096, 'line_mbps': 94.28828951955792, 'set_at': '2026-10-26T12:53:06Z'}
|
||||
after the first tick: {'up_limit': 5892096, 'alt_up_limit': 512000, 'mode_alt': True}
|
||||
4. the household switches back to normal speed: ok {'up_limit': 5892096, 'alt_up_limit': 512000, 'mode_alt': False}
|
||||
after the next tick: {'up_limit': 5892096, 'alt_up_limit': 512000, 'mode_alt': False} | record: {'box_set_bytes': 5892096, 'line_mbps': 94.28828951955792, 'set_at': '2026-10-26T12:53:06Z'} | lines: (none at INFO)
|
||||
VERDICT: PASS
|
||||
[7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'qbittorrent', 'volumes_removed': ['qbittorrent_qbittorrent_config'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': ['/mnt/felhom-drives/adatlem
|
||||
5. leftovers: {'containers': '', 'volumes': '', 'appyaml': '', 'appdata': '', 'kept': '', 'subdomain': '404'}
|
||||
@@ -0,0 +1,11 @@
|
||||
2026-10-26T13:09:21Z
|
||||
syntax-ok
|
||||
-rwxr-xr-x 1 root root 17964 Oct 26 13:09 /usr/local/bin/felhom-tenantsync
|
||||
-rwxr-xr-x 1 root root 8253 Jul 10 18:57 /usr/local/bin/felhom-tenantsync.bak-1.0.0
|
||||
-rwxr-xr-x 1 root root 10480 Jul 17 11:12 /usr/local/bin/felhom-tenantsync.bak-1.1.0
|
||||
-rwxr-xr-x 1 root root 12004 Jul 17 19:15 /usr/local/bin/felhom-tenantsync.bak-1.2.0
|
||||
-rwxr-xr-x 1 root root 15542 Oct 19 14:07 /usr/local/bin/felhom-tenantsync.v1.3.0
|
||||
751b3c26f3e4c872
|
||||
# felhom-tenantsync v1.4.0 — the offsi
|
||||
{"status":"ok","fp":"c6:07:28:3f"}
|
||||
{"status":"ok","unpruned_checked":true,"unpruned":[]}
|
||||
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
"""r1292_live.py — R-1292 live on a box with a TESTED line (Tester 1; 9202 has none, so the rule never acts there):
|
||||
a THROWAWAY qBittorrent; the household's „alternative speed" switched ON with an alternative limit of 500 KiB/s; then
|
||||
the controller's 50 % rule (its 15-minute tick) must set the NORMAL limit (`up_limit`) and leave the alternative alone;
|
||||
then the household switches back to normal speed, and the next tick must NOT read that as „the household changed it".
|
||||
qBittorrent's own API from inside its container (the admin password rides an env var, never printed). Removed through
|
||||
the product at the end (data and backups).
|
||||
|
||||
usage: SC=<dir with .ctlpw> SWEEP_EV=<evidence dir> TARGET=tester-1 DRIVE_ROOT=<drive> python3 r1292_live.py"""
|
||||
import json, os, sys, time
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../catalog-sweep-2026-10-24/tools"))
|
||||
import sweep as sw # noqa: E402
|
||||
|
||||
w = sw.w
|
||||
APP = "qbittorrent"
|
||||
|
||||
|
||||
def qb(path, data=None):
|
||||
"""One qBittorrent API call inside its container, through /root/qbtool.sh in the guest (the password via env QP)."""
|
||||
pw = (w.GENERATED.get(APP) or {}).get("QBT_ADMIN_PASSWORD", "")
|
||||
arg = " '" + data + "'" if data else ""
|
||||
return sw.g(f"QP='{pw}' sh /root/qbtool.sh {path}{arg}").strip()
|
||||
|
||||
|
||||
def record():
|
||||
"""The 50 % rule's record (settings.json upwatch.qb_limit), parsed — never a grep on a JSON file."""
|
||||
raw = sw.g("docker exec felhom-controller cat /opt/docker/felhom-controller/data/settings.json")
|
||||
try:
|
||||
return (json.loads(raw).get("upwatch") or {}).get("qb_limit")
|
||||
except ValueError:
|
||||
return "unreadable"
|
||||
|
||||
|
||||
def prefs():
|
||||
try:
|
||||
p = json.loads(qb("app/preferences"))
|
||||
return {"up_limit": p.get("up_limit"), "alt_up_limit": p.get("alt_up_limit"), "mode_alt": qb("transfer/speedLimitsMode") == "1"}
|
||||
except ValueError:
|
||||
return {"error": "unreadable"}
|
||||
|
||||
|
||||
def rule_lines(since):
|
||||
return sw.g(f"docker logs --since {since} felhom-controller 2>&1 | grep -E 'qBittorrent (upload )?limit' | cut -c1-200").strip()
|
||||
|
||||
|
||||
def wait_tick(since, say, label, cap=1100):
|
||||
for _ in range(cap // 20):
|
||||
time.sleep(20)
|
||||
out = sw.g(f"docker logs --since {since} felhom-controller 2>&1 | grep -E 'upwatch' | grep -vE 'DEBUG' | tail -1")
|
||||
# the 15-minute tick also logs the hold seeder; any upwatch line after `since` with a qBittorrent verdict counts
|
||||
ln = rule_lines(since)
|
||||
if ln:
|
||||
break
|
||||
st = record()
|
||||
say(f" [{label}] rule lines: {rule_lines(since) or '(none at INFO)'} | record: {st or '(none)'}")
|
||||
return st
|
||||
|
||||
|
||||
def main():
|
||||
say = print
|
||||
w.say = say
|
||||
w.login()
|
||||
t0 = int(time.time())
|
||||
try:
|
||||
ok = w.deploy(APP, "torrent") and w.wait_app("torrent", "/", tries=90, delay=5)
|
||||
say("1. qBittorrent installed:", ok)
|
||||
before = prefs()
|
||||
say(" before:", before)
|
||||
if "error" in before:
|
||||
raise SystemExit("INSTRUMENT: qBittorrent's preferences are unreadable — no verdict (fix the probe first)")
|
||||
say("2. alternative speed ON, alternative limit 500 KiB/s (the household's):",
|
||||
qb("app/setPreferences", "json=" + json.dumps({"alt_up_limit": 512000})) or "ok",
|
||||
qb("transfer/toggleSpeedLimitsMode", "x=1") or "ok")
|
||||
say(" now:", prefs())
|
||||
rec1 = wait_tick(t0, say, "3. first tick")
|
||||
p1 = prefs()
|
||||
say(" after the first tick:", p1)
|
||||
say("4. the household switches back to normal speed:", qb("transfer/toggleSpeedLimitsMode", "x=1") or "ok", prefs())
|
||||
t1 = int(time.time())
|
||||
time.sleep(960) # one full 15-minute tick; a "kept" decision logs nothing, a "household" one logs at INFO
|
||||
rec2 = record()
|
||||
say(" after the next tick:", prefs(), "| record:", rec2, "| lines:", rule_lines(t1) or "(none at INFO)")
|
||||
verdict = ("PASS" if p1.get("up_limit", 0) and abs(p1["up_limit"] - 94.3 * 0.5 * 1e6 / 8) < 2048 and p1.get("alt_up_limit") == 512000
|
||||
and isinstance(rec2, dict) and not rec2.get("household") else "FAIL")
|
||||
say("VERDICT:", verdict)
|
||||
finally:
|
||||
sw.remove(APP, keep=False, say=say)
|
||||
say("5. leftovers:", sw.leftovers(APP, "torrent"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
## v0.172.0 (unreleased, 2026-10-26) — a fresh install's whole-guest off-site set-up never fails silently (R-1295)
|
||||
## v0.172.0 (2026-10-26) — a fresh install's whole-guest off-site set-up never fails silently (R-1295) — RELEASED 2026-10-26 13:08 UTC on the operator's yes (image sha256:7c8d129a…, from `232f42d2`, CI 2366; rc.1 ran the live proof)
|
||||
|
||||
- **Cause (measured, `documentation/audits/r1295-pbsdr-selfcheck-2026-10-26/`):** PBS's proxy caches permissions for up to
|
||||
5 s and an ACL-only change does not clear the cache; under concurrent requests ep0's self-check of a new token is
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## 2026-10-26 — felhom-tenantsync v1.4.0: the self-check waits out the PBS permission cache (R-1295) — committed, NOT installed on ep0
|
||||
## 2026-10-26 — felhom-tenantsync v1.4.0: the self-check waits out the PBS permission cache (R-1295) — INSTALLED on ep0 2026-10-26 13:09Z on the operator's yes (sha256 `751b3c26…` = the repository's; v1.3.0 kept as `.v1.3.0`; `fingerprint` and `usage` ok)
|
||||
|
||||
- **`felhom-tenantsync.sh` v1.4.0:** the new token is re-checked every 0.5 s for up to 15 s (a log line per try) before
|
||||
the old regenerate-once-and-rollback; the transient admin token waits the same way before its first namespace list
|
||||
(under load it met the same cache and a wrong `namespace create` died). Test `test_tenantsync_selfcheck.py` (19 checks;
|
||||
v1.3.0 fails 11). Live on a throwaway PBS 4.2.5 under load, the hub's exact order, 30 pairs: v1.3.0 failed 11, v1.4.0
|
||||
failed 0 (`documentation/audits/r1295-pbsdr-selfcheck-2026-10-26/`). **Installing it on ep0 is the operator's yes.**
|
||||
failed 0 (`documentation/audits/r1295-pbsdr-selfcheck-2026-10-26/`, `ep0-install-v1.4.0.txt`).
|
||||
|
||||
## 2026-10-25 — installer 1.36.1: the preflight words a refusal again — PUBLISHED 2026-10-25 evening on the operator's yes (`installer-v1.36.1` → `79ee3e33`, served sha256 `e18cdd17…`; the three refusal sentences seen live)
|
||||
|
||||
|
||||
Reference in new issue
Block a user