From 90272ec3c029203f33c8c33acab14ddf8fd45910 Mon Sep 17 00:00:00 2001 From: atlas Date: Sun, 1 Nov 2026 20:34:50 +0100 Subject: [PATCH] move links, adminSync.ignoreUsers and scrapeTargets under their service's deploy namespace --- docs/integrations/matrix.md | 2 +- docs/swarm/ui.md | 2 +- nix/host-modules/deploy.nix | 12 ++++ nix/host-modules/hive-matrix-service.nix | 12 ---- nix/host-modules/swarm-bao.nix | 2 +- nix/host-modules/swarm-controller.nix | 43 +++++++---- nix/host-modules/swarm-otel-service.nix | 56 +-------------- nix/host-modules/swarm-otel.nix | 72 ++++++++++++++++--- nix/host-modules/swarm-ui.nix | 4 +- nix/module-eval/bao-controller.nix | 2 +- nix/module-eval/core-toggle.nix | 35 ++++++++- nix/module-eval/forge-placement.nix | 2 +- nix/module-eval/nats-authelia.nix | 4 +- nix/module-eval/shared.nix | 2 +- nix/module-eval/swarm-otel-identity.nix | 4 +- nix/module-eval/swarm-services-switch.nix | 4 +- .../src/matrix_account/operator_admin.rs | 2 +- swarm-controller/src/routes/hives.rs | 2 +- swarm-controller/src/startup.rs | 2 +- 19 files changed, 156 insertions(+), 108 deletions(-) diff --git a/docs/integrations/matrix.md b/docs/integrations/matrix.md index 1649b621..9bf0808c 100644 --- a/docs/integrations/matrix.md +++ b/docs/integrations/matrix.md @@ -217,7 +217,7 @@ lands on. - **Admins the sync didn't make keep admin.** An admin missing from that file, `@swarm`, the server user `@conduit:`, every agent's account, and every user id in - `services.hyperhive.swarm.matrix.adminSync.ignoreUsers` are never + `services.hyperhive.deploy.swarm-controller.matrixAdminSync.ignoreUsers` are never revoked. - **The last admin stays.** A revoke that would leave no admin in `#admins` besides `@swarm` and the server user isn't sent; the diff --git a/docs/swarm/ui.md b/docs/swarm/ui.md index d050ad8b..6f699247 100644 --- a/docs/swarm/ui.md +++ b/docs/swarm/ui.md @@ -945,7 +945,7 @@ the subrequest denies it. The swarm UI's header carries a single 🔗 button, visible on every route, opening a popover of links to other swarm-wide services. Backed by `GET /api/links` (swarm-controller), which serves -`services.hyperhive.swarm.controller.links` (a `listOf { label, icon, url }`, +`services.hyperhive.deploy.swarm-controller.links` (a `listOf { label, icon, url }`, same shape as the per-agent `services.hyperhive.agent.dashboardLinks`). Links to swarm services come from swarm-level options, so the list is the diff --git a/nix/host-modules/deploy.nix b/nix/host-modules/deploy.nix index f7be29ec..eabeaec3 100644 --- a/nix/host-modules/deploy.nix +++ b/nix/host-modules/deploy.nix @@ -349,6 +349,18 @@ in [ "services" "hyperhive" "c0re" "nixpkgsFlake" ] [ "services" "hyperhive" "deploy" "builder" "nixpkgsFlake" ] ) + (lib.mkRenamedOptionModule + [ "services" "hyperhive" "swarm" "controller" "links" ] + [ "services" "hyperhive" "deploy" "swarm-controller" "links" ] + ) + (lib.mkRenamedOptionModule + [ "services" "hyperhive" "swarm" "matrix" "adminSync" "ignoreUsers" ] + [ "services" "hyperhive" "deploy" "swarm-controller" "matrixAdminSync" "ignoreUsers" ] + ) + (lib.mkRenamedOptionModule + [ "services" "hyperhive" "swarm" "otel" "scrapeTargets" ] + [ "services" "hyperhive" "deploy" "swarm-otel" "scrapeTargets" ] + ) # The homeserver's port and its firewall switch, removed rather than # renamed: tuwunel listens on a unix socket only the gateway reaches, so # there is no host port to choose or open. diff --git a/nix/host-modules/hive-matrix-service.nix b/nix/host-modules/hive-matrix-service.nix index fa0bb38b..4d538eee 100644 --- a/nix/host-modules/hive-matrix-service.nix +++ b/nix/host-modules/hive-matrix-service.nix @@ -90,18 +90,6 @@ in ''; }; - adminSync.ignoreUsers = lib.mkOption { - type = lib.types.listOf (lib.types.strMatching "@[^:[:space:]]+:[^[:space:]]+"); - default = [ ]; - example = [ "@mara:example.org" ]; - description = '' - Full matrix user ids `swarm-controller`'s operator admin sync never - revokes homeserver admin from. The sync revokes admin only from - accounts it made admin itself, once their owner leaves authelia's - `admins` group; an account listed here keeps admin regardless. - ''; - }; - # This homeserver always delegates login to the swarm's authelia, as # an OIDC relying party — matrix SSO (`m.login.sso`), offered # alongside password login. No toggle: a homeserver in a swarm is a diff --git a/nix/host-modules/swarm-bao.nix b/nix/host-modules/swarm-bao.nix index 3b986232..93c3d58d 100644 --- a/nix/host-modules/swarm-bao.nix +++ b/nix/host-modules/swarm-bao.nix @@ -3033,7 +3033,7 @@ in # granter step, on the host where that step runs. environment.etc."hyperhive/bao-bootstrap-policy.hcl".source = ./bao-bootstrap-policy.hcl; - # 🚫 No `swarm.otel.scrapeTargets.bao` entry, and its absence is + # 🚫 No `deploy.swarm-otel.scrapeTargets.bao` entry, and its absence is # deliberate. That option is read only by the SWARM collector, over # loopback, so a store declared there would have metrics exactly on the # hosts that also run swarm-otel and nowhere else — silently, since a diff --git a/nix/host-modules/swarm-controller.nix b/nix/host-modules/swarm-controller.nix index f0ddfea2..d9a7a5d7 100644 --- a/nix/host-modules/swarm-controller.nix +++ b/nix/host-modules/swarm-controller.nix @@ -391,6 +391,20 @@ in ''; }; + }; + + # What stays above is what the controller IS to the swarm: + # the client id it is registered under, and how stale a + # snapshot may read. What the host running it decides is here — the quick + # links its UI serves, the accounts its matrix admin sync leaves alone, which two + # builds it runs, where its socket lives, and the three credentials it reads + # off local disk. `enable` already lives in ./deploy.nix, which also carries + # the renames. + # + # ⚠️ `deploy.swarm-controller`, NOT `deploy.hive-controller`. Both exist: + # the latter is hive-c0re's namespace, where `tls.*` lives. A definition on + # the wrong one lands on a live, unrelated option rather than failing. + options.services.hyperhive.deploy.swarm-controller = { links = lib.mkOption { type = lib.types.listOf ( lib.types.submodule { @@ -437,19 +451,18 @@ in ''; }; - }; + matrixAdminSync.ignoreUsers = lib.mkOption { + type = lib.types.listOf (lib.types.strMatching "@[^:[:space:]]+:[^[:space:]]+"); + default = [ ]; + example = [ "@mara:example.org" ]; + description = '' + Full matrix user ids the controller's operator admin sync never + revokes homeserver admin from. The sync revokes admin only from + accounts it made admin itself, once their owner leaves authelia's + `admins` group; an account listed here keeps admin regardless. + ''; + }; - # What stays above is what the controller IS to the swarm: the quick-links - # it publishes, the client id it is registered under, and how stale a - # snapshot may read. What the host running it decides is here — which two - # builds it runs, where its socket lives, and the three credentials it reads - # off local disk. `enable` already lives in ./deploy.nix, which also carries - # the renames. - # - # ⚠️ `deploy.swarm-controller`, NOT `deploy.hive-controller`. Both exist: - # the latter is hive-c0re's namespace, where `tls.*` lives. A definition on - # the wrong one lands on a live, unrelated option rather than failing. - options.services.hyperhive.deploy.swarm-controller = { queue = { natsUrl = lib.mkOption { type = lib.types.str; @@ -662,7 +675,7 @@ in }; config = lib.mkIf deployCfg.swarm-controller.enable { - services.hyperhive.swarm.controller.links = swarmServiceLinks; + services.hyperhive.deploy.swarm-controller.links = swarmServiceLinks; users.users.swarm-controller = { isSystemUser = true; @@ -848,7 +861,7 @@ in # The merged links list — see `links`' description above for who # contributes to it. Consumed by `GET /api/links` # (swarm-controller/src/startup.rs::load_links). - SWARM_CONTROLLER_LINKS = builtins.toJSON cfg.links; + SWARM_CONTROLLER_LINKS = builtins.toJSON deployCfg.swarm-controller.links; # Staleness threshold for `GET /api/hives/status` — see # `staleAfterSeconds`' description. Set unconditionally rather # than inside `queueEnv`: it is not a queue coordinate, and @@ -858,7 +871,7 @@ in # The accounts the operator admin sync never revokes. Whitespace- # separated: a matrix user id cannot contain a space. Consumed by # swarm-controller/src/matrix_account/operator_admin.rs. - SWARM_CONTROLLER_MATRIX_ADMIN_SYNC_IGNORE_USERS = lib.concatStringsSep " " matrixCfg.adminSync.ignoreUsers; + SWARM_CONTROLLER_MATRIX_ADMIN_SYNC_IGNORE_USERS = lib.concatStringsSep " " deployCfg.swarm-controller.matrixAdminSync.ignoreUsers; # Where `GET /api/alerts` reads alerts (swarm-controller/src/alerts.rs). # Every swarm has one Grafana, reached by name wherever it runs. The # token is in the store, written by `swarm-bao-grafana-controller-token` diff --git a/nix/host-modules/swarm-otel-service.nix b/nix/host-modules/swarm-otel-service.nix index 4c633263..1eb0a8b0 100644 --- a/nix/host-modules/swarm-otel-service.nix +++ b/nix/host-modules/swarm-otel-service.nix @@ -138,58 +138,6 @@ in ''; }; - 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 - ` = ":"`. 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. - ''; - }; - publishedScrapeTargets = lib.mkOption { type = lib.types.attrsOf lib.types.str; default = { }; @@ -200,7 +148,7 @@ in **Entries are declared swarm-wide**: from this module's `config`, unconditionally, keyed on the service's `swarm..domain`, so - every host evaluates the same set. Unlike `scrapeTargets`, an entry + every host evaluates the same set. Unlike `deploy.swarm-otel.scrapeTargets`, an entry is not declared under the service's own `enable`: the collector reads this list on its host and authelia's registration reads it on authelia's host, and neither need be the service's host. A swarm @@ -222,7 +170,7 @@ in slash, `http` for `https`) presents as a valid token rejected at the target, several layers from its cause. - ⚠️ Deliberately separate from `scrapeTargets`. An entry there is + ⚠️ Deliberately separate from `deploy.swarm-otel.scrapeTargets`. An entry there is trusted because the scraper and the target share a host — that option is loopback-and-unauthenticated by contract. An entry here is trusted because it presents a credential. One shape for both diff --git a/nix/host-modules/swarm-otel.nix b/nix/host-modules/swarm-otel.nix index 31063e98..99f0913b 100644 --- a/nix/host-modules/swarm-otel.nix +++ b/nix/host-modules/swarm-otel.nix @@ -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 + ` = ":"`. 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 :[/][?=]. @@ -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; }; diff --git a/nix/host-modules/swarm-ui.nix b/nix/host-modules/swarm-ui.nix index a8ccfd43..825bfe41 100644 --- a/nix/host-modules/swarm-ui.nix +++ b/nix/host-modules/swarm-ui.nix @@ -177,8 +177,8 @@ in # so — unlike authelia/matrix/forge's entries — this one needs no # host name and is never conditional on anything but this module # being enabled at all. See - # `services.hyperhive.swarm.controller.links`'s description. - services.hyperhive.swarm.controller.links = [ + # `services.hyperhive.deploy.swarm-controller.links`'s description. + services.hyperhive.deploy.swarm-controller.links = [ { label = "API docs"; icon = "🧬"; diff --git a/nix/module-eval/bao-controller.nix b/nix/module-eval/bao-controller.nix index 893f30b7..1e0d0ca3 100644 --- a/nix/module-eval/bao-controller.nix +++ b/nix/module-eval/bao-controller.nix @@ -62,7 +62,7 @@ let controllerPinnedMatrix = hive { deploy.swarm-controller.enable = true; swarm.matrix.gatewayHost = "matrix.hive.t.local"; - swarm.matrix.adminSync.ignoreUsers = [ + deploy.swarm-controller.matrixAdminSync.ignoreUsers = [ "@keep-a:t.local" "@keep-b:t.local" ]; diff --git a/nix/module-eval/core-toggle.nix b/nix/module-eval/core-toggle.nix index ea4411b6..1928e570 100644 --- a/nix/module-eval/core-toggle.nix +++ b/nix/module-eval/core-toggle.nix @@ -1594,6 +1594,15 @@ let victorialogs.port = 19428; forge.httpPort = 13000; matrix.allowEncryption = true; + controller.links = [ + { + label = "Legacy"; + icon = "L"; + url = "https://legacy.example/"; + } + ]; + matrix.adminSync.ignoreUsers = [ "@legacy:t.local" ]; + otel.scrapeTargets.legacy = "127.0.0.1:9777"; }; }; d = old.services.hyperhive.deploy; @@ -1623,6 +1632,19 @@ let && d.forgejo.httpPort == 13000 && d.matrix.allowEncryption && d.builder.nixpkgsFlake == "path:/legacy/nixpkgs" + && lib.any (l: l.label == "Legacy" && l.url == "https://legacy.example/") d.swarm-controller.links + && lib.any (l: l.label == "Legacy") ( + builtins.fromJSON old.systemd.services.swarm-controller.environment.SWARM_CONTROLLER_LINKS + ) + && d.swarm-controller.matrixAdminSync.ignoreUsers == [ "@legacy:t.local" ] + && + old.systemd.services.swarm-controller.environment.SWARM_CONTROLLER_MATRIX_ADMIN_SYNC_IGNORE_USERS + == "@legacy:t.local" + && d.swarm-otel.scrapeTargets.legacy == "127.0.0.1:9777" + && + (lib.findFirst (j: j.job_name == "legacy") null ( + (otelSettings old).receivers.prometheus.config.scrape_configs + )).static_configs == [ { targets = [ "127.0.0.1:9777" ]; } ] && old.containers.swarm-builder.config.systemd.services.swarm-builder.environment.SWARM_BUILDER_NIXPKGS_FLAKE == "path:/legacy/nixpkgs" @@ -1642,6 +1664,9 @@ let "swarm.forge.httpPort" "swarm.matrix.allowEncryption" "c0re.nixpkgsFlake" + "swarm.controller.links" + "swarm.matrix.adminSync.ignoreUsers" + "swarm.otel.scrapeTargets" ] && !(lib.any (w: lib.hasInfix "swarm.controller.queue" w) allLocal.warnings) && refused old "deploy.nats.otel.telemetryPort" @@ -1672,7 +1697,15 @@ let && (locs h.swarm.nats.domain)."= /metrics".proxyPass == "http://127.0.0.1:7777/metrics" && (locs h.swarm.victorialogs.domain)."= /metrics".proxyPass == "http://127.0.0.1:9428/metrics" && (locs h.swarm.forge.domain)."/".proxyPass == "http://127.0.0.1:3000/" - && !allLocal.containers.hive-matrix.config.services.matrix-tuwunel.settings.global.allow_encryption; + && !allLocal.containers.hive-matrix.config.services.matrix-tuwunel.settings.global.allow_encryption + && env.SWARM_CONTROLLER_MATRIX_ADMIN_SYNC_IGNORE_USERS == "" + && lib.any (l: l.label == "Forge" && l.url == "https://${h.swarm.forge.domain}/") ( + builtins.fromJSON env.SWARM_CONTROLLER_LINKS + ) + && + (lib.findFirst (j: j.job_name == "collector") null ( + (otelSettings allLocal).receivers.prometheus.config.scrape_configs + )).static_configs == [ { targets = [ "127.0.0.1:8889" ]; } ]; } { # Each old spelling lands on the new path, with its own rename warning; diff --git a/nix/module-eval/forge-placement.nix b/nix/module-eval/forge-placement.nix index da8b5c1e..4c275940 100644 --- a/nix/module-eval/forge-placement.nix +++ b/nix/module-eval/forge-placement.nix @@ -127,7 +127,7 @@ let name = "a host running the collector, authelia, grafana and nats scrapes none of them on loopback"; ok = let - t = servicesHere.services.hyperhive.swarm.otel.scrapeTargets; + t = servicesHere.services.hyperhive.deploy.swarm-otel.scrapeTargets; in servicesHere.services.hyperhive.deploy.nats.enable && !(t ? authelia) diff --git a/nix/module-eval/nats-authelia.nix b/nix/module-eval/nats-authelia.nix index 98d3e025..72ca0c04 100644 --- a/nix/module-eval/nats-authelia.nix +++ b/nix/module-eval/nats-authelia.nix @@ -300,8 +300,8 @@ let name = "authelia and nats declare no scrape target on a host with no collector"; ok = !(autheliaAndNats.services.hyperhive.deploy.swarm-otel.enable) - && !(autheliaAndNats.services.hyperhive.swarm.otel.scrapeTargets ? authelia) - && !(autheliaAndNats.services.hyperhive.swarm.otel.scrapeTargets ? nats); + && !(autheliaAndNats.services.hyperhive.deploy.swarm-otel.scrapeTargets ? authelia) + && !(autheliaAndNats.services.hyperhive.deploy.swarm-otel.scrapeTargets ? nats); } { # The xkey and the responder's OIDC client secret are read only from diff --git a/nix/module-eval/shared.nix b/nix/module-eval/shared.nix index 885cd8e5..1e414a17 100644 --- a/nix/module-eval/shared.nix +++ b/nix/module-eval/shared.nix @@ -100,7 +100,7 @@ in baoWithCollector = hive { deploy.bao.enable = true; deploy.swarm-otel.enable = true; - swarm.otel.scrapeTargets.plain = "127.0.0.1:9999"; + deploy.swarm-otel.scrapeTargets.plain = "127.0.0.1:9999"; }; # `clientSecretFile` is what ../host-modules/otel.nix's identity assertion diff --git a/nix/module-eval/swarm-otel-identity.nix b/nix/module-eval/swarm-otel-identity.nix index f61f9105..83588c37 100644 --- a/nix/module-eval/swarm-otel-identity.nix +++ b/nix/module-eval/swarm-otel-identity.nix @@ -81,7 +81,7 @@ let # is a running collector with no self-scrape, not an absent one. otelOnlyPublished = hive { deploy.swarm-otel.enable = true; - swarm.otel.scrapeTargets = lib.mkForce { }; + deploy.swarm-otel.scrapeTargets = lib.mkForce { }; swarm.otel.publishedScrapeTargets.remote = "https://remote.t.local/metrics"; }; @@ -175,7 +175,7 @@ let let s = otelSettings otelOnlyPublished; in - otelOnlyPublished.services.hyperhive.swarm.otel.scrapeTargets == { } + otelOnlyPublished.services.hyperhive.deploy.swarm-otel.scrapeTargets == { } && otelOnlyPublished.services.hyperhive.swarm.otel.publishedScrapeTargets != { } && (s.receivers ? prometheus) && builtins.elem "prometheus" s.service.pipelines."metrics/swarm".receivers; diff --git a/nix/module-eval/swarm-services-switch.nix b/nix/module-eval/swarm-services-switch.nix index 84db09a7..839c7888 100644 --- a/nix/module-eval/swarm-services-switch.nix +++ b/nix/module-eval/swarm-services-switch.nix @@ -167,7 +167,9 @@ let }; swarmServiceLinksOf = cfg: - lib.filter (l: swarmServiceLinkDomains ? ${l.label}) cfg.services.hyperhive.swarm.controller.links; + lib.filter ( + l: swarmServiceLinkDomains ? ${l.label} + ) cfg.services.hyperhive.deploy.swarm-controller.links; # Every service container at once: the services-only host plus the CI # runner. The CI runner, the review classifier, the notification router, the diff --git a/swarm-controller/src/matrix_account/operator_admin.rs b/swarm-controller/src/matrix_account/operator_admin.rs index a4ffaddd..aabd268d 100644 --- a/swarm-controller/src/matrix_account/operator_admin.rs +++ b/swarm-controller/src/matrix_account/operator_admin.rs @@ -54,7 +54,7 @@ const SERVER_USER_LOCALPART: &str = "conduit"; const GRANTED_FILE: &str = "operator-matrix-admins.json"; /// Whitespace-separated user ids the revoke never touches, set from -/// `services.hyperhive.swarm.matrix.adminSync.ignoreUsers`. +/// `services.hyperhive.deploy.swarm-controller.matrixAdminSync.ignoreUsers`. const IGNORE_USERS_ENV: &str = "SWARM_CONTROLLER_MATRIX_ADMIN_SYNC_IGNORE_USERS"; /// The localpart an SSO login by authelia user `username` lands on, or `None` diff --git a/swarm-controller/src/routes/hives.rs b/swarm-controller/src/routes/hives.rs index 74301cf2..6b518ad2 100644 --- a/swarm-controller/src/routes/hives.rs +++ b/swarm-controller/src/routes/hives.rs @@ -37,7 +37,7 @@ pub(crate) async fn get_hives(State(state): State) -> Json Vec { } /// Env var the controller's NixOS module sets from the merged -/// `services.hyperhive.swarm.controller.links` list, JSON-encoded — same +/// `services.hyperhive.deploy.swarm-controller.links` list, JSON-encoded — same /// shape/rationale as [`HIVES_ENV`]. Consumed by `GET /api/links`. const LINKS_ENV: &str = "SWARM_CONTROLLER_LINKS";