move links, adminSync.ignoreUsers and scrapeTargets under their service's deploy namespace
This commit is contained in:
parent
ee591b0546
commit
90272ec3c0
1 changed files with 156 additions and 108 deletions
|
|
@ -18,6 +18,7 @@ let
|
|||
cfg = config.services.hyperhive.swarm.otel;
|
||||
deployCfg = config.services.hyperhive.deploy;
|
||||
upstream = deployCfg.swarm-otel.upstream;
|
||||
scrapeTargets = deployCfg.swarm-otel.scrapeTargets;
|
||||
vmCfg = config.services.hyperhive.swarm.victoriametrics;
|
||||
vlCfg = config.services.hyperhive.swarm.victorialogs;
|
||||
hyperhiveCfg = config.services.hyperhive;
|
||||
|
|
@ -333,6 +334,58 @@ in
|
|||
# operator's choice for this deployment, so both hang off the deployment.
|
||||
# `enable` already lives in ./deploy.nix, which also carries the rename.
|
||||
options.services.hyperhive.deploy.swarm-otel = {
|
||||
scrapeTargets = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.str;
|
||||
default = { };
|
||||
example = lib.literalExpression ''{ collector = "127.0.0.1:8889"; }'';
|
||||
description = ''
|
||||
Prometheus exposition endpoints this collector scrapes, as
|
||||
`<job name> = "<host>:<port>"`. The collector runs in a network namespace of
|
||||
its own, so `127.0.0.1` is the collector container's loopback: a target
|
||||
here is a listener inside that container, such as its own telemetry.
|
||||
|
||||
A path and query may follow the port —
|
||||
`"127.0.0.1:9100/stats?format=prometheus"` — for an
|
||||
exporter that does not serve `/metrics`. Both are optional and
|
||||
omitted when absent, so a bare `host:port` is scraped exactly as
|
||||
before.
|
||||
|
||||
**A service declares its own entry, from its own module, under its
|
||||
own `enable`.** Do not assemble the list here: an entry then exists
|
||||
only where the service that named it runs, so a target is never
|
||||
declared on a host that does not serve it. A swarm service on the
|
||||
host is not reachable here, since its loopback is not the collector's:
|
||||
it is a `publishedScrapeTargets` entry instead, which a collector on
|
||||
any host scrapes.
|
||||
|
||||
⚠️ **That constrains the TARGET, not the SCRAPER, and the difference
|
||||
is a silent gap.** Nothing here puts the collector on the same host.
|
||||
Services are co-located by *default* — `swarm-required-services.nix`
|
||||
derives their `enable` flags from one `lib.mkDefault` — not by
|
||||
construction, and an operator may split them.
|
||||
|
||||
When they are split the target is simply never scraped: the
|
||||
service's host declares an entry no local collector reads, and the
|
||||
collector's host never enabled that service so has no entry at all.
|
||||
No error, no eval failure, no warning.
|
||||
|
||||
**No assertion can catch this.** Two hosts are separate NixOS
|
||||
evaluations with no shared context, so neither can see what the
|
||||
other runs. A service that would be seriously wrong to lose should
|
||||
say so in its own contribution, because saying it is the only
|
||||
mechanism available.
|
||||
|
||||
Samples land in a swarm-level pipeline that stamps `swarm` and
|
||||
**never** `hive`: a swarm service does not belong to a hive, and
|
||||
`hive` stays a property of which authenticated receiver accepted a
|
||||
push, not something a scrape can acquire.
|
||||
|
||||
Empty by default, in which case no scrape receiver, processor or
|
||||
pipeline is emitted at all — an enabled scraper with nothing to
|
||||
scrape is the inert configuration this option exists to avoid.
|
||||
'';
|
||||
};
|
||||
|
||||
telemetryPort = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 8889;
|
||||
|
|
@ -498,7 +551,7 @@ in
|
|||
# alive, these counters say whether it is dropping what it receives.
|
||||
# Loopback is the container's own: this collector scrapes `telemetryPort`
|
||||
# inside its netns, and nothing else reads it.
|
||||
services.hyperhive.swarm.otel.scrapeTargets.collector =
|
||||
services.hyperhive.deploy.swarm-otel.scrapeTargets.collector =
|
||||
"127.0.0.1:${toString deployCfg.swarm-otel.telemetryPort}";
|
||||
|
||||
# OTLP/HTTP, not a browsable UI, but the same reverse-proxy shape as
|
||||
|
|
@ -935,11 +988,11 @@ in
|
|||
# Same reason the published one is asserted: a value the grammar
|
||||
# rejects surfaces as `attempt to call elemAt on null` from inside
|
||||
# the renderer, naming neither the option nor the offending value.
|
||||
assertion = lib.all (t: parseScrape t != null) (lib.attrValues cfg.scrapeTargets);
|
||||
assertion = lib.all (t: parseScrape t != null) (lib.attrValues scrapeTargets);
|
||||
message = ''
|
||||
services.hyperhive.swarm.otel.scrapeTargets has ${
|
||||
services.hyperhive.deploy.swarm-otel.scrapeTargets has ${
|
||||
lib.concatMapStringsSep ", " (kv: "${kv.name} = \"${kv.value}\"") (
|
||||
lib.filter (kv: parseScrape kv.value == null) (lib.attrsToList cfg.scrapeTargets)
|
||||
lib.filter (kv: parseScrape kv.value == null) (lib.attrsToList scrapeTargets)
|
||||
)
|
||||
}, which is not of the form <host>:<port>[/<path>][?<k>=<v>].
|
||||
|
||||
|
|
@ -959,12 +1012,11 @@ in
|
|||
# The message names which side each collision came from, which is
|
||||
# the part a rendered-config error could not tell an operator.
|
||||
assertion =
|
||||
lib.intersectLists (lib.attrNames cfg.scrapeTargets) (lib.attrNames cfg.publishedScrapeTargets)
|
||||
== [ ];
|
||||
lib.intersectLists (lib.attrNames scrapeTargets) (lib.attrNames cfg.publishedScrapeTargets) == [ ];
|
||||
message = ''
|
||||
services.hyperhive.swarm.otel: ${
|
||||
lib.concatMapStringsSep ", " (j: "'${j}'") (
|
||||
lib.intersectLists (lib.attrNames cfg.scrapeTargets) (lib.attrNames cfg.publishedScrapeTargets)
|
||||
lib.intersectLists (lib.attrNames scrapeTargets) (lib.attrNames cfg.publishedScrapeTargets)
|
||||
)
|
||||
} is declared as both a loopback
|
||||
scrapeTargets job and a publishedScrapeTargets job.
|
||||
|
|
@ -1149,9 +1201,9 @@ in
|
|||
# target: a `prometheus` receiver with nothing to scrape is
|
||||
# the shape this whole issue is about, a config that renders
|
||||
# and deploys perfectly while adding no data.
|
||||
// lib.optionalAttrs (cfg.scrapeTargets != { } || cfg.publishedScrapeTargets != { }) {
|
||||
// lib.optionalAttrs (scrapeTargets != { } || cfg.publishedScrapeTargets != { }) {
|
||||
prometheus.config.scrape_configs =
|
||||
lib.mapAttrsToList loopbackScrapeConfig cfg.scrapeTargets
|
||||
lib.mapAttrsToList loopbackScrapeConfig scrapeTargets
|
||||
# ⚠️ `++`, so the two kinds of target land in ONE list —
|
||||
# which is exactly why a job name may not appear in both
|
||||
# options. A list concatenation does not resolve a
|
||||
|
|
@ -1410,7 +1462,7 @@ in
|
|||
# separated FOR is the credential it proves, and that is
|
||||
# the receiver's job, not the pipeline's.
|
||||
++ map (n: "otlp/${n}") serviceProducerNames
|
||||
++ lib.optional (cfg.scrapeTargets != { } || cfg.publishedScrapeTargets != { }) "prometheus";
|
||||
++ lib.optional (scrapeTargets != { } || cfg.publishedScrapeTargets != { }) "prometheus";
|
||||
processors = [ "resource/${swarmTierName}" ];
|
||||
exporters = exporterNames;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue