refactor: Module to ugaif and readme update

This commit is contained in:
UGA Innovation Factory
2025-12-15 15:32:40 -05:00
committed by Hunter Halloran
parent c46b0aa685
commit 205f03337a
31 changed files with 577 additions and 271 deletions

355
README.md
View File

@@ -1,6 +1,19 @@
# UGA Innovation Factory - NixOS Systems
This repository contains the NixOS configuration for the Innovation Factory's fleet of laptops, desktops, and surface tablets.
This repository contains the NixOS configuration for the Innovation Factory's fleet of laptops, desktops, and surface tablets. It provides a declarative, reproducible system configuration using Nix flakes.
## Table of Contents
- [Repository Structure](#repository-structure)
- [Configuration Namespace](#configuration-namespace)
- [Prerequisites](#prerequisites)
- [Quick Start](#quick-start)
- [Building Artifacts](#building-artifacts-isos-lxc-proxmox)
- [Configuration Guide](#configuration-guide)
- [User Management](#user-management)
- [Host Configuration](#host-configuration)
- [External Flake Templates](#external-flake-templates)
- [Development](#development)
## Repository Structure
@@ -10,6 +23,27 @@ This repository contains the NixOS configuration for the Innovation Factory's fl
- **`hosts/`**: Contains the logic for generating host configurations and hardware-specific types.
- **`sw/`**: Software modules (Desktop, Kiosk, Python, Neovim, etc.).
## Configuration Namespace
All UGA Innovation Factory-specific NixOS options are organized under the `ugaif` namespace to clearly distinguish them from standard NixOS options. The main option groups are:
- **`ugaif.host`**: Hardware and host-level configuration
- `ugaif.host.filesystem`: Disk device and swap size settings
- `ugaif.host.buildMethods`: Supported artifact build methods (ISO, LXC, etc.)
- `ugaif.host.wsl`: WSL-specific configuration
- **`ugaif.sw`**: Software and system type configuration
- `ugaif.sw.enable`: Enable the software configuration module
- `ugaif.sw.type`: System type (`desktop`, `tablet-kiosk`, `headless`, `stateless-kiosk`)
- `ugaif.sw.kioskUrl`: URL for kiosk mode browsers
- `ugaif.sw.python`: Python development tools settings
- `ugaif.sw.remoteBuild`: Remote build configuration
- **`ugaif.users`**: User account management
- `ugaif.users.accounts`: User account definitions
- `ugaif.users.enabledUsers`: List of users enabled on the system
- `ugaif.users.shell`: Default shell for users
## Prerequisites
To work with this repository on a non-NixOS system (like macOS or another Linux distro), you need to install Nix. We recommend the Determinate Systems installer for a reliable and feature-complete setup (including Flakes support out of the box).
@@ -20,42 +54,72 @@ curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix
## Quick Start
### Updating the System
### For End Users: Updating Your System
The system includes a utility script `update-system` that handles rebuilding and switching configurations. It automatically detects if it is running on a Surface tablet and offloads the build to a more powerful host if necessary.
To apply changes to the current system:
The easiest way to update your system is using the included `update-system` utility:
```bash
update-system
```
This command pulls the latest configuration from GitHub and rebuilds the system.
This command:
- Pulls the latest configuration from GitHub
- Rebuilds the system with any changes
- Automatically uses remote builders if you're on a Surface tablet
If your configuration uses external flakes (e.g., via `flakeUrl`), you may need to allow impure evaluation:
If you use external flakes (personal dotfiles), add the `--impure` flag:
```bash
update-system --impure
```
### Manual Rebuilds
### For Administrators: Managing the Fleet
If you need to rebuild manually or target a specific host:
#### Applying Configuration Changes
After modifying files in this repository:
```bash
# Local build
sudo nixos-rebuild switch --flake .
# Test the configuration builds
nix flake check
# Build for a specific host
sudo nixos-rebuild switch --flake .#nix-laptop1
# Push changes to GitHub
git add .
git commit -m "Description of changes"
git push
# Users can then run: update-system
```
### Updating Flake Inputs
#### Manual Rebuilds
To update the lockfile (nixpkgs, home-manager versions, etc.):
For testing or emergency fixes:
```bash
# Rebuild current host
sudo nixos-rebuild switch --flake .
# Rebuild specific host
sudo nixos-rebuild switch --flake .#nix-laptop1
# Test without switching
sudo nixos-rebuild test --flake .#nix-laptop1
```
#### Updating Dependencies
Update nixpkgs, home-manager, and other flake inputs:
```bash
# Update all inputs
nix flake update
# Update specific input
nix flake lock --update-input nixpkgs
# After updating, test and commit the new flake.lock
git add flake.lock
git commit -m "Update flake inputs"
```
## Building Artifacts (ISOs, LXC, Proxmox)
@@ -95,103 +159,159 @@ nix build .#proxmox-nix-lxc1
## Configuration Guide
### Adding a New User
### User Management
#### Adding a New User
1. Open `users.nix`.
2. Add a new entry to `modules.users.accounts`.
3. Generate a hashed password using `mkpasswd -m sha-512` (requires `whois` package or similar).
- Hashed passwords are intended for shared credentials as a minimal layer of safety; do not treat them as secure storage for personal secrets (use per-user secrets managed outside the flake instead).
4. Commit and push.
2. Add a new entry to `ugaif.users.accounts`:
### Assigning Users to Hosts
```nix
ugaif.users.accounts = {
# ... existing users ...
newuser = {
description = "New User Name";
extraGroups = [ "networkmanager" "wheel" ];
hashedPassword = "$6$..."; # Generate with: mkpasswd -m sha-512
opensshKeys = [ "ssh-ed25519 AAAA..." ];
};
};
```
By default, only `root` and `engr-ugaif` are enabled. To enable a specific student user on a specific device:
3. Generate a hashed password using `mkpasswd -m sha-512` (requires `whois` package).
4. Commit and push the changes.
**Note:** Hashed passwords are for shared credentials only. For personal secrets, use external secret management.
#### Assigning Users to Hosts
By default, only `root` and `engr-ugaif` are enabled on all systems. To enable additional users on specific devices:
1. Open `inventory.nix`.
2. Locate the host type (e.g., `nix-laptop`).
3. Add or update the `devices` section for the specific index:
3. Add the user to the device's `extraUsers` list:
```nix
nix-laptop = {
count = 2;
devices = {
"1" = { extraUsers = [ "student_username" ]; };
"1".extraUsers = [ "newuser" "hdh20267" ];
};
};
```
### Using External Flakes for User Configuration
#### Using External Flakes for User Configuration
### Customizing the Kiosk URL for Surfaces
Users can manage their own dotfiles and configuration in a separate flake repository. This allows full control over shell configuration, editor settings, and Home Manager modules.
Surface tablets run the kiosk configuration and delegate the Chromium launch URL via `sw.kioskUrl`. You can set a per-device URL directly from `inventory.nix` by providing a `modules` override for the device entry:
**Security Note:** External flakes run with the same privileges as the system configuration. Only use trusted flakes and pin to specific commits.
To enable this:
1. Open `users.nix`.
2. Set the `flakeUrl` for the user:
```nix
hdh20267 = {
description = "User Name";
extraGroups = [ "networkmanager" "wheel" ];
hashedPassword = "$6$...";
flakeUrl = "github:hdh20267/dotfiles";
# Optional: Disable system defaults
useZshTheme = false; # Manage your own Zsh config
useNvimPlugins = false; # Manage your own Neovim config
};
```
The external flake must provide a `nixosModules.default` output. See [User Flake Template](#user-flake-for-usersnix) below for an example.
### Host Configuration
#### Adding a New Host
To add more devices of an existing type:
1. Open `inventory.nix`.
2. Increment the `count` for the host type:
```nix
nix-laptop.count = 3; # Creates nix-laptop1, nix-laptop2, nix-laptop3
```
#### Device-Specific Configuration Overrides
You can customize individual devices in `inventory.nix` using either shortcut keys or direct configuration.
**Shortcut Keys** (for common settings):
- `extraUsers` → Sets `ugaif.users.enabledUsers`
- `hostname` → Sets a custom hostname (default: `{type}{number}`)
- `buildMethods` → Sets `ugaif.host.buildMethods`
- `wslUser` → Sets `ugaif.host.wsl.user`
- `flakeUrl` → Imports an external system flake
**Direct Configuration** (using the `ugaif` namespace or standard NixOS options):
```nix
nix-laptop = {
count = 2;
devices = {
"1" = {
# Shortcut keys
extraUsers = [ "hdh20267" ];
hostname = "laptop-special";
# UGAIF options
ugaif.host.filesystem.swapSize = "64G";
ugaif.sw.extraPackages = with pkgs; [ docker vim ];
# Standard NixOS options
networking.firewall.enable = false;
services.openssh.enable = true;
};
};
};
```
#### Customizing Kiosk URLs for Surface Tablets
Surface tablets run in kiosk mode with a full-screen Chromium browser. Set the URL per-device:
```nix
nix-surface = {
count = 3;
devices = {
"1" = {
modules = {
sw = {
kioskUrl = "https://ha.factory.uga.edu/surface-1";
};
};
};
"1".ugaif.sw.kioskUrl = "https://ha.factory.uga.edu/dashboard-1";
"2".ugaif.sw.kioskUrl = "https://ha.factory.uga.edu/dashboard-2";
};
};
```
Any other device attributes (filesystem overrides, extra users) can still sit beside `modules`; they are merged into the generated host configuration so you just need to set the `kioskUrl` value you want to use for that Surface.
#### Using External Flakes for System Configuration
Users can manage their own configuration (both Home Manager and System-level settings) in a separate flake repository. External flakes run with the same privileges as the primary configuration, so audit any flake before pointing to it and pin to a known-good commit when possible.
To use this:
1. Open `users.nix`.
2. In the user's configuration block, set the `flakeUrl` option:
```nix
hdh20267 = {
# ... other settings ...
flakeUrl = "github:hdh20267/dotfiles";
};
```
The external flake must provide a `nixosModules.default` output. This module is imported into the system configuration, allowing the user to override their own system settings (like `shell`, `extraGroups`) and define their Home Manager configuration.
You can also opt-out of the default system configurations for Zsh and Neovim if you prefer to manage them entirely yourself:
* `useZshTheme` (default: `true`): Set to `false` to disable the system-wide Zsh theme and configuration.
* `useNvimPlugins` (default: `true`): Set to `false` to disable the system-wide Neovim plugins and configuration.
### 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, installing system-wide packages, or even overriding hardware settings (like swap size) without modifying `inventory.nix`.
1. Open `inventory.nix`.
2. In the `devices` override for the host, set the `flakeUrl`:
For complex system customizations (Docker, custom services, hardware tweaks), use an external flake:
```nix
nix-laptop = {
count = 2;
devices = {
"2" = {
flakeUrl = "github:myuser/my-system-config";
};
"2".flakeUrl = "github:myuser/my-system-config";
};
};
```
The external flake must provide a `nixosModules.default` output. Any configuration defined in that module will be merged with the host's configuration, so treat these flakes as privileged code and audit them before importing.
The external flake must provide a `nixosModules.default` output. See [System Flake Template](#system-flake-for-inventorynix) below for an example.
## External Flake Templates
If you are creating a new flake to use with `flakeUrl`, use these templates as a starting point.
If you're creating a flake to use with `flakeUrl`, use these templates as starting points.
**Important:** Do not specify `inputs` in your flake. This ensures your flake uses the exact same `nixpkgs` version as the main system, preventing version drift and saving disk space.
### User Flake (for `users.nix`)
Use this for user-specific dotfiles, shell configuration, and user packages. It can also override system-level user settings.
Note that `inputs` are omitted. This ensures the flake uses the exact same `nixpkgs` version as the main system, preventing version drift and saving disk space.
Use this template for user-specific dotfiles, shell configuration, Home Manager modules, and overriding user account settings.
```nix
{
@@ -204,7 +324,7 @@ Note that `inputs` are omitted. This ensures the flake uses the exact same `nixp
nixosModules.default = { pkgs, lib, ... }: {
# 1. Override System-Level User Settings
modules.users.accounts.hdh20267 = {
ugaif.users.accounts.hdh20267 = {
shell = pkgs.fish;
extraGroups = [ "docker" ];
@@ -239,7 +359,7 @@ Note that `inputs` are omitted. This ensures the flake uses the exact same `nixp
### System Flake (for `inventory.nix`)
Use this for host-specific system services, hardware tweaks, or root-level packages.
Use this template for host-specific system services (Docker, databases, web servers), hardware configuration tweaks, or system-wide packages.
```nix
{
@@ -255,10 +375,10 @@ Use this for host-specific system services, hardware tweaks, or root-level packa
virtualisation.docker.enable = true;
# Example: Override hardware settings defined in the main repo
host.filesystem.swapSize = lib.mkForce "64G";
ugaif.host.filesystem.swapSize = lib.mkForce "64G";
# Example: Enable specific users
modules.users.enabledUsers = [ "myuser" ];
ugaif.users.enabledUsers = [ "myuser" ];
# Example: Add a custom binary cache
nix.settings.substituters = [ "https://nix-community.cachix.org" ];
@@ -268,20 +388,93 @@ Use this for host-specific system services, hardware tweaks, or root-level packa
}
```
### Adding a New Host
1. Open `inventory.nix`.
2. Increment the `count` for the relevant host type.
3. The new host will be named sequentially (e.g., `nix-laptop3`).
## Development
### Python Environment
The system comes with `pixi` and `uv` for Python project management. It is recommended to use these tools for project-specific environments rather than installing global Python packages.
All systems include `pixi` and `uv` for Python project management. Use these tools for project-specific environments instead of installing global Python packages (which can cause conflicts).
**Creating a new project with Pixi:**
```bash
pixi init my_project
cd my_project
pixi add pandas numpy
pixi add pandas numpy matplotlib
pixi run python script.py
```
**Using uv for quick tasks:**
```bash
uv venv
source .venv/bin/activate
uv pip install requests
```
### Testing Changes Locally
Before pushing changes, verify your configuration builds correctly:
```bash
# Check all configurations
nix flake check
# Build a specific configuration
nix build .#nixosConfigurations.nix-laptop1.config.system.build.toplevel
# Test an ISO build
nix build .#installer-iso-nix-laptop1
```
### Common Configuration Patterns
#### Adding System Packages to All Hosts
Edit `sw/desktop/programs.nix` (or the appropriate type directory) to add packages to the base system:
```nix
basePackages = with pkgs; [
htop
vim
git
# Add your packages here
];
```
#### Changing Default User Shell
Edit `users.nix` to set a different shell for a specific user:
```nix
myuser = {
description = "My User";
shell = pkgs.fish; # or pkgs.zsh, pkgs.bash
# ... other settings
};
```
Then ensure the program is enabled in the system configuration (usually already done for common shells).
## Troubleshooting
### Flake Check Errors
If `nix flake check` fails, use `--show-trace` for detailed error information:
```bash
nix flake check --show-trace
```
### External Flakes Not Loading
If using `flakeUrl`, ensure:
1. The flake repository is public or you have SSH access configured
2. The flake has a `nixosModules.default` output
3. You're using `--impure` flag if the flake has impure operations
### Build Failures on Surface Tablets
Surface tablets automatically offload builds to remote builders. If builds fail:
1. Verify the remote builder is accessible: `ssh engr-ugaif@nix-builder`
2. Check remote builder has sufficient disk space: `df -h`
3. Try building locally with remote builds disabled by commenting out `ugaif.sw.remoteBuild.enable`

1
assets/plymouth-theme Submodule

Submodule assets/plymouth-theme added at 8658f4fb40

View File

@@ -85,7 +85,7 @@
{
# Formatter for 'nix fmt'
formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.nixfmt-rfc-style);
# Generate NixOS configurations from hosts/default.nix
nixosConfigurations = hosts.nixosConfigurations;

View File

@@ -8,11 +8,11 @@
# Boot & Storage Configuration
# ============================================================================
# This module defines the Disko partition layout and bootloader settings.
# It exposes 'host.filesystem' options to allow per-host overrides of
# It exposes 'ugaif.host.filesystem' options to allow per-host overrides of
# the target device and swap size.
{
options.host = {
options.ugaif.host = {
filesystem = {
device = lib.mkOption {
type = lib.types.str;
@@ -45,7 +45,7 @@
disko.devices = {
disk.main = {
type = "disk";
device = config.host.filesystem.device;
device = config.ugaif.host.filesystem.device;
content = {
type = "gpt";
partitions = {
@@ -71,7 +71,7 @@
swap = {
name = "swap";
label = "swap";
size = config.host.filesystem.swapSize;
size = config.ugaif.host.filesystem.swapSize;
content = {
type = "swap";
};

View File

@@ -60,7 +60,7 @@ let
# 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 { };
accounts = usersData.ugaif.users.accounts or { };
# Extract flakeUrls and convert to modules
userFlakeModules = lib.mapAttrsToList (
@@ -70,6 +70,14 @@ let
else
{ }
) accounts;
allModules =
commonModules
++ userFlakeModules
++ extraModules
++ [
{ networking.hostName = hostName; }
];
in
{
system = lib.nixosSystem {
@@ -77,21 +85,9 @@ let
specialArgs = { inherit inputs; };
modules =
commonModules
++ userFlakeModules
++ extraModules
++ [
{ networking.hostName = hostName; }
];
modules = allModules;
};
modules =
commonModules
++ userFlakeModules
++ extraModules
++ [
{ networking.hostName = hostName; }
];
modules = allModules;
};
# Function to generate a set of hosts based on inventory count and overrides
@@ -127,27 +123,22 @@ let
overrideModule =
{ ... }:
let
# Remove special keys for filesystem overrides, keep other config attrs
fsConf = builtins.removeAttrs devConf [
# Extract device-specific config, removing special keys that need custom handling
baseConfig = lib.removeAttrs devConf [
"extraUsers"
"flakeUrl"
"hostname"
"modules"
"buildMethods"
"wslUser"
];
extraConfig = lib.removeAttrs devConf [
"extraUsers"
"flakeUrl"
"hostname"
"buildMethods"
"wslUser"
# Handle special keys that map to specific ugaif options
specialConfig = lib.mkMerge [
(lib.optionalAttrs (devConf ? extraUsers) { ugaif.users.enabledUsers = devConf.extraUsers; })
(lib.optionalAttrs (devConf ? buildMethods) { ugaif.host.buildMethods = devConf.buildMethods; })
(lib.optionalAttrs (devConf ? wslUser) { ugaif.host.wsl.user = devConf.wslUser; })
];
in
lib.mkIf hasOverride (lib.recursiveUpdate (lib.recursiveUpdate {
host.filesystem = fsConf;
modules.users.enabledUsers = devConf.extraUsers or [ ];
} (lib.optionalAttrs (devConf ? buildMethods) { host.buildMethods = devConf.buildMethods; } // lib.optionalAttrs (devConf ? wslUser) { host.wsl.user = devConf.wslUser; })) extraConfig);
lib.mkIf hasOverride (lib.recursiveUpdate baseConfig specialConfig);
config = mkHost {
hostName = hostName;

View File

@@ -28,16 +28,16 @@
"rd.systemd.show_status=auto"
];
host.filesystem.swapSize = lib.mkDefault "16G";
host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
host.buildMethods = lib.mkDefault [ "installer-iso" ];
ugaif.host.filesystem.swapSize = lib.mkDefault "16G";
ugaif.host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
ugaif.host.buildMethods = lib.mkDefault [ "installer-iso" ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}
)
{
modules.sw.enable = true;
modules.sw.type = "desktop";
ugaif.sw.enable = true;
ugaif.sw.type = "desktop";
}
]

View File

@@ -31,10 +31,13 @@
];
# Ephemeral setup: No swap, no disk
host.filesystem.swapSize = lib.mkForce "0G";
host.filesystem.device = lib.mkForce "/dev/null"; # Dummy device
host.buildMethods = lib.mkDefault [ "iso" "ipxe" ];
ugaif.host.filesystem.swapSize = lib.mkForce "0G";
ugaif.host.filesystem.device = lib.mkForce "/dev/null"; # Dummy device
ugaif.host.buildMethods = lib.mkDefault [
"iso"
"ipxe"
];
# Disable Disko config since we are running from RAM/ISO
disko.enableConfig = lib.mkForce false;
@@ -42,7 +45,11 @@
fileSystems."/" = {
device = "none";
fsType = "tmpfs";
options = [ "defaults" "size=50%" "mode=755" ];
options = [
"defaults"
"size=50%"
"mode=755"
];
};
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
@@ -50,7 +57,7 @@
}
)
{
modules.sw.enable = true;
modules.sw.type = "stateless-kiosk";
ugaif.sw.enable = true;
ugaif.sw.type = "stateless-kiosk";
}
]

View File

@@ -35,9 +35,9 @@
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
host.filesystem.swapSize = lib.mkDefault "34G";
host.buildMethods = lib.mkDefault [ "installer-iso" ];
ugaif.host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
ugaif.host.filesystem.swapSize = lib.mkDefault "34G";
ugaif.host.buildMethods = lib.mkDefault [ "installer-iso" ];
# Suspend / logind behavior
services.upower.enable = lib.mkDefault true;
@@ -51,7 +51,7 @@
}
)
{
modules.sw.enable = true;
modules.sw.type = "desktop";
ugaif.sw.enable = true;
ugaif.sw.type = "desktop";
}
]

View File

@@ -35,11 +35,14 @@
];
services.vscode-server.enable = true;
system.stateVersion = "25.11";
host.buildMethods = lib.mkDefault [ "lxc" "proxmox" ];
ugaif.host.buildMethods = lib.mkDefault [
"lxc"
"proxmox"
];
}
)
{
modules.sw.enable = true;
modules.sw.type = "headless";
ugaif.sw.enable = true;
ugaif.sw.type = "headless";
}
]

View File

@@ -43,9 +43,9 @@
boot.kernelPackages = lib.mkForce refKernelPackages;
host.filesystem.swapSize = lib.mkDefault "8G";
host.filesystem.device = lib.mkDefault "/dev/mmcblk0";
host.buildMethods = lib.mkDefault [ "installer-iso" ];
ugaif.host.filesystem.swapSize = lib.mkDefault "8G";
ugaif.host.filesystem.device = lib.mkDefault "/dev/mmcblk0";
ugaif.host.buildMethods = lib.mkDefault [ "installer-iso" ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
@@ -53,7 +53,7 @@
)
inputs.nixos-hardware.nixosModules.microsoft-surface-go
{
modules.sw.enable = true;
modules.sw.type = "tablet-kiosk";
ugaif.sw.enable = true;
ugaif.sw.type = "tablet-kiosk";
}
]

View File

@@ -2,35 +2,38 @@
[
inputs.nixos-wsl.nixosModules.default
inputs.vscode-server.nixosModules.default
({ lib, config, ... }: {
options.host.wsl.user = lib.mkOption {
type = lib.types.str;
default = "engr-ugaif";
description = "The default user to log in as in WSL.";
};
(
{ lib, config, ... }:
{
options.ugaif.host.wsl.user = lib.mkOption {
type = lib.types.str;
default = "engr-ugaif";
description = "The default user to log in as in WSL.";
};
config = {
wsl.enable = true;
wsl.defaultUser = config.host.wsl.user;
# Enable the headless software profile
modules.sw.enable = true;
modules.sw.type = "headless";
config = {
wsl.enable = true;
wsl.defaultUser = config.ugaif.host.wsl.user;
# Fix for VS Code Server in WSL if needed, though vscode-server input exists
services.vscode-server.enable = true;
# Enable the headless software profile
ugaif.sw.enable = true;
ugaif.sw.type = "headless";
# Disable Disko and Bootloader for WSL
disko.enableConfig = lib.mkForce false;
boot.loader.systemd-boot.enable = lib.mkForce false;
boot.loader.grub.enable = lib.mkForce false;
# Fix for VS Code Server in WSL if needed, though vscode-server input exists
services.vscode-server.enable = true;
# Disable networking for wsl (it manages its own networking)
systemd.network.enable = lib.mkForce false;
# Provide dummy values for required options from boot.nix
host.filesystem.device = "/dev/null";
host.filesystem.swapSize = "0G";
};
})
# Disable Disko and Bootloader for WSL
disko.enableConfig = lib.mkForce false;
boot.loader.systemd-boot.enable = lib.mkForce false;
boot.loader.grub.enable = lib.mkForce false;
# Disable networking for wsl (it manages its own networking)
systemd.network.enable = lib.mkForce false;
# Provide dummy values for required options from boot.nix
ugaif.host.filesystem.device = "/dev/null";
ugaif.host.filesystem.swapSize = "0G";
};
}
)
]

View File

@@ -77,7 +77,7 @@ let
};
in
{
options.modules.users = {
options.ugaif.users = {
shell = lib.mkOption {
type = lib.types.package;
default = pkgs.bash;
@@ -97,7 +97,7 @@ in
config = {
# Default enabled users (always present)
modules.users.enabledUsers = [
ugaif.users.enabledUsers = [
"root"
"engr-ugaif"
];
@@ -106,8 +106,8 @@ in
users.users =
let
enabledAccounts = lib.filterAttrs (
name: _: lib.elem name config.modules.users.enabledUsers
) config.modules.users.accounts;
name: _: lib.elem name config.ugaif.users.enabledUsers
) config.ugaif.users.accounts;
in
lib.mapAttrs (
name: user:
@@ -121,7 +121,7 @@ in
description = if user.description != null then user.description else lib.mkDefault "";
openssh.authorizedKeys.keys = user.opensshKeys;
packages = finalPackages;
shell = if user.shell != null then user.shell else config.modules.users.shell;
shell = if user.shell != null then user.shell else config.ugaif.users.shell;
}
) enabledAccounts;
@@ -136,8 +136,8 @@ in
users =
let
enabledAccounts = lib.filterAttrs (
name: _: lib.elem name config.modules.users.enabledUsers
) config.modules.users.accounts;
name: _: lib.elem name config.ugaif.users.enabledUsers
) config.ugaif.users.accounts;
in
lib.mapAttrs (
name: user:

View File

@@ -1,4 +1,9 @@
{ inputs, hosts, self, system }:
{
inputs,
hosts,
self,
system,
}:
# This file defines the logic for generating various build artifacts (ISOs, Netboot, LXC, etc.)
# It exports a set of packages that can be built using `nix build .#<artifact-name>`
let
@@ -9,7 +14,8 @@ let
# Creates a self-installing ISO for a specific host configuration
# This ISO will automatically partition the disk (using disko) and install the system
mkInstaller = hostName:
mkInstaller =
hostName:
let
targetConfig = self.nixosConfigurations.${hostName}.config;
targetSystem = targetConfig.system.build.toplevel;
@@ -18,7 +24,12 @@ let
nixpkgs.lib.nixosSystem {
inherit system;
specialArgs = {
inherit inputs hostName targetSystem diskoScript;
inherit
inputs
hostName
targetSystem
diskoScript
;
hostPlatform = system;
};
modules = [
@@ -29,7 +40,8 @@ let
};
# Uses nixos-generators to create artifacts like LXC containers, Proxmox VMA, or Live ISOs
mkGenerator = hostName: format:
mkGenerator =
hostName: format:
nixos-generators.nixosGenerate {
inherit system;
specialArgs = { inherit inputs; };
@@ -44,7 +56,8 @@ let
# Creates Netboot (iPXE) artifacts using the native NixOS netboot module
# Returns a system configuration that includes the netboot module
mkNetboot = hostName:
mkNetboot =
hostName:
nixpkgs.lib.nixosSystem {
inherit system;
specialArgs = { inherit inputs; };
@@ -60,66 +73,110 @@ let
hostNames = builtins.attrNames hosts.nixosConfigurations;
# Generate installer ISOs for hosts that have "installer-iso" in their buildMethods
installerPackages = lib.listToAttrs (lib.concatMap (name:
let cfg = hosts.nixosConfigurations.${name}; in
if lib.elem "installer-iso" cfg.config.host.buildMethods then [{
name = "installer-iso-${name}";
value = (mkInstaller name).config.system.build.isoImage;
}] else []
) hostNames);
installerPackages = lib.listToAttrs (
lib.concatMap (
name:
let
cfg = hosts.nixosConfigurations.${name};
in
if lib.elem "installer-iso" cfg.config.ugaif.host.buildMethods then
[
{
name = "installer-iso-${name}";
value = (mkInstaller name).config.system.build.isoImage;
}
]
else
[ ]
) hostNames
);
# Generate Live ISOs for hosts that have "iso" in their buildMethods
isoPackages = lib.listToAttrs (lib.concatMap (name:
let cfg = hosts.nixosConfigurations.${name}; in
if lib.elem "iso" cfg.config.host.buildMethods then [{
name = "iso-${name}";
value = mkGenerator name "iso";
}] else []
) hostNames);
isoPackages = lib.listToAttrs (
lib.concatMap (
name:
let
cfg = hosts.nixosConfigurations.${name};
in
if lib.elem "iso" cfg.config.ugaif.host.buildMethods then
[
{
name = "iso-${name}";
value = mkGenerator name "iso";
}
]
else
[ ]
) hostNames
);
# Generate iPXE artifacts (kernel, initrd, script) for hosts that have "ipxe" in their buildMethods
ipxePackages = lib.listToAttrs (lib.concatMap (name:
let cfg = hosts.nixosConfigurations.${name}; in
if lib.elem "ipxe" cfg.config.host.buildMethods then [{
name = "ipxe-${name}";
value =
let
build = (mkNetboot name).config.system.build;
in
pkgs.symlinkJoin {
name = "netboot-artifacts-${name}";
paths = [
build.netbootRamdisk
build.kernel
build.netbootIpxeScript
];
};
}] else []
) hostNames);
ipxePackages = lib.listToAttrs (
lib.concatMap (
name:
let
cfg = hosts.nixosConfigurations.${name};
in
if lib.elem "ipxe" cfg.config.ugaif.host.buildMethods then
[
{
name = "ipxe-${name}";
value =
let
build = (mkNetboot name).config.system.build;
in
pkgs.symlinkJoin {
name = "netboot-artifacts-${name}";
paths = [
build.netbootRamdisk
build.kernel
build.netbootIpxeScript
];
};
}
]
else
[ ]
) hostNames
);
# Generate LXC tarballs for hosts that have "lxc" in their buildMethods
lxcPackages = lib.listToAttrs (lib.concatMap (name:
let cfg = hosts.nixosConfigurations.${name}; in
if lib.elem "lxc" cfg.config.host.buildMethods then [{
name = "lxc-${name}";
value =
if cfg.config.boot.isContainer then
cfg.config.system.build.tarball
else
mkGenerator name "lxc";
}] else []
) hostNames);
lxcPackages = lib.listToAttrs (
lib.concatMap (
name:
let
cfg = hosts.nixosConfigurations.${name};
in
if lib.elem "lxc" cfg.config.ugaif.host.buildMethods then
[
{
name = "lxc-${name}";
value =
if cfg.config.boot.isContainer then cfg.config.system.build.tarball else mkGenerator name "lxc";
}
]
else
[ ]
) hostNames
);
proxmoxPackages = lib.listToAttrs (lib.concatMap (name:
let cfg = hosts.nixosConfigurations.${name}; in
if lib.elem "proxmox" cfg.config.host.buildMethods then [{
name = "proxmox-${name}";
value =
if cfg.config.boot.isContainer then
cfg.config.system.build.tarball
else
mkGenerator name "proxmox";
}] else []
) hostNames);
proxmoxPackages = lib.listToAttrs (
lib.concatMap (
name:
let
cfg = hosts.nixosConfigurations.${name};
in
if lib.elem "proxmox" cfg.config.ugaif.host.buildMethods then
[
{
name = "proxmox-${name}";
value =
if cfg.config.boot.isContainer then cfg.config.system.build.tarball else mkGenerator name "proxmox";
}
]
else
[ ]
) hostNames
);
in
installerPackages // isoPackages // ipxePackages // lxcPackages // proxmoxPackages

View File

@@ -1,7 +1,17 @@
# This module defines a systemd service that automatically installs NixOS to the disk.
# It is intended to be used in an installation ISO.
# It expects `targetSystem` (the closure to install) and `diskoScript` (the partitioning script) to be passed as arguments.
{ config, lib, pkgs, inputs, hostName, hostPlatform, targetSystem, diskoScript, ... }:
{
config,
lib,
pkgs,
inputs,
hostName,
hostPlatform,
targetSystem,
diskoScript,
...
}:
{
environment.systemPackages = [
pkgs.git
@@ -14,7 +24,10 @@
systemd.services.auto-install = {
description = "Automatic NixOS install for ${hostName}";
after = [ "network-online.target" "systemd-udev-settle.service" ];
after = [
"network-online.target"
"systemd-udev-settle.service"
];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];

View File

@@ -47,7 +47,7 @@
nix-surface = {
count = 3;
devices = {
"1".modules.sw.kioskUrl = "https://google.com";
"1".ugaif.sw.kioskUrl = "https://google.com";
};
};

View File

@@ -16,7 +16,7 @@
with lib;
let
cfg = config.modules.sw;
cfg = config.ugaif.sw;
in
{
imports = [
@@ -25,7 +25,7 @@ in
./updater.nix
];
options.modules.sw = {
options.ugaif.sw = {
enable = mkEnableOption "Standard Workstation Configuration";
type = mkOption {

View File

@@ -9,7 +9,7 @@
with lib;
let
cfg = config.modules.sw;
cfg = config.ugaif.sw;
basePackages = with pkgs; [
tmux
man

View File

@@ -6,7 +6,7 @@
}:
{
modules.sw.python.enable = lib.mkDefault true;
ugaif.sw.python.enable = lib.mkDefault true;
services.displayManager.sddm.enable = true;
services.desktopManager.plasma6.enable = true;

View File

@@ -9,7 +9,7 @@
with lib;
let
cfg = config.modules.sw;
cfg = config.ugaif.sw;
basePackages = with pkgs; [
tmux
man

View File

@@ -15,10 +15,10 @@
with lib;
let
cfg = config.modules.sw.python;
cfg = config.ugaif.sw.python;
in
{
options.modules.sw.python = {
options.ugaif.sw.python = {
enable = mkEnableOption "Python development tools (pixi, uv)" // {
default = true;
};

View File

@@ -9,15 +9,35 @@
}:
lib.mkMerge [
(import ./kiosk-browser.nix {
inherit config lib pkgs inputs;
inherit
config
lib
pkgs
inputs
;
})
(import ./services.nix {
inherit config lib pkgs inputs;
inherit
config
lib
pkgs
inputs
;
})
(import ./net.nix {
inherit config lib pkgs inputs;
inherit
config
lib
pkgs
inputs
;
})
(import ./programs.nix {
inherit config lib pkgs inputs;
inherit
config
lib
pkgs
inputs
;
})
]

View File

@@ -1,7 +1,11 @@
# This module configures Chromium for kiosk mode under Sway.
# It includes a startup script that determines the kiosk URL based on the machine's MAC address.
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
let
macCaseBuilder = (import ./mac-hostmap.nix { inherit lib; }).macCaseBuilder;

View File

@@ -13,15 +13,16 @@ let
# varName: the shell variable to assign
# prefix: optional string to prepend to the value (default: "")
# attrset: attribute set to use (default: hostmap)
macCaseBuilder = {
varName,
prefix ? "",
attrset ? hostmap
}:
macCaseBuilder =
{
varName,
prefix ? "",
attrset ? hostmap,
}:
lib.concatStringsSep "\n" (
lib.mapAttrsToList (mac: val: " ${mac}) ${varName}=${prefix}${val} ;;") attrset
);
in
in
{
inherit hostmap macCaseBuilder;
}

View File

@@ -1,5 +1,11 @@
# This module configures the network for the stateless kiosk using base networking (no systemd-networkd).
{ config, lib, pkgs, inputs, ... }:
{
config,
lib,
pkgs,
inputs,
...
}:
{
networking = {
useNetworkd = false;

View File

@@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
{
programs.sway = {
enable = true;

View File

@@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
let
macCaseBuilder = (import ./mac-hostmap.nix { inherit lib; }).macCaseBuilder;
shellCases = macCaseBuilder {

View File

@@ -6,7 +6,7 @@
}:
let
cfg = config.modules.sw;
cfg = config.ugaif.sw;
in
{
programs.dconf = {

View File

@@ -9,7 +9,7 @@
with lib;
let
cfg = config.modules.sw;
cfg = config.ugaif.sw;
basePackages = with pkgs; [
libcamera
chromium

View File

@@ -155,7 +155,7 @@
--noerrdialogs \
--disable-session-crashed-bubble \
--disable-infobars \
${config.modules.sw.kioskUrl}
${config.ugaif.sw.kioskUrl}
'';
};
};

View File

@@ -8,7 +8,7 @@
with lib;
{
options.modules.sw.remoteBuild = lib.mkOption {
options.ugaif.sw.remoteBuild = lib.mkOption {
type = types.submodule {
options = {
hosts = mkOption {
@@ -29,7 +29,7 @@ with lib;
};
config = {
modules.sw.remoteBuild.enable = lib.mkDefault (config.modules.sw.type == "tablet-kiosk");
ugaif.sw.remoteBuild.enable = lib.mkDefault (config.ugaif.sw.type == "tablet-kiosk");
environment.systemPackages = [
(pkgs.writeShellScriptBin "update-system" ''
@@ -62,18 +62,15 @@ with lib;
description = "System daemon to one-shot run the Nix updater from fleet flake as root";
serviceConfig = {
Type = "oneshot";
ExecStart =
ExecStart =
let
hosts = config.modules.sw.remoteBuild.hosts;
hosts = config.ugaif.sw.remoteBuild.hosts;
builders = lib.strings.concatMapStringsSep ";" (x: x) hosts;
rebuildCmd = "${pkgs.nixos-rebuild}/bin/nixos-rebuild switch --refresh";
source = "--flake github:UGA-Innovation-Factory/nixos-systems";
remoteBuildFlags = if config.modules.sw.remoteBuild.enable
then
''--builders "${builders}"''
else "";
remoteBuildFlags = if config.ugaif.sw.remoteBuild.enable then ''--builders "${builders}"'' else "";
in
"${rebuildCmd} ${remoteBuildFlags} --print-build-logs ${source}#${config.networking.hostName}";
"${rebuildCmd} ${remoteBuildFlags} --print-build-logs ${source}#${config.networking.hostName}";
User = "root";
Group = "root";
TimeoutStartSec = "0";

View File

@@ -5,11 +5,11 @@
# ============================================================================
# This file defines the available user accounts. These accounts are NOT
# enabled by default on all systems. They must be enabled via the
# 'modules.users.enabledUsers' option in inventory.nix or system flakes.
# 'ugaif.users.enabledUsers' option in inventory.nix or system flakes.
# Define the users here using the new option
# To generate a password hash, run: mkpasswd -m sha-512
modules.users.accounts = {
ugaif.users.accounts = {
root = {
isNormalUser = false;
hashedPassword = "!";