diff --git a/README.md b/README.md index d25a0d3..9cac9e3 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,94 @@ hdh20267 = { The external flake must provide a `homeManagerModules.default` output. Note that using this feature may require running `update-system --impure` if the flake is not locked in the system's `flake.lock`. +### Using External Flakes for System Configuration + +You can also override the system-level configuration for a specific host using an external flake. This is useful for adding system services (like Docker), changing boot parameters, or installing system-wide packages that are not in the standard image. + +1. Open `inventory.nix`. +2. In the `devices` override for the host, set the `flakeUrl`: + +```nix +nix-laptop = { + count = 2; + devices = { + "2" = { + flakeUrl = "github:myuser/my-system-config"; + # You can still combine this with other overrides + swapSize = "64G"; + }; + }; +}; +``` + +The external flake must provide a `nixosModules.default` output. + +## External Flake Templates + +If you are creating a new flake to use with `flakeUrl`, use these templates as a starting point. + +### Home Manager Flake (for `users.nix`) + +Use this for user-specific dotfiles, shell configuration, and user packages. + +```nix +{ + description = "My Home Manager Configuration"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + # home-manager is not strictly required as an input if you only export a module, + # but it's good practice for standalone testing. + }; + + outputs = { self, nixpkgs, ... }: { + # This output is what nixos-systems looks for + homeManagerModules.default = { pkgs, ... }: { + home.stateVersion = "25.11"; + + home.packages = with pkgs; [ + ripgrep + bat + fzf + ]; + + programs.git = { + enable = true; + userName = "My Name"; + userEmail = "me@example.com"; + }; + }; + }; +} +``` + +### System Flake (for `inventory.nix`) + +Use this for host-specific system services, hardware tweaks, or root-level packages. + +```nix +{ + description = "My System Configuration Override"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11"; + }; + + outputs = { self, nixpkgs, ... }: { + # This output is what nixos-systems looks for + nixosModules.default = { pkgs, ... }: { + environment.systemPackages = [ pkgs.docker ]; + + virtualisation.docker.enable = true; + + # Example: Add a custom binary cache + nix.settings.substituters = [ "https://nix-community.cachix.org" ]; + nix.settings.trusted-public-keys = [ "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" ]; + }; + }; +} +``` + ### Adding a New Host 1. Open `inventory.nix`. diff --git a/hosts/default.nix b/hosts/default.nix index ba82ec7..08445de 100644 --- a/hosts/default.nix +++ b/hosts/default.nix @@ -47,22 +47,36 @@ let mkHostGroup = { prefix, count, system ? "x86_64-linux", extraModules ? [], deviceOverrides ? {} }: lib.listToAttrs (map (i: { name = "${prefix}${toString i}"; - value = mkHost { - hostName = "${prefix}${toString i}"; - inherit system; - extraModules = extraModules ++ - (lib.optional (builtins.hasAttr (toString i) deviceOverrides) - ({ ... }: - let - devConf = deviceOverrides.${toString i}; - fsConf = builtins.removeAttrs devConf [ "extraUsers" ]; - in { - host.filesystem = fsConf; - modules.users.enabledUsers = devConf.extraUsers or []; - } - ) - ); - }; + 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 + 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 diff --git a/hosts/user-config.nix b/hosts/user-config.nix index 6514378..3f30584 100644 --- a/hosts/user-config.nix +++ b/hosts/user-config.nix @@ -3,7 +3,7 @@ let userSubmodule = lib.types.submodule { options = { isNormalUser = lib.mkOption { type = lib.types.bool; default = true; }; - description = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; }; + description = lib.mkOption { type = lib.types.str; default = ""; }; extraGroups = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; }; hashedPassword = lib.mkOption { type = lib.types.str; default = "!"; }; extraPackages = lib.mkOption { type = lib.types.listOf lib.types.package; default = []; }; @@ -49,9 +49,7 @@ in finalPackages = lib.subtractLists user.excludePackages (defaultPackages ++ user.extraPackages); in { - inherit (user) isNormalUser extraGroups hashedPassword; - description = if user.description != null then user.description else lib.mkDefault ""; - openssh.authorizedKeys.keys = user.opensshKeys; + inherit (user) isNormalUser description extraGroups hashedPassword; packages = finalPackages; shell = config.modules.users.shell; } @@ -68,7 +66,7 @@ in enabledAccounts = lib.filterAttrs (name: _: lib.elem name config.modules.users.enabledUsers) config.modules.users.accounts; in lib.mapAttrs (name: user: { ... }: { - imports = user.extraImports ++ + imports = user.extraImports ++ [ ../sw/theme.nix ../sw/nvim.nix ] ++ (lib.optional (user.flakeUrl != "") (builtins.getFlake user.flakeUrl).homeManagerModules.default); home.username = name; home.homeDirectory = if name == "root" then "/root" else "/home/${name}"; diff --git a/inventory.nix b/inventory.nix index 9e4398c..65394a1 100644 --- a/inventory.nix +++ b/inventory.nix @@ -10,18 +10,17 @@ # Enable specific users for this device index "1" = { extraUsers = [ "hdh20267" ]; }; "2" = { extraUsers = [ "hdh20267" ]; }; + + # Example of using an external flake for system configuration: + # "2" = { flakeUrl = "github:user/system-flake"; }; }; }; # Desktop Configuration # Base specs: NVMe drive, 16G Swap - nix-desktop = { - count = 1; - }; + nix-desktop.count = 1; # Surface Tablet Configuration (Kiosk Mode) # Base specs: eMMC drive, 8G Swap - nix-surface = { - count = 3; - }; + nix-surface.count = 3; } diff --git a/users.nix b/users.nix index cca44a9..649129a 100644 --- a/users.nix +++ b/users.nix @@ -6,21 +6,17 @@ root = { isNormalUser = false; hashedPassword = "!"; - extraImports = [ ./sw/theme.nix ]; - opensshKeys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBC7xzHxY2BfFUybMvG4wHSF9oEAGzRiLTFEndLvWV/X hdh20267@engr733847d.engr.uga.edu" ]; }; engr-ugaif = { description = "UGA Innovation Factory"; extraGroups = [ "networkmanager" "wheel" "video" "input" ]; hashedPassword = "$6$El6e2NhPrhVFjbFU$imlGZqUiizWw5fMP/ib0CeboOcFhYjIVb8oR1V1dP2NjDeri3jMoUm4ZABOB2uAF8UEDjAGHhFuZxhtbHg647/"; - extraImports = [ ./sw/theme.nix ./sw/nvim.nix ]; opensshKeys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBC7xzHxY2BfFUybMvG4wHSF9oEAGzRiLTFEndLvWV/X hdh20267@engr733847d.engr.uga.edu" ]; }; hdh20267 = { description = "Hunter Halloran"; extraGroups = [ "networkmanager" "wheel" ]; homePackages = [ pkgs.ghostty ]; - extraImports = [ ./sw/theme.nix ./sw/nvim.nix ]; # Example of using an external flake for configuration: # flakeUrl = "github:hdh20267/dotfiles"; };