fix(ops-log): record the host's NAME, not the ssh target
elway passes its `host` argument straight through, and that argument is an ssh target. Five records of a real jobs.cfg change on esh-pve were written under host `infra-ops@esh-pve`. The consequence was not cosmetic. infra-hermes triaged the ESH backup job errors, queried `--host esh-pve`, got nothing back, and correctly reported the 05:29 exclusion of VM 102 as an unattributed change. The record had existed the whole time, five lines of it, under a name nobody would think to ask for. A log you cannot query under the obvious name is not a log. `normalize_host` strips any `user@` prefix on write AND on query, so records written before this fix are findable too, and `audit` -- which matches records by host name -- stops missing them as well. Verified in both directions: a record written with `infra-ops@esh-pve` and one written with `esh-pve` now both return for `--host esh-pve`, and the five historical elway entries surface under that query.
This commit is contained in:
+17
-2
@@ -141,12 +141,27 @@ def append(record: dict) -> None:
|
|||||||
fcntl.flock(fh.fileno(), fcntl.LOCK_UN)
|
fcntl.flock(fh.fileno(), fcntl.LOCK_UN)
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_host(host: str) -> str:
|
||||||
|
"""`infra-ops@esh-pve` -> `esh-pve`.
|
||||||
|
|
||||||
|
The ssh TARGET is not the host's name, and recording it as one makes the
|
||||||
|
entry unfindable. Measured 2026-09-19: five elway records of a real
|
||||||
|
jobs.cfg change on esh-pve were written under host `infra-ops@esh-pve`, so
|
||||||
|
infra-hermes's `--host esh-pve` query returned nothing and he correctly
|
||||||
|
reported the change as unattributed. The record existed the whole time. A
|
||||||
|
log you cannot query under the obvious name is not a log.
|
||||||
|
|
||||||
|
Also fixes `audit`, which matches records by host name.
|
||||||
|
"""
|
||||||
|
return host.rsplit("@", 1)[-1].strip() or host
|
||||||
|
|
||||||
|
|
||||||
def record(host: str, action: str, target: str = "", outcome: str = "changed",
|
def record(host: str, action: str, target: str = "", outcome: str = "changed",
|
||||||
detail: str = "", extra: dict | None = None) -> dict:
|
detail: str = "", extra: dict | None = None) -> dict:
|
||||||
rec = {
|
rec = {
|
||||||
"ts": now_iso(),
|
"ts": now_iso(),
|
||||||
"agent": agent_id(),
|
"agent": agent_id(),
|
||||||
"host": host,
|
"host": normalize_host(host),
|
||||||
"action": action,
|
"action": action,
|
||||||
"target": target,
|
"target": target,
|
||||||
"outcome": outcome,
|
"outcome": outcome,
|
||||||
@@ -181,7 +196,7 @@ def read_records(limit: int | None = None, since_s: int | None = None,
|
|||||||
out.append({"ts": "?", "agent": "?", "host": "?", "action": "UNPARSEABLE",
|
out.append({"ts": "?", "agent": "?", "host": "?", "action": "UNPARSEABLE",
|
||||||
"target": "", "outcome": "failed", "detail": line[:200]})
|
"target": "", "outcome": "failed", "detail": line[:200]})
|
||||||
continue
|
continue
|
||||||
if host and rec.get("host") != host:
|
if host and normalize_host(rec.get("host", "")) != normalize_host(host):
|
||||||
continue
|
continue
|
||||||
if target and rec.get("target") != target:
|
if target and rec.get("target") != target:
|
||||||
continue
|
continue
|
||||||
|
|||||||
Reference in New Issue
Block a user