Watch
0
0
Fork
You've already forked hyperhive
0

every hive runs its otel collector, and agents export to it by default

This commit is contained in:
atlas 2026-10-18 23:17:28 +02:00 • committed by mara
commit 13daf4c7dc
28 changed files with 245 additions and 303 deletions

View file

@ -47,7 +47,11 @@ let
otel.metricIntervalMs = 10000;
};
agentNoOtel = shared.agentBare;
# Sets nothing: what an agent gets on a hive, whose meta flake renders no
# otel line.
agentDefault = shared.agentBare;
agentNoOtel = agent { otel.enable = false; };
agentSettings = machine: machine.services.opentelemetry-collector.settings;
cases = [
@ -100,11 +104,30 @@ let
&& p.exporters != [ ]
&& lib.all (e: (s.exporters ? ${e}) && s.exporters.${e}.endpoint == agentBridge) p.exporters;
}
{
# 🎯 What the meta flake no longer says: an agent that sets nothing
# exports, to a name rather than an address. The name carries no swarm
# domain and no hive, so the same build is correct on every hive; the
# resolver of the hive it runs on answers it. `agentNoOtel` above is the
# control that these lookups find nothing where the switch is off.
name = "an agent with no otel config exports to the fixed hive-collector name by default";
ok =
let
endpoint = "http://hive-collector.hive:4318";
env = agentDefault.systemd.globalEnvironment;
s = agentSettings agentDefault;
in
agentDefault.services.hyperhive.agent.otel.enable
&& env.OTEL_EXPORTER_OTLP_ENDPOINT == endpoint
&& agentDefault.environment.variables.OTEL_EXPORTER_OTLP_ENDPOINT == endpoint
&& lib.all (e: s.exporters.${e}.endpoint == endpoint) s.service.pipelines.logs.exporters
&& !(agentNoOtel.systemd.globalEnvironment ? OTEL_EXPORTER_OTLP_ENDPOINT);
}
{
# Presence control for the two cases above: with the switch off there
# is no collector in the container at all, so their passing is about
# the wiring rather than about a unit that renders regardless.
name = "an agent that has not opted into telemetry runs no collector";
name = "an agent that switched telemetry off runs no collector";
ok = !agentNoOtel.services.opentelemetry-collector.enable;
}
{

View file

@ -283,11 +283,11 @@ let
{
# The case the old hive-tier gate got wrong: this host runs the swarm's
# collector and no hive collector at all, and the forwarder still exists
# with an address that resolves. Gated on `otel.enable` it rendered
# with an address that resolves. Gated on `otel.collector.enable` it rendered
# nothing here, so the store's journal left no trace anywhere.
name = "a store on a host with no hive collector still forwards";
ok =
!baoWithCollector.services.hyperhive.otel.enable
!baoWithCollector.services.hyperhive.otel.collector.enable
&& (baoForwarder baoWithCollector).enable
&& (baoForwarder baoWithCollector).settings.exporters.otlphttp.endpoint != "";
}

View file

@ -233,18 +233,22 @@ let
&& e.HIVE_AGENT_NATS_URL == e.HIVE_C0RE_NATS_URL;
}
{
# What agents are handed lands in their builds, so it has to be the same
# on every hive: a name, which this hive's resolver answers with the
# bridge IP its collector binds. hive-c0re itself keeps the address.
name = "the agents' collector address is a swarm-wide name this hive resolves to its bridge";
# Agents are handed no address at all: their module defaults to a
# literal name, the same on every hive and in every swarm, which this
# hive's resolver answers with the bridge IP its collector binds.
# hive-c0re itself keeps the address. `HYPERHIVE_OTEL_ENDPOINT` is gone,
# and the bridge address next to it is the control that the lookup on
# the same attrset finds what is there.
name = "the agents' collector address is a fixed name this hive resolves to its bridge";
ok =
let
e = allLocal.systemd.services.hive-c0re.environment;
bridge = allLocal.services.hyperhive.network.bridgeIp;
in
e.HYPERHIVE_OTEL_ENDPOINT == "http://hive-collector.t.local:4318"
!(e ? HYPERHIVE_OTEL_ENDPOINT)
&& e.OTEL_EXPORTER_OTLP_ENDPOINT == "http://${bridge}:4318"
&& lib.elem "/hive-collector.t.local/${bridge}" allLocal.services.dnsmasq.settings.address;
&& allLocal.services.hyperhive.otel.collector.host == "hive-collector.hive"
&& lib.elem "/hive-collector.hive/${bridge}" allLocal.services.dnsmasq.settings.address;
}
{
# The agents mint against the swarm's IdP, the same endpoint the hive's

View file

@ -19,6 +19,7 @@ let
;
})
hive
hiveWithController
runGroup
otelSettings
;
@ -27,24 +28,22 @@ let
# tier's, which lives in a container and is read through `otelSettings`.
# The IdP is here too, with a hand-named secret file: the collector's wait
# for that file exists beside authelia's container.
hiveOtel = hive {
otel.enable = true;
hiveOtel = hiveWithController {
otel.clientSecretFile = "/var/lib/hive-otel-oidc/client.secret";
deploy.authelia.enable = true;
};
# A hive holding its own store leaf, placed by hand, and naming no secret
# file: the collector's secret comes from the store under that leaf.
hiveOtelLeaf = hive {
otel.enable = true;
hiveOtelLeaf = hiveWithController {
gateway.enable = false;
deploy.bao.clientCertFile = "/etc/pki/hive.pem";
deploy.bao.clientKeyFile = "/etc/pki/hive-key.pem";
};
# The IdP, the store and the collector on one host: the publisher that
# writes the secret and the unit that reads it, in one config.
hiveOtelAllLocal = hive {
otel.enable = true;
hiveOtelAllLocal = hiveWithController {
deploy.bao.enable = true;
deploy.authelia.enable = true;
};
@ -144,7 +143,7 @@ let
{
# The receiver, the pipeline entry and the nginx server it reads have to
# agree on one address, and none of them may exist without a gateway on
# the host. `hiveOtelLeaf` is the control: it runs no gateway, and the
# the host. `hiveOtelLeaf` is the control: it opts out of the gateway, and the
# clause asserting that keeps the control from going vacuous.
name = "the hive collector reads the gateway's stub_status, and only where a gateway runs";
ok =

View file

@ -221,7 +221,7 @@ let
in
{
matrix = h.deploy.matrix.enable;
otel = h.otel.enable;
otel = h.otel.collector.enable;
authelia = h.deploy.authelia.enable;
nats = h.deploy.nats.enable;
swarm-otel = h.deploy.swarm-otel.enable;

View file

@ -99,10 +99,9 @@ in
};
# `clientSecretFile` is what ../host-modules/otel.nix's identity assertion
# demands of any hive with the tier on.
baoWithHiveOtel = hive {
# demands of any host running a hive.
baoWithHiveOtel = hiveWithController {
deploy.bao.enable = true;
otel.enable = true;
otel.clientSecretFile = "/var/lib/hive-otel-oidc/client.secret";
};

View file

@ -50,7 +50,6 @@ let
deploy.hive-controller.enable = false;
deploy.allSwarmServices = true;
deploy.matrix.enable = false;
otel.enable = false;
deploy.authelia.enable = false;
deploy.nats.enable = false;
deploy.swarm-otel.enable = false;