Compare commits

..
3 changed files with 66 additions and 68 deletions

View file

@ -750,20 +750,37 @@ in
HYPERHIVE_SWARM_NAME = config.services.hyperhive.swarmName; HYPERHIVE_SWARM_NAME = config.services.hyperhive.swarmName;
} }
// lib.optionalAttrs config.services.hyperhive.forge.enable { // lib.optionalAttrs config.services.hyperhive.forge.enable {
# In-cluster forge URL — the gateway vhost (`forge.<domain>`), which # In-cluster forge URL.
# nginx proxies to forgejo. Set directly: this env only exists when # - Isolated (private netns): containers resolve `forge.<domain>` via
# hyperhive is enabled. See `docs/gateway.md::HIVE_FORGE_URL`. # the bridge dnsmasq and reach nginx on port 80. No raw forge port
HIVE_FORGE_URL = "http://${config.services.hyperhive.forge.domain}"; # needed — nginx proxies to forgejo as it does for the operator.
# - Shared netns: host loopback is reachable, use direct port.
# See `docs/gateway.md::HIVE_FORGE_URL`.
HIVE_FORGE_URL =
if
config.services.hyperhive.network.enable && config.services.hyperhive.network.isolateContainers
then
"http://${config.services.hyperhive.forge.domain}"
else
"http://127.0.0.1:${toString config.services.hyperhive.forge.httpPort}";
} }
// lib.optionalAttrs config.services.hyperhive.matrix.enable { // lib.optionalAttrs config.services.hyperhive.matrix.enable {
# In-cluster matrix homeserver URL for each agent's # In-cluster matrix homeserver URL for each agent's
# hive-matrix-daemon — the gateway vhost (`matrix.<domain>`). The # hive-matrix-daemon. Same shape + rationale as HIVE_FORGE_URL:
# - Isolated (private netns): reach tuwunel via the gateway vhost
# (`matrix.<domain>`) on plain http:80 — host loopback is dead.
# - Shared netns: direct host loopback on the tuwunel port.
# gatewayHost null-guard falls back to loopback so a domain-less # gatewayHost null-guard falls back to loopback so a domain-less
# config still evals. Forwarded to agents by meta.rs alongside # config doesn't break eval (it just won't work under isolation,
# HIVE_FORGE_URL; shares the same env-forwarding ordering caveat # which needs a gateway anyway). Forwarded to agents by meta.rs
# (value baked at config-generation time). # alongside HIVE_FORGE_URL; shares the same env-forwarding ordering
# caveat (value baked at config-generation time).
HIVE_MATRIX_URL = HIVE_MATRIX_URL =
if config.services.hyperhive.matrix.gatewayHost != null then if
config.services.hyperhive.network.enable
&& config.services.hyperhive.network.isolateContainers
&& config.services.hyperhive.matrix.gatewayHost != null
then
"http://${config.services.hyperhive.matrix.gatewayHost}" "http://${config.services.hyperhive.matrix.gatewayHost}"
else else
"http://127.0.0.1:${toString config.services.hyperhive.matrix.httpPort}"; "http://127.0.0.1:${toString config.services.hyperhive.matrix.httpPort}";

View file

@ -377,7 +377,7 @@ in
# `environment.etc."resolv.conf".text` is `nameserver <bridgeIp>`. # `environment.etc."resolv.conf".text` is `nameserver <bridgeIp>`.
# This container always shares the host netns # This container always shares the host netns
# (`privateNetwork = false`), so it reaches `bridgeIp` regardless # (`privateNetwork = false`), so it reaches `bridgeIp` regardless
# of agent-container isolation. Network module off → inherit the host's # of `isolateContainers`. Network module off → inherit the host's
# resolv.conf. See `docs/network.md`. # resolv.conf. See `docs/network.md`.
networking = lib.mkMerge [ networking = lib.mkMerge [
(lib.mkIf networkCfg.enable { (lib.mkIf networkCfg.enable {

View file

@ -19,18 +19,18 @@ in
defaultText = lib.literalExpression "config.services.hyperhive.enable"; defaultText = lib.literalExpression "config.services.hyperhive.enable";
example = false; example = false;
description = '' description = ''
**DEPRECATED ignored.** The hive network (bridge + dnsmasq Stand up the hive-internal bridge + dnsmasq resolver.
resolver + private-netns isolation) is now always on whenever Defaults to `config.services.hyperhive.enable` so it comes
hyperhive is enabled; setting this to `false` warns and has no on automatically with the rest of hyperhive. Requires
effect. Retained as a no-op so existing configs eval; will be `services.hyperhive.domain` to be set the dnsmasq resolver
removed in a future release. is authoritative for `<hive-domain>` and its sub-domains.
When enabled: a bridge interface (`bridgeName`) appears on the
The network requires `services.hyperhive.domain` to be set the host with `bridgeIp` assigned, and the hive-gateway container
dnsmasq resolver is authoritative for `<hive-domain>` and its runs a dnsmasq listening on that IP for `<hive-domain>` +
sub-domains. A bridge interface (`bridgeName`) appears on the host sub-domains. Agent containers still default to shared host
with `bridgeIp` assigned, the hive-gateway container runs a dnsmasq netns the endpoint is up but only used once
on that IP, and each agent container runs in a private netns with a `isolateContainers = true` flips containers to private netns
veth pair on the bridge. + veth peers on this bridge.
''; '';
}; };
@ -94,16 +94,11 @@ in
isolateContainers = lib.mkOption { isolateContainers = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
default = true; default = false;
example = true; example = true;
description = '' description = ''
**DEPRECATED ignored.** Network isolation is now the only mode and Flip agent containers from shared host netns to private netns.
is always on whenever hyperhive is enabled; the shared-netns path was When true, each agent container gets a dedicated veth
removed. This option is retained as a no-op so existing configs eval;
setting it to `false` warns and has no effect. It will be removed in
a future release.
Each agent container gets a dedicated veth
pair attached to `bridgeName` and a deterministic IP from pair attached to `bridgeName` and a deterministic IP from
the bridge subnet. The bridge (already up when `enable = true`) the bridge subnet. The bridge (already up when `enable = true`)
becomes the sole routed path between the host and agent becomes the sole routed path between the host and agent
@ -147,27 +142,21 @@ in
}; };
config = lib.mkMerge [ config = lib.mkMerge [
# The hive network + container isolation are unconditional whenever (lib.mkIf cfg.enable {
# hyperhive is enabled: the shared-netns mode was removed, so there is
# one mode (private netns behind the bridge). `network.enable` and
# `isolateContainers` are kept as deprecated no-op options (see the
# warnings block below) so existing configs that set them still eval.
(lib.mkIf config.services.hyperhive.enable {
assertions = [ assertions = [
{ {
assertion = config.services.hyperhive.domain != null; assertion = config.services.hyperhive.domain != null;
message = '' message = ''
hyperhive requires services.hyperhive.domain to be set the services.hyperhive.network.enable = true requires
hive resolver is authoritative for `<hive-domain>` and its services.hyperhive.domain to be set the resolver needs a
sub-domains, and agents reach the forge/matrix through the domain to be authoritative for. Either pin a hostname
gateway by that domain. Pin a hostname (`services.hyperhive.domain = "example.com";`) or set
(`services.hyperhive.domain = "example.com";`). `services.hyperhive.network.enable = false` explicitly.
''; '';
} }
]; ];
# Virtual bridge — each agent container attaches a veth pair (isolation # Virtual bridge — veth pairs attach when isolateContainers flips on.
# is unconditional now).
networking.bridges.${cfg.bridgeName}.interfaces = [ ]; networking.bridges.${cfg.bridgeName}.interfaces = [ ];
# Bridge IP — dnsmasq (in the gateway container) binds here. # Bridge IP — dnsmasq (in the gateway container) binds here.
@ -185,9 +174,23 @@ in
}; };
}) })
# Container isolation overlay — now unconditional (the shared-netns # Guard: fires unconditionally on isolateContainers so the assertion
# mode was removed). See docs/network.md#container-isolation. # is not silently swallowed when enable=false.
(lib.mkIf config.services.hyperhive.enable { (lib.mkIf cfg.isolateContainers {
assertions = [
{
assertion = cfg.enable;
message = ''
services.hyperhive.network.isolateContainers = true requires
services.hyperhive.network.enable = true (the bridge and
resolver must be running before isolation is flipped on).
'';
}
];
})
# Container isolation overlay — see docs/network.md#container-isolation.
(lib.mkIf (cfg.enable && cfg.isolateContainers) {
# Agents route internet traffic via the bridge; NAT masquerades their RFC-1918 IPs. # Agents route internet traffic via the bridge; NAT masquerades their RFC-1918 IPs.
boot.kernel.sysctl."net.ipv4.ip_forward" = 1; boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
@ -219,27 +222,5 @@ in
HIVE_NETWORK_SUBNET = "${cfg.bridgeIp}/${toString cfg.bridgePrefixLength}"; HIVE_NETWORK_SUBNET = "${cfg.bridgeIp}/${toString cfg.bridgePrefixLength}";
}; };
}) })
# Deprecation surface for the removed toggles. Both options are kept so
# existing configs that set them to `true` still eval cleanly; setting
# either to `false` no longer does anything (network + isolation are
# unconditional now), so warn rather than silently ignore.
{
# Only warn when hyperhive itself is enabled — otherwise `cfg.enable`
# defaults to `false` (tracking `hyperhive.enable`) and we'd fire a
# spurious deprecation warning on a host that doesn't run hyperhive.
warnings = lib.optionals config.services.hyperhive.enable (
lib.optional (!cfg.enable) ''
services.hyperhive.network.enable = false is deprecated and ignored
the hive network is now always on (private-netns isolation is the
only mode). Remove the setting.
''
++ lib.optional (!cfg.isolateContainers) ''
services.hyperhive.network.isolateContainers = false is deprecated
and ignored network isolation is now the only mode and is always
on. Remove the setting.
''
);
}
]; ];
} }