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

This commit is contained in:
admin committed 2026-10-26 14:17:07 +01:00
1 parent a90a9745a8
commit 69443d3c4e
6 files changed
+137 -3

No files matched your search

@@ -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()