Watch
0
0
Fork
You've already forked hyperhive
0

swarm-bao: stamp collector's service.name as "bao"

bao's own in-container collector labelled every log line and metric it
forwards `service.name=swarm-bao` (`processors.resource.attributes`,
keyed off `swarm.bao.machine`), while every panel in the shipped
Grafana bao dashboard queries the literal `service.name="bao"` — no
panel has matched since the scrape moved into that collector.

Rename it in the collector instead of templating the dashboard: a new
`collectorServiceName` binding in swarm-bao.nix, deliberately not
`cfg.machine` (that value names the container/receiver, not bao's
display identity), stamps `service.name="bao"` directly. bao.json is
back to its origin/main shape, unchanged.

Adds a module-eval case to checks.module-eval-grafana that reads the
collector's own evaluated config and asserts its service.name matches
every selector the shipped dashboard uses; verified invert-proof by
setting the value back to cfg.machine and confirming that specific
case (and only it) fails.
This commit is contained in:
atlas 2026-09-24 21:37:58 +02:00 • committed by mara
commit cb176c7be7
2 changed files with 53 additions and 1 deletions

View file

@ -30,6 +30,16 @@ let
swarm.grafana.package = pkgs.emptyDirectory;
};
# Same pairing `nix/module-eval/bao-otel-collector.nix` uses for its own
# cases: the store's container with its own collector on, so
# `.containers.swarm-bao.config` carries a real, evaluated
# `opentelemetry-collector.settings` rather than one this file would have
# to hand-assemble.
baoWithCollector = hive {
deploy.bao.enable = true;
deploy.swarm-otel.enable = true;
};
# The metrics UI beside the IdP. It reads its secret out of the store like
# every other Grafana host, so it needs a store identity like every other
# Grafana host — the cert pair here is not scenery, it is the arm that would
@ -261,6 +271,33 @@ let
&& lib.all (r: r.field == "severity_text" && r.enabled == true && lib.elem r.level canonical) rules
&& lib.all (text: lib.any (r: r.value == text) rules) emitted;
}
{
# 🩸 The regression this guards: moving bao's metrics scrape into its
# own in-container collector made that collector stamp every exported
# series `service.name=swarm-bao`, while every panel in the shipped
# bao.json still queried the literal `"service.name"="bao"` — delivery
# could be perfect and no panel would ever match. Fixed by renaming it
# in the collector rather than in the dashboard: `swarm-bao.nix`'s
# `collectorServiceName` now stamps `"bao"` directly. This case reads
# the collector's OWN evaluated config — not a hand-copied literal —
# so it fails again the moment that binding and the dashboard drift
# apart in either direction.
# 🔬 Invert-proof: change `collectorServiceName` in swarm-bao.nix back
# to `cfg.machine` and this case fails.
name = "the bao dashboard's selectors match the service.name bao's own collector stamps";
ok =
let
attrs =
baoWithCollector.containers.swarm-bao.config.services.opentelemetry-collector.settings.processors.resource.attributes;
stamped = lib.findFirst (a: a.key == "service.name") null attrs;
board = builtins.fromJSON (builtins.readFile ../host-modules/swarm-grafana/dashboards/bao.json);
exprs = lib.concatMap (p: map (t: t.expr or "") (p.targets or [ ])) board.panels;
selectors = lib.filter (e: lib.hasInfix "service.name" e) exprs;
in
stamped != null
&& builtins.length selectors == 12
&& lib.all (e: lib.hasInfix "\"service.name\"=\"${stamped.value}\"" e) selectors;
}
];
in
runGroup "grafana" cases