bao's metrics were scraped by the SWARM collector over loopback, via a `swarm.otel.scrapeTargets.bao` entry gated on `deploy.swarm-otel.enable` — "does the swarm's collector run on THIS host". It had to be: loopback only reaches a reader that landed on the same host. What that rendered everywhere else was nothing at all. Off that host the metrics listener was not emitted, so the store's metrics reached the store nowhere, and a host with no entry is indistinguishable from a host nobody asked to scrape. Moves the scrape into the collector this container already runs, per mara on #4537: "move the existing scraper to the local collector". The container shares the host netns (privateNetwork = false), so the scrape still dials 127.0.0.1 — the listener keeps its address, its `metrics_only` narrowing and its loopback-only bind, and the API listener's `tls_require_and_verify_client_cert` is untouched. The listener and its `prometheus_retention_time` lose their gate: the reader ships with the store now, so there is no host where the endpoint has none. The metrics pipeline reuses the logs pipeline's `resource` processor and `otlphttp` exporter, so both signals carry the same `service.name` and leave by the one hop. Logs are unaffected: `journaldUnits` and --link-journal=host stay until every sibling swarm container has a collector of its own. The module-eval absence arm "a store with no collector beside it serves no metrics" is inverted rather than dropped — the condition it asserted is the bug. Three cases join it: the job is in swarm-bao AND gone from swarm-otel (a move, not a copy), the scrape target and listener are both pinned to loopback, and the metrics pipeline shares its exporter with the logs one.
56 lines
2.6 KiB
Nix
56 lines
2.6 KiB
Nix
# Glue: register the secret store's own journal forwarder as an OIDC client
|
|
# wherever authelia runs.
|
|
#
|
|
# ONE PAIRING PER FILE — swarm-bao's forwarder ← authelia, and nothing else.
|
|
# Deleting this leaves a forwarder authelia has never heard of: the token
|
|
# endpoint refuses it, nothing is minted, the publisher has nothing to copy
|
|
# into the store, and the collector's export is a 401 nobody asked for.
|
|
#
|
|
# ⚠️ A SECOND client beside ./glue-swarm-otel-oidc-client.nix's, not a reuse
|
|
# of it. That one is the swarm collector's identity for what IT pushes; this
|
|
# one belongs to the collector inside the store's container, which is a
|
|
# different principal on a different host — one identity per principal, the
|
|
# rule `swarm-controller.nix` states over its own `queueClientId`.
|
|
#
|
|
# ⚠️ Gated on authelia being HERE, and deliberately NOT on this host running
|
|
# the store. A client is a row in THIS host's provider config, so it can only
|
|
# be declared where that config is rendered, and ./swarm-bao.nix's `config`
|
|
# hangs off `deploy.bao.enable` — the split ./glue-grafana-oidc-client.nix and
|
|
# ./glue-swarm-otel-oidc-client.nix each made for the same reason. Read either
|
|
# file's own comment for the property this one shares with them.
|
|
{
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
hyperhiveCfg = config.services.hyperhive;
|
|
deployCfg = hyperhiveCfg.deploy;
|
|
baoCfg = hyperhiveCfg.swarm.bao;
|
|
in
|
|
{
|
|
config = lib.mkIf (hyperhiveCfg.enable && deployCfg.authelia.enable) {
|
|
# One declaration, two readers: `clientId` is a read-only option
|
|
# ./swarm-bao.nix owns, and ./swarm-otel.nix builds this principal's
|
|
# authenticator audience from the same option.
|
|
services.hyperhive.swarm.authelia.oidc.clients = [
|
|
{
|
|
id = baoCfg.otel.clientId;
|
|
description = "HyperHive secret store journal forwarder";
|
|
kind = "machine";
|
|
redirectUris = [ ];
|
|
# Its own id as its own permitted audience — the self-referential
|
|
# form `swarm-authelia.nix`'s `hiveClients` uses, which is the shape
|
|
# to copy here: this forwarder's token lands on an `oidc/*` receiver
|
|
# of the swarm collector, exactly as a hive's does.
|
|
audience = [ baoCfg.otel.clientId ];
|
|
# ⚠️ What makes the token READABLE by that receiver at all. Authelia's
|
|
# default is an opaque handle, and an `oidc` extension verifies
|
|
# offline against `/jwks.json` — so without this the export fails with
|
|
# a message about the verifier rather than about the token. Same
|
|
# value, same reason, as every hive's client.
|
|
accessTokenSignedResponseAlg = "RS256";
|
|
}
|
|
];
|
|
};
|
|
}
|