Commit f9c4df6d by PLN (Algolia)

bridge: show the signal path as a rig row

health_item() turns the health.json gig-log publishes into one more panel item,
through the same tray_summary() the tray renders, so the two faces cannot
disagree. A stale observer is 'broken', no observer is 'absent'; neither can
read as up.
parent 699e93c7
...@@ -56,6 +56,7 @@ THERMAL_CONF = Path("/etc/thermal-mode.conf") ...@@ -56,6 +56,7 @@ THERMAL_CONF = Path("/etc/thermal-mode.conf")
sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from rig_units import SERVICES as _INVENTORY # noqa: E402 from rig_units import SERVICES as _INVENTORY # noqa: E402
import rig_health # noqa: E402 (the one health.json gig-log publishes; read-only here)
# The panel does not care about boot policy (that is `--ensure`'s business), so # The panel does not care about boot policy (that is `--ensure`'s business), so
# it keeps its own 4-tuple shape rather than spreading a 5th field everywhere. # it keeps its own 4-tuple shape rather than spreading a 5th field everywhere.
...@@ -174,6 +175,23 @@ def _leds_state(state, detail): ...@@ -174,6 +175,23 @@ def _leds_state(state, detail):
return "down", f"{detail} — board is plugged in but DARK, start this" return "down", f"{detail} — board is plugged in but DARK, start this"
_HEALTH_STATE = {"ok": "up", "degraded": "down", "down": "broken", "stale": "broken"}
def health_item(h: dict) -> dict:
"""The signal path as one more panel row, from the same document and the same
wording the tray uses (rig_health.tray_summary), so the two faces cannot
disagree. `unknown` means gig-log is not running: that is `absent` here, which
the panel draws as not-applicable, never as a green row."""
s = rig_health.tray_summary(h)
detail = s["row"].removeprefix("rig: ")
if s["tip"]:
detail += " — " + s["tip"][0].removeprefix("rig: ")
return {"key": "rig-health", "name": "signal path", "kind": "health",
"blurb": "clock, surface driver, sound engine (gig-log)",
"state": _HEALTH_STATE.get(h.get("overall"), "absent"), "detail": detail}
def status(): def status():
"""Every piece of the rig, with the state the reader actually needs.""" """Every piece of the rig, with the state the reader actually needs."""
lines = L._cmdlines() # one /proc scan for the whole snapshot lines = L._cmdlines() # one /proc scan for the whole snapshot
...@@ -224,6 +242,8 @@ def status(): ...@@ -224,6 +242,8 @@ def status():
"state": "up" if _lcxl() else "down", "state": "up" if _lcxl() else "down",
"detail": "connected" if _lcxl() else "not detected"}) "detail": "connected" if _lcxl() else "not detected"})
items.append(health_item(rig_health.read_health()))
return {"items": items, "gear": gear(), "converge": _job.state()} return {"items": items, "gear": gear(), "converge": _job.state()}
......
...@@ -146,3 +146,26 @@ def test_converge_never_makes_sound(monkeypatch): ...@@ -146,3 +146,26 @@ def test_converge_never_makes_sound(monkeypatch):
R._Converge()._run(launch_apps=False) R._Converge()._run(launch_apps=False)
assert "--audio" not in seen["argv"] assert "--audio" not in seen["argv"]
assert "--converge" in seen["argv"] assert "--converge" in seen["argv"]
# ── the signal path row (rig_health) ───────────────────────────────
def _h(overall, **checks):
return {"overall": overall, "checks": {n: {"state": s, "detail": d} for n, (s, d) in checks.items()}}
def test_health_row_is_up_only_when_the_observer_says_ok():
assert R.health_item(_h("ok"))["state"] == "up"
def test_health_row_is_broken_when_down_and_names_the_failing_check():
it = R.health_item(_h("down", audio_clock=("fail", "no hardware clock")))
assert it["state"] == "broken" and "audio_clock" in it["detail"]
def test_a_stale_observer_is_broken_not_up():
"""A dead observer must never read green."""
assert R.health_item({"overall": "stale", "detail": "old", "checks": {}})["state"] == "broken"
def test_no_observer_is_absent_not_up():
assert R.health_item({"overall": "unknown", "checks": {}})["state"] == "absent"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment