fix(#3849): scrape the path openbao actually serves
The store's scrape target rendered as `host:port` alone, so the collector
requested `/metrics` — a path openbao does not serve on any listener. Every
scrape since the target landed has 404'd, which reads as a dead exporter
rather than a wrong address, and no bao sample has ever reached the store.
`scrapeTargets` values may now carry a path and query. Both are optional and
omitted when absent, so every existing target renders the config it rendered
before. The query cannot ride in `metrics_path`: prometheus percent-encodes
the `?`, so it has to become `params`.
Measured against openbao 2.6.2 and otelcol-contrib 0.151.0, the pinned
versions: `/metrics` 404s ("this listener only serves the metrics endpoint"),
`/v1/sys/metrics` answers JSON, and only `?format=prometheus` — or an Accept
header the collector happens to send today — returns exposition text. The
query param is the half that does not depend on content negotiation.
This commit is contained in:
parent
fe81dcaf59
commit
7eb5c92d15
3 changed files with 106 additions and 8 deletions
|
|
@ -118,6 +118,10 @@ let
|
|||
baoWithCollector = hive {
|
||||
deploy.bao.enable = true;
|
||||
deploy.swarm-otel.enable = true;
|
||||
# A second job declared as bare `host:port`, so the pair of cases below
|
||||
# reads one rendered scrape list: the store's entry carries a path, this
|
||||
# one carries none.
|
||||
swarm.otel.scrapeTargets.plain = "127.0.0.1:9999";
|
||||
};
|
||||
baoNoCollector = hive {
|
||||
deploy.bao.enable = true;
|
||||
|
|
@ -133,6 +137,14 @@ let
|
|||
# look there rather than at the host's service set.
|
||||
baoUnits = machine: machine.containers.swarm-bao.config.systemd.services;
|
||||
|
||||
# The scrape list prometheus is handed, not the option a service declared:
|
||||
# the address, the path and the query are one string on the way in and three
|
||||
# fields on the way out, and only the second shape is what gets requested.
|
||||
scrapeJob =
|
||||
machine: job:
|
||||
lib.findFirst (c: c.job_name == job) null
|
||||
machine.containers.swarm-otel.config.services.opentelemetry-collector.settings.receivers.prometheus.config.scrape_configs;
|
||||
|
||||
# A priority collision is a property of the *option*, not
|
||||
# of the merged value's interior — nix throws the moment the value is
|
||||
# demanded at all, so `seq`-ing each `serviceConfig` value to WHNF is
|
||||
|
|
@ -385,6 +397,28 @@ let
|
|||
in
|
||||
s.listener ? metrics && (s.telemetry.prometheus_retention_time or "0s") != "0s";
|
||||
}
|
||||
{
|
||||
# openbao serves no `/metrics` at all, so a scrape of the default path
|
||||
# 404s: the store looks like a dead exporter, and every panel built on
|
||||
# it renders empty rather than erroring.
|
||||
name = "the store's scrape asks for the path openbao serves";
|
||||
ok =
|
||||
let
|
||||
j = scrapeJob baoWithCollector "bao";
|
||||
in
|
||||
(j.metrics_path or "") == "/v1/sys/metrics" && (j.params.format or [ ]) == [ "prometheus" ];
|
||||
}
|
||||
{
|
||||
# Presence control for the case above: both fields are omitted rather
|
||||
# than defaulted, so a target declared as bare `host:port` renders what
|
||||
# it rendered before the path grammar existed.
|
||||
name = "a target with no path renders neither metrics_path nor params";
|
||||
ok =
|
||||
let
|
||||
j = scrapeJob baoWithCollector "plain";
|
||||
in
|
||||
j != null && !(j ? metrics_path) && !(j ? params);
|
||||
}
|
||||
{
|
||||
# Absence arm. Unauthenticated by design, so it must not exist where
|
||||
# nothing reads it.
|
||||
|
|
|
|||
Loading…
Reference in a new issue