feat: Enable system flake additions from external files
This commit is contained in:
88
README.md
88
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`.
|
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
|
### Adding a New Host
|
||||||
|
|
||||||
1. Open `inventory.nix`.
|
1. Open `inventory.nix`.
|
||||||
|
|||||||
@@ -47,21 +47,35 @@ let
|
|||||||
mkHostGroup = { prefix, count, system ? "x86_64-linux", extraModules ? [], deviceOverrides ? {} }:
|
mkHostGroup = { prefix, count, system ? "x86_64-linux", extraModules ? [], deviceOverrides ? {} }:
|
||||||
lib.listToAttrs (map (i: {
|
lib.listToAttrs (map (i: {
|
||||||
name = "${prefix}${toString i}";
|
name = "${prefix}${toString i}";
|
||||||
value = mkHost {
|
value =
|
||||||
hostName = "${prefix}${toString i}";
|
|
||||||
inherit system;
|
|
||||||
extraModules = extraModules ++
|
|
||||||
(lib.optional (builtins.hasAttr (toString i) deviceOverrides)
|
|
||||||
({ ... }:
|
|
||||||
let
|
let
|
||||||
devConf = deviceOverrides.${toString i};
|
devConf = deviceOverrides.${toString i} or {};
|
||||||
fsConf = builtins.removeAttrs devConf [ "extraUsers" ];
|
hasOverride = builtins.hasAttr (toString i) deviceOverrides;
|
||||||
in {
|
|
||||||
|
# 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;
|
host.filesystem = fsConf;
|
||||||
modules.users.enabledUsers = devConf.extraUsers or [];
|
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));
|
}) (lib.range 1 count));
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ let
|
|||||||
userSubmodule = lib.types.submodule {
|
userSubmodule = lib.types.submodule {
|
||||||
options = {
|
options = {
|
||||||
isNormalUser = lib.mkOption { type = lib.types.bool; default = true; };
|
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 = []; };
|
extraGroups = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; };
|
||||||
hashedPassword = lib.mkOption { type = lib.types.str; default = "!"; };
|
hashedPassword = lib.mkOption { type = lib.types.str; default = "!"; };
|
||||||
extraPackages = lib.mkOption { type = lib.types.listOf lib.types.package; 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);
|
finalPackages = lib.subtractLists user.excludePackages (defaultPackages ++ user.extraPackages);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
inherit (user) isNormalUser extraGroups hashedPassword;
|
inherit (user) isNormalUser description extraGroups hashedPassword;
|
||||||
description = if user.description != null then user.description else lib.mkDefault "";
|
|
||||||
openssh.authorizedKeys.keys = user.opensshKeys;
|
|
||||||
packages = finalPackages;
|
packages = finalPackages;
|
||||||
shell = config.modules.users.shell;
|
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;
|
enabledAccounts = lib.filterAttrs (name: _: lib.elem name config.modules.users.enabledUsers) config.modules.users.accounts;
|
||||||
in
|
in
|
||||||
lib.mapAttrs (name: user: { ... }: {
|
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);
|
(lib.optional (user.flakeUrl != "") (builtins.getFlake user.flakeUrl).homeManagerModules.default);
|
||||||
home.username = name;
|
home.username = name;
|
||||||
home.homeDirectory = if name == "root" then "/root" else "/home/${name}";
|
home.homeDirectory = if name == "root" then "/root" else "/home/${name}";
|
||||||
|
|||||||
@@ -10,18 +10,17 @@
|
|||||||
# Enable specific users for this device index
|
# Enable specific users for this device index
|
||||||
"1" = { extraUsers = [ "hdh20267" ]; };
|
"1" = { extraUsers = [ "hdh20267" ]; };
|
||||||
"2" = { extraUsers = [ "hdh20267" ]; };
|
"2" = { extraUsers = [ "hdh20267" ]; };
|
||||||
|
|
||||||
|
# Example of using an external flake for system configuration:
|
||||||
|
# "2" = { flakeUrl = "github:user/system-flake"; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Desktop Configuration
|
# Desktop Configuration
|
||||||
# Base specs: NVMe drive, 16G Swap
|
# Base specs: NVMe drive, 16G Swap
|
||||||
nix-desktop = {
|
nix-desktop.count = 1;
|
||||||
count = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Surface Tablet Configuration (Kiosk Mode)
|
# Surface Tablet Configuration (Kiosk Mode)
|
||||||
# Base specs: eMMC drive, 8G Swap
|
# Base specs: eMMC drive, 8G Swap
|
||||||
nix-surface = {
|
nix-surface.count = 3;
|
||||||
count = 3;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,21 +6,17 @@
|
|||||||
root = {
|
root = {
|
||||||
isNormalUser = false;
|
isNormalUser = false;
|
||||||
hashedPassword = "!";
|
hashedPassword = "!";
|
||||||
extraImports = [ ./sw/theme.nix ];
|
|
||||||
opensshKeys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBC7xzHxY2BfFUybMvG4wHSF9oEAGzRiLTFEndLvWV/X hdh20267@engr733847d.engr.uga.edu" ];
|
|
||||||
};
|
};
|
||||||
engr-ugaif = {
|
engr-ugaif = {
|
||||||
description = "UGA Innovation Factory";
|
description = "UGA Innovation Factory";
|
||||||
extraGroups = [ "networkmanager" "wheel" "video" "input" ];
|
extraGroups = [ "networkmanager" "wheel" "video" "input" ];
|
||||||
hashedPassword = "$6$El6e2NhPrhVFjbFU$imlGZqUiizWw5fMP/ib0CeboOcFhYjIVb8oR1V1dP2NjDeri3jMoUm4ZABOB2uAF8UEDjAGHhFuZxhtbHg647/";
|
hashedPassword = "$6$El6e2NhPrhVFjbFU$imlGZqUiizWw5fMP/ib0CeboOcFhYjIVb8oR1V1dP2NjDeri3jMoUm4ZABOB2uAF8UEDjAGHhFuZxhtbHg647/";
|
||||||
extraImports = [ ./sw/theme.nix ./sw/nvim.nix ];
|
|
||||||
opensshKeys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBC7xzHxY2BfFUybMvG4wHSF9oEAGzRiLTFEndLvWV/X hdh20267@engr733847d.engr.uga.edu" ];
|
opensshKeys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBC7xzHxY2BfFUybMvG4wHSF9oEAGzRiLTFEndLvWV/X hdh20267@engr733847d.engr.uga.edu" ];
|
||||||
};
|
};
|
||||||
hdh20267 = {
|
hdh20267 = {
|
||||||
description = "Hunter Halloran";
|
description = "Hunter Halloran";
|
||||||
extraGroups = [ "networkmanager" "wheel" ];
|
extraGroups = [ "networkmanager" "wheel" ];
|
||||||
homePackages = [ pkgs.ghostty ];
|
homePackages = [ pkgs.ghostty ];
|
||||||
extraImports = [ ./sw/theme.nix ./sw/nvim.nix ];
|
|
||||||
# Example of using an external flake for configuration:
|
# Example of using an external flake for configuration:
|
||||||
# flakeUrl = "github:hdh20267/dotfiles";
|
# flakeUrl = "github:hdh20267/dotfiles";
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user