Files
athenix/hosts/default.nix
2025-12-09 19:24:13 -05:00

127 lines
4.2 KiB
Nix

{ inputs, hosts ? import ../inventory.nix, ... }:
# ============================================================================
# Host Generator
# ============================================================================
# This file contains the logic to generate NixOS configurations for all hosts
# defined in inventory.nix. It handles:
# 1. Common module imports (boot, users, software).
# 2. Host-specific overrides (filesystem, enabled users).
# 3. External flake integration for system overrides.
let
nixpkgs = inputs.nixpkgs;
lib = nixpkgs.lib;
home-manager = inputs.home-manager;
disko = inputs.disko;
# Modules shared by all hosts
commonModules = [
./boot.nix
./user-config.nix
../users.nix
../sw
home-manager.nixosModules.home-manager
disko.nixosModules.disko
{
system.stateVersion = "25.11";
nix.settings.experimental-features = [ "nix-command" "flakes" ];
# Automatic Garbage Collection
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 30d";
};
# Optimize storage
nix.optimise.automatic = true;
}
];
# Helper to create a single NixOS system configuration
mkHost = { hostName, system ? "x86_64-linux", extraModules ? [ ] }:
let
# Load users.nix to find external user flakes
# We use legacyPackages to evaluate the simple data structure of users.nix
pkgs = nixpkgs.legacyPackages.${system};
usersData = import ../users.nix { inherit pkgs; };
accounts = usersData.modules.users.accounts or {};
# Extract flakeUrls and convert to modules
userFlakeModules = lib.mapAttrsToList (name: user:
if (user ? flakeUrl && user.flakeUrl != "") then
(builtins.getFlake user.flakeUrl).nixosModules.default
else
{}
) accounts;
in
lib.nixosSystem {
inherit system;
specialArgs = { inherit inputs; };
modules =
commonModules
++ userFlakeModules
++ extraModules
++ [
{ networking.hostName = hostName; }
];
};
# Function to generate a set of hosts based on inventory count and overrides
mkHostGroup = { prefix, count, system ? "x86_64-linux", extraModules ? [], deviceOverrides ? {} }:
lib.listToAttrs (map (i: {
name = "${prefix}${toString i}";
value =
let
devConf = deviceOverrides.${toString i} or {};
hasOverride = builtins.hasAttr (toString i) deviceOverrides;
# Extract flakeUrl if it exists
externalFlake = if hasOverride && (builtins.hasAttr "flakeUrl" devConf)
then builtins.getFlake devConf.flakeUrl
else null;
# Module from external flake
externalModule = if externalFlake != null
then externalFlake.nixosModules.default
else {};
# Config override module (filesystem, users)
overrideModule = { ... }:
let
# Remove special keys that are not filesystem options
fsConf = builtins.removeAttrs devConf [ "extraUsers" "flakeUrl" ];
in lib.mkIf hasOverride {
host.filesystem = fsConf;
modules.users.enabledUsers = devConf.extraUsers or [];
};
in
mkHost {
hostName = "${prefix}${toString i}";
inherit system;
extraModules = extraModules ++ [ overrideModule ] ++ (lib.optional (externalFlake != null) externalModule);
};
}) (lib.range 1 count));
# Generate host groups based on the input hosts configuration
hostGroups = lib.mapAttrsToList (type: config:
let
typeFile = ./types + "/${type}.nix";
modules = if builtins.pathExists typeFile
then import typeFile { inherit inputs; }
else throw "Host type '${type}' not found in hosts/types/";
in
mkHostGroup {
prefix = type;
inherit (config) count;
extraModules = modules;
deviceOverrides = config.devices or {};
}
) hosts;
in
lib.foldl' lib.recursiveUpdate {} hostGroups