Watch
0
0
Fork
You've already forked hyperhive
0

nix: move the in-container modules to nix/container-modules/

Refs #3773
This commit is contained in:
atlas 2026-09-29 19:27:40 +02:00 • committed by mara
commit cce41c1d79
11 changed files with 10 additions and 10 deletions

View file

@ -711,7 +711,7 @@ in
# Both units that make an outbound call are consumers, for the
# same reason the trust bundle below names both: an unordered
# resolver write is a race that only shows up on a cold boot.
(import ./../swarm-container-resolver.nix {
(import ./../../container-modules/swarm-container-resolver.nix {
inherit (networkCfg) bridgeIp;
dnsConsumers = [
"forgejo.service"

View file

@ -1224,7 +1224,7 @@ in
{ ... }:
{
imports = [
(import ./swarm-container-resolver.nix {
(import ../container-modules/swarm-container-resolver.nix {
inherit (networkCfg) bridgeIp;
dnsConsumers = [ "authelia-${instance}.service" ];
})

View file

@ -3513,7 +3513,7 @@ in
{ config, ... }:
{
imports = [
(import ./swarm-container-resolver.nix {
(import ../container-modules/swarm-container-resolver.nix {
inherit (networkCfg) bridgeIp;
# The forwarder resolves two swarm names of its own — the
# collector it exports to and the identity provider it mints

View file

@ -1,61 +0,0 @@
# The resolver file a swarm service container writes for itself.
#
# Every swarm service container shares the host netns (`privateNetwork =
# false`) and force-disables `resolvconf`, so that the `/etc/resolv.conf`
# `nixos-containers` copies in at start is not regenerated empty. That copy
# is a `cp --remove-destination` in the host-side preStart, run ONCE per
# container start — so the container's resolver is a snapshot of the host's
# file at its boot instant, and stays that snapshot for its whole life.
#
# A snapshot is not a resolver. Anything that makes the host's file wrong at
# that one instant — a resolvconf regeneration mid-deploy, a host that has
# not yet pointed itself at the bridge — leaves the container with a resolver
# it can never recover from, and the symptom surfaces arbitrarily far from
# the cause: a queue refusing every client because the auth-callout responder
# cannot look up its IdP.
#
# So the container writes the file itself, on every boot, from the one
# address that is correct on both sides of a netns boundary (the bridge IP —
# see `hive-gateway/default.nix`, which forces the host to the same value).
{
bridgeIp,
# Units in this container that resolve a name. The caller names them
# because this module cannot know them, and an unordered resolver write
# is a race that only shows up on a cold boot.
dnsConsumers ? [ ],
}:
{ lib, pkgs, ... }:
{
# ⚠️ `networking.nameservers` CANNOT replace this unit. `resolvconf` is its
# only consumer, and these containers disable it — so setting it renders no
# file and changes no behaviour, while still evaluating and deploying
# perfectly cleanly. It reads like a fix and is a no-op.
#
# ⚠️ Nor can a static `environment.etc."resolv.conf"`: that has to survive
# `etc` activation landing on top of the regular file the host already
# copied there, which is a runtime property no eval can demonstrate. This
# oneshot shape is the one every agent container already uses
# (`nix/agent-modules/network.nix`), so it has runtime evidence behind it.
systemd.services.swarm-bridge-dns = {
description = "point resolv.conf at the hive bridge resolver";
wantedBy = [ "multi-user.target" ];
after = [ "local-fs.target" ];
before = [ "network-online.target" ] ++ dnsConsumers;
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
# Pin the journal identity; without it systemd derives one from the
# generated script's store path (an opaque `<hash>-…-start`).
SyslogIdentifier = "swarm-bridge-dns";
};
path = [ pkgs.coreutils ];
script = ''
set -eu
# `rm` first: this is a regular file the host copied in, not something
# to write through, and a leftover symlink would redirect the write.
rm -f /etc/resolv.conf
printf 'nameserver %s\n' ${lib.escapeShellArg bridgeIp} > /etc/resolv.conf
echo "swarm-bridge-dns: resolv.conf -> nameserver ${bridgeIp}"
'';
};
}

View file

@ -1,52 +0,0 @@
# What every hyperhive service nixos-container sets for itself, imported
# inside the container's own `config`.
#
# The host module that declares `containers.<name>` sets the options below.
# They restate host-side facts the container cannot read on its own: its
# evaluation is nested inside `containers.<name>`, and reading the host side
# back from in here recurses.
{ config, lib, ... }:
let
cfg = config.services.hyperhive.swarmContainer;
in
{
options.services.hyperhive.swarmContainer = {
privateNetwork = lib.mkOption {
type = lib.types.bool;
description = ''
Must equal the host-side `containers.<name>.privateNetwork`. When
`false` the container shares the host netns, so its own
firewall.service would rewrite the HOST ruleset at every boot; the
container's firewall is turned off and the host firewall owns all
filtering.
'';
};
writesOwnResolvConf = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Something in this container writes `/etc/resolv.conf` itself (the
`swarm-container-resolver.nix` unit, or a static file), so
resolvconf is forced off. Left on, host-tracking would regenerate the
file empty, since the host's copy doesn't cross the boundary after
start.
'';
};
};
config = lib.mkMerge [
{
# A container that sets its own keeps it. Changing this value changes
# it for every container that doesn't, and that is a state migration
# for each of them.
system.stateVersion = lib.mkDefault "26.05";
}
(lib.mkIf (!cfg.privateNetwork) {
networking.firewall.enable = false;
})
(lib.mkIf cfg.writesOwnResolvConf {
networking.resolvconf.enable = lib.mkForce false;
})
];
}

View file

@ -727,7 +727,7 @@ in
{ ... }:
{
imports = [
(import ./swarm-container-resolver.nix {
(import ../container-modules/swarm-container-resolver.nix {
inherit (networkCfg) bridgeIp;
dnsConsumers = [ "grafana.service" ];
})

View file

@ -747,7 +747,7 @@ in
{ ... }:
{
imports = [
(import ./swarm-container-resolver.nix {
(import ../container-modules/swarm-container-resolver.nix {
inherit (networkCfg) bridgeIp;
# The responder introspects authelia BY NAME on every auth
# request, and a responder that cannot resolve it denies

View file

@ -1194,7 +1194,7 @@ in
# taken once at boot, so without this the upstream export
# depends on the host's file having been right at that instant.
imports = [
(import ./swarm-container-resolver.nix {
(import ../container-modules/swarm-container-resolver.nix {
inherit (config.services.hyperhive.network) bridgeIp;
dnsConsumers = [ "opentelemetry-collector.service" ];
})

View file

@ -279,7 +279,7 @@ in
{ ... }:
{
imports = [
(import ./swarm-container-resolver.nix {
(import ../container-modules/swarm-container-resolver.nix {
inherit (networkCfg) bridgeIp;
dnsConsumers = [ "victorialogs.service" ];
})

View file

@ -200,8 +200,8 @@ in
{ ... }:
{
imports = [
./swarm-container.nix
(import ./swarm-container-resolver.nix {
../container-modules/swarm-container.nix
(import ../container-modules/swarm-container-resolver.nix {
inherit (networkCfg) bridgeIp;
dnsConsumers = [ "victoriametrics.service" ];
})