Compare commits
2 changed files with 41 additions and 129 deletions
|
|
@ -181,33 +181,6 @@ in
|
|||
addresses its siblings by name.
|
||||
'';
|
||||
};
|
||||
|
||||
scrapeTargets = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.str;
|
||||
default = { };
|
||||
example = lib.literalExpression ''{ forgejo = "127.0.0.1:3000"; }'';
|
||||
description = ''
|
||||
Prometheus exposition endpoints this collector scrapes, as
|
||||
`<job name> = "<host>:<port>"`.
|
||||
|
||||
**A service declares its own entry, from its own module, under its
|
||||
own `enable`.** That is what puts the scraper and the target on the
|
||||
same host by construction rather than by luck: an entry exists only
|
||||
where the service that named it runs. Do not assemble the list here.
|
||||
Every swarm service being co-located is a property of the all-local
|
||||
deployment, not a guarantee — and that is precisely the case where
|
||||
the difference is invisible until a swarm splits across hosts.
|
||||
|
||||
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.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf (config.services.hyperhive.enable && cfg.enable) {
|
||||
|
|
@ -414,32 +387,15 @@ in
|
|||
# an auth claim yields nothing — silently, with a healthy
|
||||
# startup), and one receiver holding many credentials never
|
||||
# reveals which one matched.
|
||||
receivers =
|
||||
lib.mapAttrs' (
|
||||
h: p:
|
||||
lib.nameValuePair "otlp/${h}" {
|
||||
protocols.http = {
|
||||
endpoint = "127.0.0.1:${toString p}";
|
||||
auth.authenticator = "oidc/${h}";
|
||||
};
|
||||
}
|
||||
) hivePorts
|
||||
# MERGED with the per-hive receivers, never assigned over
|
||||
# them. A plain assignment here would drop every hive's
|
||||
# receiver and still render a valid config that starts
|
||||
# cleanly — the collector has no opinion about how many
|
||||
# pipelines it was supposed to have.
|
||||
#
|
||||
# Only emitted when a service has actually declared a
|
||||
# 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 != { }) {
|
||||
prometheus.config.scrape_configs = lib.mapAttrsToList (job: target: {
|
||||
job_name = job;
|
||||
static_configs = [ { targets = [ target ]; } ];
|
||||
}) cfg.scrapeTargets;
|
||||
};
|
||||
receivers = lib.mapAttrs' (
|
||||
h: p:
|
||||
lib.nameValuePair "otlp/${h}" {
|
||||
protocols.http = {
|
||||
endpoint = "127.0.0.1:${toString p}";
|
||||
auth.authenticator = "oidc/${h}";
|
||||
};
|
||||
}
|
||||
) hivePorts;
|
||||
|
||||
exporters =
|
||||
lib.optionalAttrs vmCfg.enable {
|
||||
|
|
@ -496,28 +452,14 @@ in
|
|||
# `exporterNames` is shared by every pipeline — where a
|
||||
# sample goes is a property of this tier, not of the hive
|
||||
# that sent it.
|
||||
service.pipelines =
|
||||
lib.mapAttrs' (
|
||||
h: _:
|
||||
lib.nameValuePair "metrics/${h}" {
|
||||
receivers = [ "otlp/${h}" ];
|
||||
processors = [ "resource/${h}" ];
|
||||
exporters = exporterNames;
|
||||
}
|
||||
) hivePorts
|
||||
# Its OWN pipeline, and that separation is the ruling, not a
|
||||
# tidiness choice: every `resource/<hive>` above UPSERTS a
|
||||
# `hive` key, so a scraped swarm sample routed through any of
|
||||
# them would acquire the one label a swarm-level service must
|
||||
# not have. Keeping it out of them makes the absence
|
||||
# structural rather than something to remember to strip.
|
||||
// lib.optionalAttrs (cfg.scrapeTargets != { }) {
|
||||
"metrics/swarm" = {
|
||||
receivers = [ "prometheus" ];
|
||||
processors = [ "resource/swarm" ];
|
||||
exporters = exporterNames;
|
||||
};
|
||||
};
|
||||
service.pipelines = lib.mapAttrs' (
|
||||
h: _:
|
||||
lib.nameValuePair "metrics/${h}" {
|
||||
receivers = [ "otlp/${h}" ];
|
||||
processors = [ "resource/${h}" ];
|
||||
exporters = exporterNames;
|
||||
}
|
||||
) hivePorts;
|
||||
}
|
||||
// {
|
||||
extensions = lib.mapAttrs' (
|
||||
|
|
@ -565,51 +507,36 @@ in
|
|||
# processor is the whole attribution boundary — the value
|
||||
# is a constant per receiver, so it says which hive
|
||||
# authenticated, not which hive claimed to be sending.
|
||||
processors =
|
||||
lib.mapAttrs' (
|
||||
h: _:
|
||||
lib.nameValuePair "resource/${h}" {
|
||||
attributes = [
|
||||
{
|
||||
key = "hive";
|
||||
value = h;
|
||||
action = "upsert";
|
||||
}
|
||||
# Stamped here rather than on a separate upstream-only
|
||||
# pipeline, which would double the pipeline count to
|
||||
# withhold one constant label from the local store. It
|
||||
# is redundant there — one VictoriaMetrics per swarm, so
|
||||
# every series in it already belongs to this swarm — but
|
||||
# a constant label multiplies no series, and it means
|
||||
# what LEAVES and what STAYS have the same shape.
|
||||
#
|
||||
# Upstream is where it stops being redundant: that is the
|
||||
# one hop where several swarms can land in one store, and
|
||||
# samples that cannot name their swarm collide there
|
||||
# exactly as hives collided here before per-hive
|
||||
# receivers existed.
|
||||
{
|
||||
key = "swarm";
|
||||
value = swarmDisplayName;
|
||||
action = "upsert";
|
||||
}
|
||||
];
|
||||
}
|
||||
) hivePorts
|
||||
# The swarm tier's own stamp: `swarm` and deliberately NO
|
||||
# `hive`. A scraped swarm service belongs to the swarm, not to
|
||||
# any one hive, so there is no honest value to put there — and
|
||||
# an invented one (a sentinel, the local hive's name) would be
|
||||
# queried as though it meant something.
|
||||
// lib.optionalAttrs (cfg.scrapeTargets != { }) {
|
||||
"resource/swarm".attributes = [
|
||||
processors = lib.mapAttrs' (
|
||||
h: _:
|
||||
lib.nameValuePair "resource/${h}" {
|
||||
attributes = [
|
||||
{
|
||||
key = "hive";
|
||||
value = h;
|
||||
action = "upsert";
|
||||
}
|
||||
# Stamped here rather than on a separate upstream-only
|
||||
# pipeline, which would double the pipeline count to
|
||||
# withhold one constant label from the local store. It
|
||||
# is redundant there — one VictoriaMetrics per swarm, so
|
||||
# every series in it already belongs to this swarm — but
|
||||
# a constant label multiplies no series, and it means
|
||||
# what LEAVES and what STAYS have the same shape.
|
||||
#
|
||||
# Upstream is where it stops being redundant: that is the
|
||||
# one hop where several swarms can land in one store, and
|
||||
# samples that cannot name their swarm collide there
|
||||
# exactly as hives collided here before per-hive
|
||||
# receivers existed.
|
||||
{
|
||||
key = "swarm";
|
||||
value = swarmDisplayName;
|
||||
action = "upsert";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
) hivePorts;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -113,21 +113,6 @@ in
|
|||
}
|
||||
];
|
||||
|
||||
# This store publishes its own health as prometheus metrics on the same
|
||||
# listener it serves queries on, so the swarm's collector can scrape it
|
||||
# with no exporter and no extra port.
|
||||
#
|
||||
# Declared here rather than in the collector's module because that is the
|
||||
# rule the option carries: an entry exists only where the service that
|
||||
# named it runs, which is what keeps scraper and target on one host by
|
||||
# construction instead of by luck.
|
||||
#
|
||||
# The loopback literal introduces no new assumption — it is the address
|
||||
# this module already pins the listener to, and the same one the
|
||||
# collector's `otlphttp/victoriametrics` exporter already writes to. If
|
||||
# that reach is ever wrong, it is wrong for the write path first.
|
||||
services.hyperhive.swarm.otel.scrapeTargets.victoriametrics = "127.0.0.1:${toString cfg.port}";
|
||||
|
||||
services.nginx.virtualHosts."${cfg.domain}" = (gatewayCfg.lib.tlsFor cfg.domain) // {
|
||||
listen = gatewayCfg.lib.listen;
|
||||
extraConfig = gatewayCfg.lib.securityHeaders;
|
||||
|
|
|
|||
Loading…
Reference in a new issue