Watch
0
0
Fork
You've already forked hyperhive
0

swarm-otel: declare forgejo's published scrape target on every host

The forgejo entry in `swarm.otel.publishedScrapeTargets` was declared
under `deploy.forgejo.enable`, so it existed only in the forge host's
evaluation. Its two readers evaluate elsewhere: the collector renders
its prometheus jobs from its own host's list, and authelia registers
the collector client's audience from its own host's list. With the
forge, the collector and authelia on different hosts, the collector
had no forgejo job and authelia would have refused its token.

Declare the entry unconditionally in swarm-otel-service.nix, keyed on
`swarm.forge.domain`, which every host evaluates identically. A swarm
with no forge scrapes a name that answers nothing and shows a failing
job, the same trade the collector and grafana OIDC clients already make.

Single-host render is unchanged: the entry already existed there.

Part of #5205
This commit is contained in:
atlas 2026-10-13 10:24:17 +02:00 • committed by mara
commit 6c1ab87f68
4 changed files with 82 additions and 23 deletions

View file

@ -1,7 +1,8 @@
# The swarm's telemetry collector as every hive sees it: the name it is
# reached on, its receiver ports, the client it is registered as and the
# audiences that client may present, identical on every host. What the host
# running it decides, and the container itself, are in ./swarm-otel.nix.
# reached on, its receiver ports, the published targets it scrapes, the client
# it is registered as and the audiences that client may present, identical on
# every host. What the host running it decides, and the container itself, are
# in ./swarm-otel.nix.
{
lib,
config,
@ -274,10 +275,18 @@ in
Prometheus endpoints this collector scrapes **by name, with a
credential**, as `<job name> = "<url>"`.
A service module declares its own entry, from its own module, the
same way it does for `scrapeTargets` — and the collector's OAuth2
client derives its permitted audiences from these URLs, so a
target and the authorisation to reach it are **one declaration**.
**Entries are declared swarm-wide**: from this module's `config`,
unconditionally, keyed on the service's `swarm.<svc>.domain`, so
every host evaluates the same set. Unlike `scrapeTargets`, an entry
is not declared under the service's own `enable`: the collector
reads this list on its host and authelia's registration reads it on
authelia's host, and neither need be the service's host. A swarm
that does not run the service anywhere scrapes a name that answers
nothing, which shows as a failing job rather than a missing one.
The collector's OAuth2 client derives its permitted audiences from
these URLs, so a target and the authorisation to reach it are **one
declaration**.
Two lists that must agree would be a drift to maintain, and its
failure mode is the bad one: a target whose audience was forgotten
authenticates against nothing and reads as a scrape failure rather
@ -331,4 +340,16 @@ in
'';
};
};
# Not under any `enable`: see `publishedScrapeTargets` for why every host
# declares every entry.
#
# ⚠️ Each URL must be exactly what the collector requests, because authelia
# checks the token's audience against it: it has to agree with the gated
# `= /metrics` location on the service's vhost. A near miss is a correctly
# minted token refused at the target.
config.services.hyperhive.swarm.otel.publishedScrapeTargets = {
# The vhost location is in ./hive-forge/default.nix.
forgejo = "https://${hyperhiveCfg.swarm.forge.domain}/metrics";
};
}