# The all-local deployment mode. # # `enableAllLocalDefaults` is a *mode*, not a default other options read: # it says "this box is the whole deployment" and then asserts the values # that follow from that. mara, on the issue: it is "more of a deployment # mode via settings set, less a default setting". # # That distinction is why the derivations live here as `mkDefault` in a # `config` block rather than as `default =` inside each option. An option # declares what IT is and what it is when nobody asks; a mode declares # what a deployment shape implies. Written the other way round, every # service option had to name a flag it has no relationship to, and the # answer to "what does all-local turn on?" was spread across five files. # # Adding an autoconfigurable thing later means one line here — not a # `default =` in the new module pointing back at this flag. { lib, config, ... }: let cfg = config.services.hyperhive; in { options.services.hyperhive.enableAllLocalDefaults = lib.mkOption { type = lib.types.bool; default = false; example = true; description = '' Run the whole swarm on this host. Turning this on asserts the toggles that an all-on-one-box deployment implies: the swarm's shared services (`services.hyperhive.swarm.enableRequiredServices`), the swarm CA (`services.hyperhive.swarm.ca.autoConfigure`), the swarm controller (`services.hyperhive.swarm.controller.enable`), and the host's `/etc/hosts` entries for the names this hive serves (`services.hyperhive.gateway.localHostsEntry`) — with no real DNS for those names, the operator is browsing them from the same box that answers for them. **Off by default, and that is the load-bearing part.** A swarm's services and its hives can live on different hosts, and a host has no way to tell which ones it is meant to be — so this is an operator saying "this is that box", never something inferred. Turn it on for a dev box or a single-hive swarm and get a working deployment with no further configuration; leave it off and every swarm-level artifact is operator-provided. Each toggle it asserts can still be set explicitly, which wins — so "all local except X" needs no new option. ''; }; # What the mode asserts. `mkDefault` (priority 1000) beats an option's # own `default` (1500) and loses to any explicit definition, which is # exactly the precedence a deployment mode wants: it fills in for an # operator who hasn't spoken, and never argues with one who has. # The gateway's own all-local bit. `localHostsEntry` maps every name # this hive answers for to 127.0.0.1 in the HOST's /etc/hosts, which is # exactly what "this box is the whole deployment" implies: there is no # real DNS for these names, and the operator is browsing them from the # same machine that serves them. # # ⚠️ It does NOT affect what containers resolve. dnsmasq sets # `no-hosts = true` unconditionally (see hive-gateway/dnsmasq.nix), so # agents keep getting the bridge IP from the authoritative `address=` # rules rather than the host's 127.0.0.1 — an entry that would point # every agent at its own netns. That guard already existing is what # makes turning this on by default safe; without it this line would # break every agent's access to the forge. config.services.hyperhive.gateway.localHostsEntry = lib.mkDefault cfg.enableAllLocalDefaults; config.services.hyperhive.swarm = { enableRequiredServices = lib.mkDefault cfg.enableAllLocalDefaults; ca.autoConfigure = lib.mkDefault cfg.enableAllLocalDefaults; # The queue's auth-callout nkeys. Generating them is safe exactly # when one operator owns both the queue and its responder, which is # what this mode asserts. On any other topology the seeds have to # reach whoever runs the responder, and minting them here would move # that hand-off somewhere less visible rather than removing it. nats.autoGenerateCallout = lib.mkDefault cfg.enableAllLocalDefaults; # The controller is asserted by the MODE and by nothing else. Its own # option stays `default = false` precisely because running it is a # statement about swarm topology — but "this box is the whole # deployment" IS that statement, and it is the one shape where the # answer isn't ambiguous. Deriving it from `enableRequiredServices` # instead would be wrong: a hive in a larger swarm can legitimately # want the shared services without being the host that controls them. controller.enable = lib.mkDefault cfg.enableAllLocalDefaults; # The controller's queue coordinates. Co-location is what makes these # derivable at all — loopback only reaches the queue when the queue is # here, and the minted client secret only exists on the host authelia # ran its first boot on — so they belong to the mode that asserts this # box is the whole deployment, not to the options' own `default`. # # Deriving them from `swarm.nats.enable` / `swarm.authelia.enable` # inside those defaults is the mixing this file exists to prevent: the # option would be describing a deployment shape instead of describing # itself, and "what does all-local turn on?" would stop having one # answer. # # ⚠️ Must live INSIDE this attrset, not as a second # `config.services.hyperhive.swarm.…` path beside it — written that # way the two definitions of `swarm` collide and the nested one is # silently lost. The gate caught exactly that: mode on, `natsUrl` # still "". # # The *requirement* stays in `swarm-controller.nix` as an assertion: # needing a queue is the controller's own property in every topology, # and only the convenience is local. controller.queue.natsUrl = lib.mkIf cfg.enableAllLocalDefaults ( lib.mkDefault "nats://127.0.0.1:${toString config.services.hyperhive.swarm.nats.port}" ); controller.queue.clientSecretFile = lib.mkIf cfg.enableAllLocalDefaults ( lib.mkDefault "${config.services.hyperhive.swarm.authelia.hostClientSecretDir}/swarm-controller.secret" ); }; }