From bd2c1583da3f3c78668a029839efdca5a421525a Mon Sep 17 00:00:00 2001 From: alexion Date: Thu, 20 Aug 2026 10:46:24 -0400 Subject: [PATCH] feat(network): add fleet endpoint registry --- flake.nix | 51 +++++++++++++++++++++++++++++++++++++++ lib/default.nix | 3 +++ lib/guests.nix | 16 ++++++++++++ lib/network-endpoints.nix | 42 ++++++++++++++++++++++++++++++++ modules/network.nix | 22 +++++++++++++++++ 5 files changed, 134 insertions(+) create mode 100644 lib/network-endpoints.nix diff --git a/flake.nix b/flake.nix index bdadfbe..4966a82 100644 --- a/flake.nix +++ b/flake.nix @@ -173,6 +173,57 @@ touch $out ''; + network-endpoint-fleet-registry = + let + hostEndpointConfig = + lib.nixosSystem { + system = "x86_64-linux"; + specialArgs.my = self.lib; + modules = [ + ./modules/network.nix + { + modules.network.endpoint.address = "10.23.50.146"; + } + ]; + }; + guestEndpointConfig = + lib.nixosSystem { + system = "x86_64-linux"; + specialArgs.my = self.lib; + modules = [ + inputs.sops-nix.nixosModules.sops + ./modules/network.nix + ./modules/reverse-proxy.nix + (self.lib.guest { name = "copyparty"; }) + { + modules.network.vlans = [ 20 ]; + guests.copyparty = { + enable = true; + vlan = 20; + endpoint.address = "10.23.20.126"; + }; + } + ]; + }; + fleetEndpoints = self.lib.networkEndpoints.collectFleetEndpoints { + neogaia = hostEndpointConfig; + pikachu = guestEndpointConfig; + }; + in + pkgs.runCommand "network-endpoint-fleet-registry-check" { } '' + ${ + lib.optionalString ( + !( + fleetEndpoints.neogaia.address == "10.23.50.146" + && fleetEndpoints."pikachu-copyparty".address == "10.23.20.126" + && !(fleetEndpoints ? pikachu) + && guestEndpointConfig.config.containers.copyparty.config.systemd.network.networks."20-eth0".networkConfig.DHCP == "yes" + ) + ) "exit 1" + } + touch $out + ''; + reverse-proxy-fleet-routes = let routeHost = diff --git a/lib/default.nix b/lib/default.nix index 88d4e3b..210a84e 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -14,6 +14,7 @@ let ; serviceIdentityRegistry = import ./service-identities.nix { inherit lib; }; + networkEndpoints = import ./network-endpoints.nix { inherit lib; }; reverseProxyRoutes = import ./reverse-proxy-routes.nix { inherit lib; }; collectNixFiles = @@ -36,6 +37,7 @@ let specialArgs = { inherit inputs self; my = self.lib; + networkFleetEndpoints = self.lib.networkEndpoints.collectFleetEndpoints self.nixosConfigurations; reverseProxyFleetRoutes = self.lib.reverseProxyRoutes.collectFleetRoutes self.nixosConfigurations; }; @@ -85,6 +87,7 @@ in mkHost mkHosts bridgeName + networkEndpoints reverseProxyRoutes ; diff --git a/lib/guests.nix b/lib/guests.nix index a4c7a51..f2ed181 100644 --- a/lib/guests.nix +++ b/lib/guests.nix @@ -131,6 +131,18 @@ let guest takes its address by DHCP, keeping IP management at the router. ''; }; + endpoint = { + address = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "10.23.20.126"; + description = '' + Expected IP address assigned outside NixOS for this guest's + network endpoint. Left null, this guest contributes no endpoint to + the fleet endpoint registry. + ''; + }; + }; reverseProxy = reverseProxyRoutes.mkRouteOptions { subject = "guest route"; enableDefault = false; @@ -278,6 +290,10 @@ let config = lib.mkIf cfg.enable { sops.secrets = lib.genAttrs cfg.secrets (_: { }); + modules.network.endpoints.${machineName} = lib.mkIf (cfg.endpoint.address != null) { + inherit (cfg.endpoint) address; + }; + modules.reverse-proxy.routes.${machineName} = lib.mkIf cfg.reverseProxy.enable ( reverseProxyRoutes.routeFields cfg.reverseProxy ); diff --git a/lib/network-endpoints.nix b/lib/network-endpoints.nix new file mode 100644 index 0000000..d823fb4 --- /dev/null +++ b/lib/network-endpoints.nix @@ -0,0 +1,42 @@ +{ lib }: +let + endpointOptions = { + address = lib.mkOption { + type = lib.types.str; + example = "10.23.20.126"; + description = "Expected IP address assigned outside NixOS for this network endpoint."; + }; + }; + + endpointType = lib.types.submodule { + options = endpointOptions; + }; + + endpointFields = endpoint: { + inherit (endpoint) address; + }; + + collectFleetEndpoints = + hosts: + lib.concatMapAttrs ( + hostName: host: + let + cfg = host.config.modules.network; + hostEndpoint = lib.optionalAttrs (cfg.endpoint.address != null) { + ${hostName} = endpointFields cfg.endpoint; + }; + guestEndpoints = lib.mapAttrs' ( + endpointName: endpoint: lib.nameValuePair "${hostName}-${endpointName}" (endpointFields endpoint) + ) cfg.endpoints; + in + hostEndpoint // guestEndpoints + ) hosts; +in +{ + inherit + collectFleetEndpoints + endpointFields + endpointOptions + endpointType + ; +} diff --git a/modules/network.nix b/modules/network.nix index f7e872e..3f29ca0 100644 --- a/modules/network.nix +++ b/modules/network.nix @@ -43,6 +43,28 @@ in ''; }; + endpoint = { + address = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "10.23.50.146"; + description = '' + Expected IP address assigned outside NixOS for this host's network + endpoint. Left null, this host contributes no host endpoint to the + fleet endpoint registry. + ''; + }; + }; + + endpoints = lib.mkOption { + type = lib.types.attrsOf my.networkEndpoints.endpointType; + default = { }; + description = '' + Network endpoint declarations contributed by placed workloads on this + host, keyed by their local stable endpoint name. + ''; + }; + management = { vlan = lib.mkOption { type = lib.types.nullOr (lib.types.ints.between 1 4094); -- 2.47.3