Watch
0
0
Fork
You've already forked hyperhive
0

agents: read the hive's name and domain at runtime, not from the build

Part of #5081 (slice S0-1a). An agent's closure no longer depends on the
name or domain of the hive that renders it.

- hive-priv writes /etc/hyperhive-hive-facts (HYPERHIVE_HIVE_NAME,
  HYPERHIVE_HIVE_DOMAIN) into the container from the same WriteNspawnFlags
  call that writes /etc/hyperhive-bridge-dns. hive-c0re passes the values
  from its own unit env. hive-priv refuses a value outside [A-Za-z0-9._-].
- A systemd environment generator in the agent (hive-facts.nix) loads the
  file into the container manager's environment, so every unit sees it,
  as with the systemd.globalEnvironment entries the render used to emit.
  It also builds CLAUDE_REMOTE_CONTROL_SESSION_NAME_PREFIX
  (<hive>-<agent>), which left claude's managed settings.
- meta.rs stops forwarding HYPERHIVE_HIVE_{NAME,DOMAIN} and stops setting
  services.hyperhive.agent.hiveName. The option is removed (both
  spellings now fail with a removal message).
- otel.nix drops the agent's hive= resource label. The swarm collector
  upserts hive per authenticated receiver (swarm-otel.nix resource/<h>,
  on both the metrics and logs pipelines), so stored series keep it.

The otel first hop, otel enable and the dashboard port are still baked;
they are S0-1b.
This commit is contained in:
atlas 2026-10-12 04:40:13 +02:00 • committed by mara
commit c87a4d2c1a
14 changed files with 303 additions and 127 deletions

View file

@ -25,17 +25,10 @@
let
cfg = config.services.hyperhive.agent.otel;
userName = config.services.hyperhive.agent.user.name;
# Hive/swarm display names, read from the per-agent options meta.rs
# renders (NOT from `environment.variables` — those carry the same
# names at *runtime* only, so reading them here silently yielded
# "unknown" on every agent while the process env held the right
# answer). `null` means the hive did not name itself; "unknown" is then
# an honest label rather than a guess.
hiveDisplayName =
if config.services.hyperhive.agent.hiveName == null then
"unknown"
else
config.services.hyperhive.agent.hiveName;
# Swarm display name, read from the per-agent option meta.rs renders
# (NOT from `environment.variables`, which carries it at *runtime*
# only). `null` means the swarm is unnamed; "unknown" is then an honest
# label rather than a guess.
swarmDisplayName =
if config.services.hyperhive.agent.swarmName == null then
"unknown"
@ -45,9 +38,11 @@ let
# Resource labels every producer in this container stamps on what it
# emits. `service.name` names the container's role, not one binary
# inside it: claude's samples and `hive-metric`'s both come from this
# agent, and their metric names already tell them apart.
# agent, and their metric names already tell them apart. No `hive`: the
# swarm collector stamps it from the receiver that accepted the hive's
# push (nix/host-modules/swarm-otel.nix), so the build names no hive.
resourceAttributes =
"service.name=hyperhive-agent,agent=${userName},hive=${hiveDisplayName},swarm=${swarmDisplayName}"
"service.name=hyperhive-agent,agent=${userName},swarm=${swarmDisplayName}"
+ lib.optionalString (cfg.extraResourceAttributes != "") ",${cfg.extraResourceAttributes}";
# The variables an OTEL SDK reads on its own, in any language, in any
@ -131,7 +126,7 @@ in
description = ''
Extra comma-separated entries appended to
`OTEL_RESOURCE_ATTRIBUTES` after the built-in
`service.name` / `agent` / `hive` / `swarm` labels.
`service.name` / `agent` / `swarm` labels.
Host-driven via `services.hyperhive.otel.extraResourceAttributes`.
'';
};
@ -274,10 +269,9 @@ in
# Identity the hop above cannot supply. A host-side reader can say
# which machine a line came from; only a collector running as the
# agent can say which agent. `hive` and `swarm` are deliberately
# NOT stamped here even though the env above carries them for
# in-process producers: the swarm tier upserts `hive` from the
# receiver that accepted the sample, precisely so the label comes
# from something the sender cannot write.
# NOT stamped here: the swarm tier upserts both from the receiver
# that accepted the sample, precisely so the labels come from
# something the sender cannot write.
processors.resource.attributes = [
{
key = "service.name";