Compare commits

5 Commits

Author SHA1 Message Date
UGA Innovation Factory
ffa434e720 chore: Run nix fmt
All checks were successful
CI / Format Check (push) Successful in 2s
CI / Flake Check (push) Successful in 1m26s
CI / Evaluate Key Configurations (nix-builder) (push) Successful in 6s
CI / Evaluate Key Configurations (nix-desktop1) (push) Successful in 5s
CI / Evaluate Key Configurations (nix-laptop1) (push) Successful in 7s
CI / Evaluate Artifacts (installer-iso-nix-laptop1) (push) Successful in 13s
CI / Evaluate Artifacts (lxc-nix-builder) (push) Successful in 6s
2026-01-13 18:33:43 -05:00
UGA Innovation Factory
5f5698f608 chore: Update hdh20267 user to use new shell selection 2026-01-13 18:33:43 -05:00
UGA Innovation Factory
f606ea731c feat: Refactor to use flake-parts and import inventory and users thru the flake parts 2026-01-13 18:33:43 -05:00
UGA Innovation Factory
b1d4fe8d68 fix: Refactor flake structure to properly use flake-parts
- Remove incorrect parts/fleet-data.nix import from flake.nix
- Create flake-parts wrappers for fleet-option.nix and users.nix
- Import inventory.nix through fleet-option wrapper
- Fix module argument passing (remove pkgs from mkFleet call)
- Move NixOS-specific modules out of flake-parts imports

This addresses the 'path does not exist' error but introduces infinite recursion that needs to be resolved.
2026-01-13 18:33:43 -05:00
UGA Innovation Factory
cbddecfeb4 fix: Remove incorrect parts/fleet-data.nix import from flake.nix
fleet-data.nix is a NixOS module imported by fleet/common.nix, not a flake-parts module. It should not be imported at the flake level.
2026-01-13 18:33:37 -05:00
12 changed files with 159 additions and 223 deletions

BIN
core

Binary file not shown.

View File

@@ -76,11 +76,12 @@
imports = [ imports = [
./parts/formatter.nix ./parts/formatter.nix
./parts/lib.nix ./parts/lib.nix
./parts/fleet-data.nix
./parts/nixos-configurations.nix ./parts/nixos-configurations.nix
./parts/nixos-modules.nix ./parts/nixos-modules.nix
./parts/packages.nix ./parts/packages.nix
./parts/templates.nix ./parts/templates.nix
./inventory.nix
./users.nix
]; ];
}; };
} }

View File

@@ -12,12 +12,11 @@
}: }:
{ {
imports = [ imports = [
(import ./fleet-data.nix { inherit inputs lib; })
./fs.nix ./fs.nix
./boot.nix ./boot.nix
./user-config.nix ./user-config.nix
./fleet-option.nix
../sw ../sw
../users.nix
]; ];
options.athenix = { options.athenix = {

View File

@@ -17,7 +17,7 @@ let
# Evaluate inventory to get fleet data # Evaluate inventory to get fleet data
# Import fleet-option.nix (defines athenix.fleet) and inventory.nix (sets values) # Import fleet-option.nix (defines athenix.fleet) and inventory.nix (sets values)
# We use a minimal module here to avoid circular dependencies from common.nix's imports # We use a minimal module here to avoid circular dependencies from common.nix's imports
hostTypes = config.athenix.hwTypes; hostTypes = config.athenix.hwTypes;
# Helper to create a single NixOS system configuration # Helper to create a single NixOS system configuration

View File

@@ -1,65 +0,0 @@
# ============================================================================
# Fleet Data for NixOS Configurations
# ============================================================================
# This module exposes only the fleet inventory data (not hwTypes module functions)
# to individual NixOS configurations. Used by fleet/common.nix.
{ inputs, lib, ... }:
let
fleetDefinition = lib.mkOption {
description = "Hardware types definitions for the fleet.";
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options = {
type = lib.mkOption {
type = lib.types.oneOf [
lib.types.str
lib.types.listOf lib.types.str
];
default = name;
description = "Type(s) of system configuration for this device.";
};
system = lib.mkOption {
type = lib.types.str;
default = "x86_64-linux";
description = "NixOS system architecture for this hardware type.";
};
devices = lib.mkOption {
type = lib.types.oneOf [
lib.types.int
(lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
freeformType = lib.types.attrs;
}
)
))
];
};
count = lib.mkOption {
type = lib.types.int;
default = 0;
description = "Number of devices of this type to create.";
};
defaultCount = lib.mkOption {
type = lib.types.int;
default = 0;
description = "Default number of devices to create with default configurations and numbered hostnames.";
};
overrides = lib.mkOption {
type = lib.types.attrs;
default = { };
description = "Overrides to apply to all devices of this type.";
};
};
}
)
);
};
in
{
imports = [ ../inventory.nix ];
options.athenix.fleet = fleetDefinition;
}

View File

@@ -59,6 +59,109 @@ let
) )
); );
}; };
# Submodule defining the structure of a user account
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;
};
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 = [ ];
};
excludePackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
homePackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
extraImports = lib.mkOption {
type = lib.types.listOf lib.types.path;
default = [ ];
};
external = lib.mkOption {
type = lib.types.nullOr (
lib.types.oneOf [
lib.types.path
lib.types.package
lib.types.attrs
]
);
default = null;
description = ''
External user configuration module. Can be:
- A path to a local module directory
- A fetchGit/fetchTarball result pointing to a repository
The external module can contain:
- user.nix (optional): Sets athenix.users.<name> options AND home-manager config
- nixos.nix (optional): System-level NixOS configuration
Example: builtins.fetchGit { url = "https://github.com/user/dotfiles"; rev = "..."; }
'';
};
opensshKeys = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "List of SSH public keys for the user.";
};
shell = lib.mkOption {
type = lib.types.nullOr (
lib.types.enum [
"bash"
"zsh"
"fish"
"tcsh"
]
);
default = "bash";
description = "The shell for this user.";
};
editor = lib.mkOption {
type = lib.types.nullOr (
lib.types.enum [
"vim"
"neovim"
"emacs"
"nano"
"code"
]
);
default = "neovim";
description = "The default editor for this user.";
};
useZshTheme = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to apply the system Zsh theme.";
};
useNvimPlugins = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to apply the system Neovim configuration.";
};
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether this user account is enabled on this system.";
};
};
};
in in
{ {
options.athenix = { options.athenix = {
@@ -67,6 +170,11 @@ in
description = "Hardware types definitions for the fleet."; description = "Hardware types definitions for the fleet.";
type = lib.types.attrs; type = lib.types.attrs;
}; };
users = lib.mkOption {
type = lib.types.attrsOf userSubmodule;
default = { };
description = "User accounts configuration. Set enable=true for users that should exist on this system.";
};
}; };
config.athenix.hwTypes = lib.mkDefault (import ../hw { inherit inputs; }); config.athenix.hwTypes = lib.mkDefault (import ../hw { inherit inputs; });

View File

@@ -14,9 +14,6 @@
# and Home Manager configuration. # and Home Manager configuration.
let let
# Load users.nix to get account definitions
accounts = config.athenix.users or { };
# Helper: Resolve external module path from fetchGit/fetchTarball/path # Helper: Resolve external module path from fetchGit/fetchTarball/path
resolveExternalPath = resolveExternalPath =
external: external:
@@ -33,149 +30,9 @@ let
path != null path != null
&& (builtins.isPath path || (builtins.isString path && lib.hasPrefix "/" path)) && (builtins.isPath path || (builtins.isString path && lib.hasPrefix "/" path))
&& builtins.pathExists path; && builtins.pathExists path;
# Extract athenix.users options from external user.nix modules
# First, build a cache of options per user from their external user.nix (if any).
externalUserModuleOptions = lib.genAttrs (lib.attrNames accounts) (
name:
let
user = accounts.${name};
externalPath = resolveExternalPath (user.external or null);
userNixPath = if externalPath != null then externalPath + "/user.nix" else null;
in
if isValidPath userNixPath then
let
# Import and evaluate the module with minimal args
outerModule = import userNixPath { inherit inputs; };
evaluatedModule = outerModule {
config = { };
inherit lib pkgs;
osConfig = null;
};
# Extract just the athenix.users.<name> options
athenixUsers = evaluatedModule.athenix.users or { };
in
athenixUsers.${name} or { }
else
{ }
);
# externalUserOptions only contains users that actually have options defined
externalUserOptions = lib.filterAttrs (
_: moduleOptions: moduleOptions != { }
) externalUserModuleOptions;
# Submodule defining the structure of a user account
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;
};
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 = [ ];
};
excludePackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
homePackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
extraImports = lib.mkOption {
type = lib.types.listOf lib.types.path;
default = [ ];
};
external = lib.mkOption {
type = lib.types.nullOr (
lib.types.oneOf [
lib.types.path
lib.types.package
lib.types.attrs
]
);
default = null;
description = ''
External user configuration module. Can be:
- A path to a local module directory
- A fetchGit/fetchTarball result pointing to a repository
The external module can contain:
- user.nix (optional): Sets athenix.users.<name> options AND home-manager config
- nixos.nix (optional): System-level NixOS configuration
Example: builtins.fetchGit { url = "https://github.com/user/dotfiles"; rev = "..."; }
'';
};
opensshKeys = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "List of SSH public keys for the user.";
};
shell = lib.mkOption {
type = lib.types.nullOr lib.types.package;
default = null;
description = "The shell for this user.";
};
editor = lib.mkOption {
type = lib.types.nullOr lib.types.package;
default = null;
description = "The default editor for this user.";
};
useZshTheme = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to apply the system Zsh theme.";
};
useNvimPlugins = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to apply the system Neovim configuration.";
};
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether this user account is enabled on this system.";
};
};
};
in in
{ {
options.athenix.users = lib.mkOption {
type = lib.types.attrsOf userSubmodule;
default = { };
description = "User accounts configuration. Set enable=true for users that should exist on this system.";
};
config = { config = {
# Merge user definitions from users.nix with options from external user.nix modules
# External options take precedence over users.nix (which uses lib.mkDefault)
athenix.users = lib.mapAttrs (
name: user:
user
// {
description = lib.mkDefault (user.description or null);
shell = lib.mkDefault (user.shell or null);
extraGroups = lib.mkDefault (user.extraGroups or [ ]);
}
// (externalUserOptions.${name} or { })
) accounts;
# Generate NixOS users # Generate NixOS users
users.users = users.users =
let let
@@ -187,16 +44,31 @@ in
isPlasma6 = config.services.desktopManager.plasma6.enable; isPlasma6 = config.services.desktopManager.plasma6.enable;
defaultPackages = lib.optionals (isPlasma6 && name != "root") [ pkgs.kdePackages.kate ]; defaultPackages = lib.optionals (isPlasma6 && name != "root") [ pkgs.kdePackages.kate ];
finalPackages = lib.subtractLists user.excludePackages (defaultPackages ++ user.extraPackages); finalPackages = lib.subtractLists user.excludePackages (defaultPackages ++ user.extraPackages);
shells = {
bash = pkgs.bash;
zsh = pkgs.zsh;
fish = pkgs.fish;
tcsh = pkgs.tcsh;
};
in in
{ rec {
inherit (user) isNormalUser extraGroups hashedPassword; inherit (user) isNormalUser extraGroups hashedPassword;
description = if user.description != null then user.description else lib.mkDefault ""; description = if user.description != null then user.description else lib.mkDefault "";
openssh.authorizedKeys.keys = user.opensshKeys; openssh.authorizedKeys.keys = user.opensshKeys;
packages = finalPackages; shell = if user.shell != null then shells.${user.shell} else pkgs.bash;
shell = if user.shell != null then user.shell else pkgs.bash; packages = finalPackages ++ [ shell ];
group = if user.isNormalUser then name else lib.mkDefault "root";
} }
) enabledAccounts; ) enabledAccounts;
# Generate user groups for normal users
users.groups =
let
enabledAccounts = lib.filterAttrs (_: user: user.enable) config.athenix.users;
normalUsers = lib.filterAttrs (_: user: user.isNormalUser) enabledAccounts;
in
lib.mapAttrs (_: _: { }) normalUsers;
# Home Manager configs per user # Home Manager configs per user
home-manager = { home-manager = {
useGlobalPkgs = true; useGlobalPkgs = true;
@@ -263,6 +135,10 @@ in
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}";
home.stateVersion = "25.11"; home.stateVersion = "25.11";
programs.${user.editor} = {
enable = true;
defaultEditor = true;
};
} }
(lib.mkIf (!hasExternal) { (lib.mkIf (!hasExternal) {
# For local users only, add their packages # For local users only, add their packages

View File

@@ -70,7 +70,8 @@
# rev = "e1ccd7cc3e709afe4f50b0627e1c4bde49165014"; # rev = "e1ccd7cc3e709afe4f50b0627e1c4bde49165014";
# }; # };
# }; # };
{...}: { { ... }:
{
athenix.fleet = { athenix.fleet = {
# ========== Lab Laptops ========== # ========== Lab Laptops ==========
# Creates: nix-laptop1, nix-laptop2 # Creates: nix-laptop1, nix-laptop2
@@ -131,6 +132,7 @@
rev = "dab32f5884895cead0fae28cb7d88d17951d0c12"; rev = "dab32f5884895cead0fae28cb7d88d17951d0c12";
submodules = true; submodules = true;
}; };
"usda-dash".athenix.users.engr-ugaif.enable = true;
}; };
overrides = { overrides = {
athenix.host.useHostPrefix = false; athenix.host.useHostPrefix = false;

View File

@@ -3,7 +3,7 @@
{ {
inputs, inputs,
lib, lib,
config config,
}: }:
import ../fleet/default.nix { import ../fleet/default.nix {
inherit inputs lib config; inherit inputs lib config;

View File

@@ -1,12 +1,20 @@
# NixOS configurations generated from fleet # NixOS configurations generated from fleet
{ inputs, self, lib, pkgs, config, ... }: {
inputs,
self,
lib,
pkgs,
config,
...
}:
{ {
imports = [ imports = [
(import ../fleet/fleet-option.nix { inherit inputs lib pkgs config; }) ../fleet/fleet-option.nix
]; ];
flake.nixosConfigurations = flake.nixosConfigurations =
let let
fleet = self.lib.mkFleet { inherit inputs lib pkgs config; }; fleet = self.lib.mkFleet { inherit inputs lib config; };
in in
fleet.nixosConfigurations; fleet.nixosConfigurations;
} }

7
parts/users.nix Normal file
View File

@@ -0,0 +1,7 @@
# Flake-parts wrapper for users.nix
{ inputs, ... }:
let
# Minimal pkgs just for shell paths - will be overridden in actual NixOS configs
pkgs = inputs.nixpkgs.legacyPackages.x86_64-linux;
in
import ../users.nix { inherit pkgs; }

View File

@@ -1,4 +1,4 @@
{ pkgs, ... }: { ... }:
{ {
# ============================================================================ # ============================================================================
# User Definitions # User Definitions
@@ -49,7 +49,7 @@
hdh20267 = { hdh20267 = {
external = builtins.fetchGit { external = builtins.fetchGit {
url = "https://git.factory.uga.edu/hdh20267/hdh20267-nix"; url = "https://git.factory.uga.edu/hdh20267/hdh20267-nix";
rev = "c538e0c0510045b58264627bb897fc499dc7c490"; rev = "dbdf65c7bd59e646719f724a3acd2330e0c922ec";
}; };
}; };
sv22900 = { sv22900 = {
@@ -58,7 +58,7 @@
"networkmanager" "networkmanager"
"wheel" "wheel"
]; ];
shell = pkgs.zsh; shell = "zsh";
# enable = false by default, set to true per-system # enable = false by default, set to true per-system
}; };
}; };