Compare commits
71 Commits
85ffa56d12
...
legacy/202
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4a44cbddb | ||
|
|
27281f223f | ||
|
|
9c4aa59868 | ||
|
|
07d32eb459 | ||
|
|
3edadbf546 | ||
|
|
1bcb354b0c | ||
|
|
b960ba8ff2 | ||
|
|
135a126b91 | ||
|
|
2e9c888f06 | ||
|
|
8e801474cf | ||
|
|
532a57ab3d | ||
|
|
b2ba4f59dc | ||
|
|
e02c904d16 | ||
|
|
6bf8e7fdb6 | ||
|
|
309efa9e16 | ||
|
|
b758bb2c71 | ||
|
|
4f5ad03bc9 | ||
|
|
79a0c3e75e | ||
|
|
29571e842a | ||
|
|
cf65a2a968 | ||
|
|
315b248f14 | ||
|
|
01c0dbc4ae | ||
|
|
6bcc562697 | ||
|
|
b9ea8d8a8e | ||
|
|
5f53d6c839 | ||
|
|
af22dbe03e | ||
|
|
8776f19562 | ||
|
|
89011003b5 | ||
|
|
b83c8709fc | ||
|
|
a6e9b2665d | ||
|
|
cb7df047a8 | ||
|
|
23af6a3050 | ||
|
|
f037ad8f49 | ||
|
|
958a815489 | ||
|
|
0c81e2218f | ||
|
|
cce1ee4a2c | ||
|
|
35223b6435 | ||
|
|
cb9bff5d74 | ||
|
|
aa233dbbc8 | ||
|
|
b81500bd7b | ||
|
|
4af1549b41 | ||
|
|
08802d3147 | ||
|
|
319111b469 | ||
|
|
44e8a897ca | ||
|
|
6e755a1db0 | ||
|
|
1d70023307 | ||
|
|
4819082ed3 | ||
|
|
22564e96d4 | ||
|
|
ee03958c1e | ||
|
|
d4079dae32 | ||
|
|
c3211f7446 | ||
|
|
65e0840c31 | ||
|
|
1f55099138 | ||
|
|
1dc81173e5 | ||
|
|
0e898c316d | ||
|
|
6b6f449d9f | ||
|
|
71ea6258e9 | ||
|
|
fd7a4b1156 | ||
|
|
ac4192f764 | ||
|
|
795d179788 | ||
|
|
2acb63e220 | ||
|
|
2b7fcf5f21 | ||
|
|
7b8dcc7621 | ||
|
|
7941135cb3 | ||
|
|
5eeaa48f09 | ||
|
|
75359032b1 | ||
|
|
af81786d52 | ||
|
|
90688ec5f1 | ||
|
|
0ba0e854cf | ||
|
|
811eb1bd4b | ||
|
|
6ab5f20946 |
81
.gitea/workflows/ci.yml
Normal file
81
.gitea/workflows/ci.yml
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request_review:
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
flake-check:
|
||||||
|
name: Flake Check
|
||||||
|
runs-on: [self-hosted, nix-builder]
|
||||||
|
needs: [format-check]
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check flake
|
||||||
|
run: nix flake check --show-trace --print-build-logs
|
||||||
|
|
||||||
|
format-check:
|
||||||
|
name: Format Check
|
||||||
|
runs-on: [self-hosted, nix-builder]
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
run: |
|
||||||
|
nix fmt **/*.nix
|
||||||
|
if ! git diff --quiet; then
|
||||||
|
echo "::error::Code is not formatted. Please run 'nix fmt **/*.nix' locally."
|
||||||
|
git diff
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
eval-configs:
|
||||||
|
name: Evaluate Key Configurations
|
||||||
|
runs-on: [self-hosted, nix-builder]
|
||||||
|
needs: [flake-check, format-check]
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
config:
|
||||||
|
- nix-builder
|
||||||
|
- nix-laptop1
|
||||||
|
- nix-desktop1
|
||||||
|
fail-fast: false
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Evaluate configuration
|
||||||
|
run: |
|
||||||
|
echo "Evaluating configuration for ${{ matrix.config }}"
|
||||||
|
nix eval .#nixosConfigurations.${{ matrix.config }}.config.system.build.toplevel.drvPath \
|
||||||
|
--show-trace
|
||||||
|
|
||||||
|
eval-artifacts:
|
||||||
|
name: Evaluate Artifacts
|
||||||
|
runs-on: [self-hosted, nix-builder]
|
||||||
|
needs: [flake-check, format-check]
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
artifact:
|
||||||
|
- lxc-nix-builder
|
||||||
|
- installer-iso-nix-laptop1
|
||||||
|
fail-fast: false
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Evaluate artifact
|
||||||
|
run: |
|
||||||
|
echo "Evaluating artifact ${{ matrix.artifact }}"
|
||||||
|
nix eval .#${{ matrix.artifact }}.drvPath \
|
||||||
|
--show-trace
|
||||||
44
.github/copilot-instructions.md
vendored
44
.github/copilot-instructions.md
vendored
@@ -1,12 +1,14 @@
|
|||||||
# GitHub Copilot Instructions for nixos-systems
|
# GitHub Copilot Instructions for Athenix
|
||||||
|
|
||||||
This repository manages NixOS configurations for the UGA Innovation Factory's fleet of devices using Nix flakes and a custom configuration system.
|
This repository manages NixOS configurations for the UGA Innovation Factory's fleet of devices using Nix flakes and a custom configuration system.
|
||||||
|
|
||||||
|
**Repository:** https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git
|
||||||
|
|
||||||
## Repository Overview
|
## Repository Overview
|
||||||
|
|
||||||
This is a **NixOS system configuration repository** that uses:
|
This is a **NixOS system configuration repository** that uses:
|
||||||
- **Nix flakes** for dependency management and reproducible builds
|
- **Nix flakes** for dependency management and reproducible builds
|
||||||
- **Custom namespace** (`ugaif.*`) for all Innovation Factory-specific options
|
- **Custom namespace** (`athenix.*`) for all Innovation Factory-specific options
|
||||||
- **Inventory-based** host generation from `inventory.nix`
|
- **Inventory-based** host generation from `inventory.nix`
|
||||||
- **External module support** for user and system configurations
|
- **External module support** for user and system configurations
|
||||||
- **Multiple hardware types**: desktops, laptops, Surface tablets, LXC containers, WSL
|
- **Multiple hardware types**: desktops, laptops, Surface tablets, LXC containers, WSL
|
||||||
@@ -30,18 +32,18 @@ This is a **NixOS system configuration repository** that uses:
|
|||||||
- **`templates/`**: Templates for external configurations
|
- **`templates/`**: Templates for external configurations
|
||||||
|
|
||||||
### Naming Conventions
|
### Naming Conventions
|
||||||
- Module options: Use `ugaif.*` namespace for all custom options
|
- Module options: Use `athenix.*` namespace for all custom options
|
||||||
- Hostnames: `{type}{number}` or `{type}-{name}` (e.g., `nix-laptop1`, `nix-surface-alpha`)
|
- Hostnames: `{type}{number}` or `{type}-{name}` (e.g., `nix-laptop1`, `nix-surface-alpha`)
|
||||||
- Hardware types: Prefix with `nix-` (e.g., `nix-desktop`, `nix-laptop`)
|
- Hardware types: Prefix with `nix-` (e.g., `nix-desktop`, `nix-laptop`)
|
||||||
- Software types: Use descriptive names (`desktop`, `tablet-kiosk`, `headless`)
|
- Software types: Use descriptive names (`desktop`, `tablet-kiosk`, `headless`)
|
||||||
|
|
||||||
## Custom Namespace (`ugaif`)
|
## Custom Namespace (`athenix`)
|
||||||
|
|
||||||
All Innovation Factory-specific options MUST use the `ugaif` namespace:
|
All Innovation Factory-specific options MUST use the `athenix` namespace:
|
||||||
|
|
||||||
### Host Options (`ugaif.host.*`)
|
### Host Options (`athenix.host.*`)
|
||||||
```nix
|
```nix
|
||||||
ugaif.host = {
|
athenix.host = {
|
||||||
filesystem.device = "/dev/sda"; # Boot disk
|
filesystem.device = "/dev/sda"; # Boot disk
|
||||||
filesystem.swapSize = "32G"; # Swap size
|
filesystem.swapSize = "32G"; # Swap size
|
||||||
buildMethods = [ "iso" ]; # Artifact types
|
buildMethods = [ "iso" ]; # Artifact types
|
||||||
@@ -50,9 +52,9 @@ ugaif.host = {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Software Options (`ugaif.sw.*`)
|
### Software Options (`athenix.sw.*`)
|
||||||
```nix
|
```nix
|
||||||
ugaif.sw = {
|
athenix.sw = {
|
||||||
type = "desktop"; # System type
|
type = "desktop"; # System type
|
||||||
kioskUrl = "https://..."; # Kiosk browser URL
|
kioskUrl = "https://..."; # Kiosk browser URL
|
||||||
python.enable = true; # Python tools (pixi, uv)
|
python.enable = true; # Python tools (pixi, uv)
|
||||||
@@ -64,13 +66,13 @@ ugaif.sw = {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### User Options (`ugaif.users.*`)
|
### User Options (`athenix.users.*`)
|
||||||
```nix
|
```nix
|
||||||
ugaif.users = {
|
athenix.users = {
|
||||||
accounts = { ... }; # User definitions
|
accounts = { ... }; # User definitions
|
||||||
enabledUsers = [ "root" "engr-ugaif" ]; # Enabled users
|
enabledUsers = [ "root" "engr-ugaif" ]; # Enabled users
|
||||||
};
|
};
|
||||||
ugaif.forUser = "username"; # Convenience: enable user + set WSL user
|
athenix.forUser = "username"; # Convenience: enable user + set WSL user
|
||||||
```
|
```
|
||||||
|
|
||||||
## Development Workflow
|
## Development Workflow
|
||||||
@@ -90,8 +92,8 @@ ugaif.forUser = "username"; # Convenience: enable user + set WSL user
|
|||||||
### Common Tasks
|
### Common Tasks
|
||||||
|
|
||||||
#### Adding a New User
|
#### Adding a New User
|
||||||
1. Edit `users.nix` to add user definition under `ugaif.users.accounts`
|
1. Edit `users.nix` to add user definition under `athenix.users.accounts`
|
||||||
2. Enable user in `inventory.nix` via `ugaif.users.username.enable = true` or use `ugaif.forUser = "username"`
|
2. Enable user in `inventory.nix` via `athenix.users.username.enable = true` or use `athenix.forUser = "username"`
|
||||||
3. Test: `nix flake check`
|
3. Test: `nix flake check`
|
||||||
|
|
||||||
#### Adding a New Host
|
#### Adding a New Host
|
||||||
@@ -102,11 +104,11 @@ ugaif.forUser = "username"; # Convenience: enable user + set WSL user
|
|||||||
#### Modifying Software Configuration
|
#### Modifying Software Configuration
|
||||||
1. Edit appropriate file in `sw/` directory based on system type
|
1. Edit appropriate file in `sw/` directory based on system type
|
||||||
2. For system-wide changes: modify `sw/{type}/programs.nix`
|
2. For system-wide changes: modify `sw/{type}/programs.nix`
|
||||||
3. For specific hosts: use `ugaif.sw.extraPackages` in `inventory.nix`
|
3. For specific hosts: use `athenix.sw.extraPackages` in `inventory.nix`
|
||||||
4. Test: `nix flake check`
|
4. Test: `nix flake check`
|
||||||
|
|
||||||
#### Creating External Modules
|
#### Creating External Modules
|
||||||
1. Use templates: `nix flake init -t github:UGA-Innovation-Factory/nixos-systems#{user|system}`
|
1. Use templates: `nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#{user|system}`
|
||||||
2. User modules: Provide `user.nix` (required) and `nixos.nix` (optional)
|
2. User modules: Provide `user.nix` (required) and `nixos.nix` (optional)
|
||||||
3. System modules: Provide `default.nix` that accepts `{ inputs, ... }`
|
3. System modules: Provide `default.nix` that accepts `{ inputs, ... }`
|
||||||
4. Reference in `inventory.nix` or `users.nix` using `builtins.fetchGit`
|
4. Reference in `inventory.nix` or `users.nix` using `builtins.fetchGit`
|
||||||
@@ -114,7 +116,7 @@ ugaif.forUser = "username"; # Convenience: enable user + set WSL user
|
|||||||
## Important Constraints
|
## Important Constraints
|
||||||
|
|
||||||
### What NOT to Do
|
### What NOT to Do
|
||||||
- **Never** use options outside the `ugaif` namespace for Innovation Factory-specific functionality
|
- **Never** use options outside the `athenix` namespace for Innovation Factory-specific functionality
|
||||||
- **Never** remove or modify working host configurations unless explicitly requested
|
- **Never** remove or modify working host configurations unless explicitly requested
|
||||||
- **Never** break existing functionality when adding new features
|
- **Never** break existing functionality when adding new features
|
||||||
- **Never** hardcode values that should be configurable
|
- **Never** hardcode values that should be configurable
|
||||||
@@ -122,7 +124,7 @@ ugaif.forUser = "username"; # Convenience: enable user + set WSL user
|
|||||||
|
|
||||||
### What to ALWAYS Do
|
### What to ALWAYS Do
|
||||||
- **Always** run `nix flake check` before finalizing changes
|
- **Always** run `nix flake check` before finalizing changes
|
||||||
- **Always** use the `ugaif.*` namespace for custom options
|
- **Always** use the `athenix.*` namespace for custom options
|
||||||
- **Always** preserve existing comment styles and documentation
|
- **Always** preserve existing comment styles and documentation
|
||||||
- **Always** test that configurations build successfully
|
- **Always** test that configurations build successfully
|
||||||
- **Always** consider impact on existing hosts when making changes
|
- **Always** consider impact on existing hosts when making changes
|
||||||
@@ -140,7 +142,7 @@ myuser.external = builtins.fetchGit {
|
|||||||
rev = "abc123..."; # Pin to specific commit
|
rev = "abc123..."; # Pin to specific commit
|
||||||
};
|
};
|
||||||
# The external user.nix file contains BOTH user account options
|
# The external user.nix file contains BOTH user account options
|
||||||
# (ugaif.users.myuser) AND home-manager configuration
|
# (athenix.users.myuser) AND home-manager configuration
|
||||||
```
|
```
|
||||||
|
|
||||||
### System Configurations
|
### System Configurations
|
||||||
@@ -184,7 +186,7 @@ nix flake show
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Artifact Types
|
### Artifact Types
|
||||||
Set via `ugaif.host.buildMethods`:
|
Set via `athenix.host.buildMethods`:
|
||||||
- `"iso"` - Installer ISO with auto-install
|
- `"iso"` - Installer ISO with auto-install
|
||||||
- `"live-iso"` - Live boot ISO without installer
|
- `"live-iso"` - Live boot ISO without installer
|
||||||
- `"lxc"` - LXC container tarball
|
- `"lxc"` - LXC container tarball
|
||||||
@@ -231,7 +233,7 @@ Set via `ugaif.host.buildMethods`:
|
|||||||
## Code Review Checklist
|
## Code Review Checklist
|
||||||
|
|
||||||
When reviewing or generating code:
|
When reviewing or generating code:
|
||||||
- [ ] Uses `ugaif.*` namespace for custom options
|
- [ ] Uses `athenix.*` namespace for custom options
|
||||||
- [ ] Runs `nix flake check` successfully
|
- [ ] Runs `nix flake check` successfully
|
||||||
- [ ] Follows existing code style and formatting
|
- [ ] Follows existing code style and formatting
|
||||||
- [ ] Preserves existing functionality
|
- [ ] Preserves existing functionality
|
||||||
|
|||||||
48
README.md
48
README.md
@@ -1,6 +1,6 @@
|
|||||||
# UGA Innovation Factory - NixOS Systems
|
# UGA Innovation Factory - Athenix
|
||||||
|
|
||||||
[](https://github.com/UGA-Innovation-Factory/nixos-systems/actions/workflows/ci.yml)
|
[](https://git.factory.uga.edu/UGA-Innovation-Factory/athenix/actions)
|
||||||
|
|
||||||
This repository contains the NixOS configuration for the Innovation Factory's fleet of laptops, desktops, Surface tablets, and containers. It provides a declarative, reproducible system configuration using Nix flakes.
|
This repository contains the NixOS configuration for the Innovation Factory's fleet of laptops, desktops, Surface tablets, and containers. It provides a declarative, reproducible system configuration using Nix flakes.
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ This repository contains the NixOS configuration for the Innovation Factory's fl
|
|||||||
|
|
||||||
- **[Quick Start](#quick-start)** - Get started in 5 minutes
|
- **[Quick Start](#quick-start)** - Get started in 5 minutes
|
||||||
- **[docs/INVENTORY.md](docs/INVENTORY.md)** - Configure hosts and fleet inventory
|
- **[docs/INVENTORY.md](docs/INVENTORY.md)** - Configure hosts and fleet inventory
|
||||||
- **[docs/NAMESPACE.md](docs/NAMESPACE.md)** - Configuration options reference (`ugaif.*`)
|
- **[docs/NAMESPACE.md](docs/NAMESPACE.md)** - Configuration options reference (`athenix.*`)
|
||||||
- **[docs/USER_CONFIGURATION.md](docs/USER_CONFIGURATION.md)** - User account management
|
- **[docs/USER_CONFIGURATION.md](docs/USER_CONFIGURATION.md)** - User account management
|
||||||
- **[docs/EXTERNAL_MODULES.md](docs/EXTERNAL_MODULES.md)** - External configuration modules
|
- **[docs/EXTERNAL_MODULES.md](docs/EXTERNAL_MODULES.md)** - External configuration modules
|
||||||
- **[docs/BUILDING.md](docs/BUILDING.md)** - Build ISOs and container images
|
- **[docs/BUILDING.md](docs/BUILDING.md)** - Build ISOs and container images
|
||||||
@@ -28,7 +28,7 @@ This command automatically fetches the latest configuration, rebuilds your syste
|
|||||||
|
|
||||||
**Note:** If you use external user configurations (personal dotfiles), run:
|
**Note:** If you use external user configurations (personal dotfiles), run:
|
||||||
```bash
|
```bash
|
||||||
sudo nixos-rebuild switch --flake github:UGA-Innovation-Factory/nixos-systems --impure
|
sudo nixos-rebuild switch --flake git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git --impure
|
||||||
```
|
```
|
||||||
|
|
||||||
### For Administrators
|
### For Administrators
|
||||||
@@ -83,22 +83,22 @@ nixos-systems/
|
|||||||
|
|
||||||
## Configuration Overview
|
## Configuration Overview
|
||||||
|
|
||||||
All Innovation Factory options use the `ugaif.*` namespace. See **[docs/NAMESPACE.md](docs/NAMESPACE.md)** for complete reference.
|
All Innovation Factory options use the `athenix.*` namespace. See **[docs/NAMESPACE.md](docs/NAMESPACE.md)** for complete reference.
|
||||||
|
|
||||||
**Quick examples:**
|
**Quick examples:**
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
# Host configuration
|
# Host configuration
|
||||||
ugaif.host.filesystem.device = "/dev/nvme0n1";
|
athenix.host.filesystem.device = "/dev/nvme0n1";
|
||||||
ugaif.host.filesystem.swapSize = "64G";
|
athenix.host.filesystem.swapSize = "64G";
|
||||||
|
|
||||||
# Software configuration
|
# Software configuration
|
||||||
ugaif.sw.type = "desktop"; # or "headless", "tablet-kiosk"
|
athenix.sw.type = "desktop"; # or "headless", "tablet-kiosk"
|
||||||
ugaif.sw.extraPackages = with pkgs; [ vim docker ];
|
athenix.sw.extraPackages = with pkgs; [ vim docker ];
|
||||||
|
|
||||||
# User management
|
# User management
|
||||||
ugaif.users.myuser.enable = true;
|
athenix.users.myuser.enable = true;
|
||||||
ugaif.forUser = "myuser"; # Convenience shortcut
|
athenix.forUser = "myuser"; # Convenience shortcut
|
||||||
```
|
```
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
@@ -134,7 +134,7 @@ myuser = {
|
|||||||
```nix
|
```nix
|
||||||
nix-laptop = {
|
nix-laptop = {
|
||||||
devices = 2;
|
devices = 2;
|
||||||
overrides.ugaif.users.myuser.enable = true;
|
overrides.athenix.users.myuser.enable = true;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -153,8 +153,8 @@ nix-laptop = {
|
|||||||
# With configuration
|
# With configuration
|
||||||
nix-surface = {
|
nix-surface = {
|
||||||
devices = {
|
devices = {
|
||||||
"1".ugaif.sw.kioskUrl = "https://dashboard1.example.com";
|
"1".athenix.sw.kioskUrl = "https://dashboard1.example.com";
|
||||||
"2".ugaif.sw.kioskUrl = "https://dashboard2.example.com";
|
"2".athenix.sw.kioskUrl = "https://dashboard2.example.com";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -162,8 +162,8 @@ nix-surface = {
|
|||||||
nix-desktop = {
|
nix-desktop = {
|
||||||
devices = 3;
|
devices = 3;
|
||||||
overrides = {
|
overrides = {
|
||||||
ugaif.users.student.enable = true;
|
athenix.users.student.enable = true;
|
||||||
ugaif.sw.extraPackages = with pkgs; [ vim ];
|
athenix.sw.extraPackages = with pkgs; [ vim ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -177,16 +177,16 @@ Users and systems can reference external Git repositories for configuration:
|
|||||||
```nix
|
```nix
|
||||||
# In users.nix - External dotfiles with user configuration
|
# In users.nix - External dotfiles with user configuration
|
||||||
myuser.external = builtins.fetchGit {
|
myuser.external = builtins.fetchGit {
|
||||||
url = "https://github.com/username/dotfiles";
|
url = "https://git.factory.uga.edu/username/dotfiles";
|
||||||
rev = "abc123...";
|
rev = "abc123...";
|
||||||
};
|
};
|
||||||
# The external user.nix file contains both ugaif.users.myuser options
|
# The external user.nix file contains both athenix.users.myuser options
|
||||||
# AND home-manager configuration
|
# AND home-manager configuration
|
||||||
|
|
||||||
# In inventory.nix - External system config
|
# In inventory.nix - External system config
|
||||||
nix-lxc = {
|
nix-lxc = {
|
||||||
devices."server" = builtins.fetchGit {
|
devices."server" = builtins.fetchGit {
|
||||||
url = "https://github.com/org/server-config";
|
url = "https://git.factory.uga.edu/org/server-config";
|
||||||
rev = "abc123...";
|
rev = "abc123...";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -195,10 +195,10 @@ nix-lxc = {
|
|||||||
**Create templates:**
|
**Create templates:**
|
||||||
```bash
|
```bash
|
||||||
# User configuration (dotfiles)
|
# User configuration (dotfiles)
|
||||||
nix flake init -t github:UGA-Innovation-Factory/nixos-systems#user
|
nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#user
|
||||||
|
|
||||||
# System configuration
|
# System configuration
|
||||||
nix flake init -t github:UGA-Innovation-Factory/nixos-systems#system
|
nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#system
|
||||||
```
|
```
|
||||||
|
|
||||||
**See [docs/EXTERNAL_MODULES.md](docs/EXTERNAL_MODULES.md) for complete guide.**
|
**See [docs/EXTERNAL_MODULES.md](docs/EXTERNAL_MODULES.md) for complete guide.**
|
||||||
@@ -207,13 +207,13 @@ nix flake init -t github:UGA-Innovation-Factory/nixos-systems#system
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Build installer ISO
|
# Build installer ISO
|
||||||
nix build github:UGA-Innovation-Factory/nixos-systems#installer-iso-nix-laptop1
|
nix build git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#installer-iso-nix-laptop1
|
||||||
|
|
||||||
# Build LXC container
|
# Build LXC container
|
||||||
nix build .#lxc-nix-builder
|
nix build .#lxc-nix-builder
|
||||||
|
|
||||||
# List all available artifacts
|
# List all available artifacts
|
||||||
nix flake show github:UGA-Innovation-Factory/nixos-systems
|
nix flake show git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git
|
||||||
```
|
```
|
||||||
|
|
||||||
**See [docs/BUILDING.md](docs/BUILDING.md) for complete guide on building ISOs, containers, and using remote builders.**
|
**See [docs/BUILDING.md](docs/BUILDING.md) for complete guide on building ISOs, containers, and using remote builders.**
|
||||||
@@ -225,7 +225,7 @@ nix flake show github:UGA-Innovation-Factory/nixos-systems
|
|||||||
- **`stateless-kiosk`** - Diskless PXE boot kiosks
|
- **`stateless-kiosk`** - Diskless PXE boot kiosks
|
||||||
- **`headless`** - Servers and containers (no GUI)
|
- **`headless`** - Servers and containers (no GUI)
|
||||||
|
|
||||||
Set via `ugaif.sw.type` option. See [docs/NAMESPACE.md](docs/NAMESPACE.md) for all options.
|
Set via `athenix.sw.type` option. See [docs/NAMESPACE.md](docs/NAMESPACE.md) for all options.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ This guide covers building installer ISOs, live images, and container artifacts
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Build an installer ISO for a specific host
|
# Build an installer ISO for a specific host
|
||||||
nix build github:UGA-Innovation-Factory/nixos-systems#installer-iso-nix-laptop1
|
nix build git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#installer-iso-nix-laptop1
|
||||||
|
|
||||||
# Result will be in result/iso/
|
# Result will be in result/iso/
|
||||||
ls -lh result/iso/
|
ls -lh result/iso/
|
||||||
@@ -27,7 +27,7 @@ ls -lh result/iso/
|
|||||||
List all available build outputs:
|
List all available build outputs:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix flake show github:UGA-Innovation-Factory/nixos-systems
|
nix flake show git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git
|
||||||
```
|
```
|
||||||
|
|
||||||
Common artifact types:
|
Common artifact types:
|
||||||
@@ -57,10 +57,10 @@ ls -lh result/iso/nixos-*.iso
|
|||||||
sudo dd if=result/iso/nixos-*.iso of=/dev/sdX bs=4M status=progress
|
sudo dd if=result/iso/nixos-*.iso of=/dev/sdX bs=4M status=progress
|
||||||
```
|
```
|
||||||
|
|
||||||
### Building from GitHub
|
### Building from Gitea
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix build github:UGA-Innovation-Factory/nixos-systems#installer-iso-nix-laptop1
|
nix build git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#installer-iso-nix-laptop1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using the Installer
|
### Using the Installer
|
||||||
@@ -70,7 +70,7 @@ nix build github:UGA-Innovation-Factory/nixos-systems#installer-iso-nix-laptop1
|
|||||||
3. After installation completes, remove the USB drive and reboot
|
3. After installation completes, remove the USB drive and reboot
|
||||||
4. Log in with the configured user credentials
|
4. Log in with the configured user credentials
|
||||||
|
|
||||||
**Note:** The installer will **erase all data** on the target disk specified in `ugaif.host.filesystem.device`.
|
**Note:** The installer will **erase all data** on the target disk specified in `athenix.host.filesystem.device`.
|
||||||
|
|
||||||
## Live ISOs
|
## Live ISOs
|
||||||
|
|
||||||
@@ -224,7 +224,7 @@ ssh engr-ugaif@nix-builder df -h
|
|||||||
|
|
||||||
In `inventory.nix`:
|
In `inventory.nix`:
|
||||||
```nix
|
```nix
|
||||||
ugaif.sw.remoteBuild.enable = false;
|
athenix.sw.remoteBuild.enable = false;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Out of Disk Space
|
### Out of Disk Space
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ sudo nixos-rebuild build --flake .
|
|||||||
|
|
||||||
## Continuous Integration
|
## Continuous Integration
|
||||||
|
|
||||||
The repository uses GitHub Actions for automated testing and validation. CI jobs run on the self-hosted `nix-builder` machine via SSH.
|
The repository uses Gitea Actions for automated testing and validation. CI jobs run on the self-hosted `nix-builder` machine.
|
||||||
|
|
||||||
### CI Workflow
|
### CI Workflow
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ Check the CI status badge at the top of the README or view detailed logs:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# View workflow status
|
# View workflow status
|
||||||
https://github.com/UGA-Innovation-Factory/nixos-systems/actions
|
https://git.factory.uga.edu/UGA-Innovation-Factory/athenix/actions
|
||||||
```
|
```
|
||||||
|
|
||||||
### Running CI Checks Locally
|
### Running CI Checks Locally
|
||||||
@@ -118,49 +118,49 @@ nix build .#lxc-nix-builder
|
|||||||
|
|
||||||
### Self-Hosted Runner
|
### Self-Hosted Runner
|
||||||
|
|
||||||
CI jobs run on the `nix-builder` host as a self-hosted GitHub Actions runner. This provides:
|
CI jobs run on the `nix-builder` host as a self-hosted Gitea Actions runner. This provides:
|
||||||
|
|
||||||
- Native Nix environment without installation overhead
|
- Native Nix environment without installation overhead
|
||||||
- Access to local Nix store for faster builds
|
- Access to local Nix store for faster builds
|
||||||
- Consistent build environment matching deployment targets
|
- Consistent build environment matching deployment targets
|
||||||
- Direct access to build caching infrastructure
|
- Direct access to build caching infrastructure
|
||||||
|
|
||||||
#### Setting Up the GitHub Actions Runner
|
#### Setting Up the Gitea Actions Runner
|
||||||
|
|
||||||
The nix-builder host is configured with a GitHub Actions self-hosted runner in `inventory.nix`. To complete the setup:
|
The nix-builder host is configured with a Gitea Actions self-hosted runner in `inventory.nix`. To complete the setup:
|
||||||
|
|
||||||
1. **Generate a GitHub Personal Access Token (PAT)**:
|
1. **Generate a Gitea Runner Token**:
|
||||||
- Go to https://github.com/settings/tokens
|
- Go to https://git.factory.uga.edu/UGA-Innovation-Factory/athenix/settings/actions/runners
|
||||||
- Create a new token with `repo` scope
|
- Click "Create new Runner"
|
||||||
- Copy the token value
|
- Copy the registration token
|
||||||
|
|
||||||
2. **Create the token file on nix-builder**:
|
2. **Create the token file on nix-builder**:
|
||||||
```bash
|
```bash
|
||||||
ssh engr-ugaif@nix-builder
|
ssh engr-ugaif@nix-builder
|
||||||
echo "YOUR_TOKEN_HERE" | sudo tee /var/lib/github-runner-token > /dev/null
|
echo "YOUR_TOKEN_HERE" | sudo tee /var/lib/gitea-runner-token > /dev/null
|
||||||
sudo chmod 600 /var/lib/github-runner-token
|
sudo chmod 600 /var/lib/gitea-runner-token
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Rebuild the system** to start the runner:
|
3. **Rebuild the system** to start the runner:
|
||||||
```bash
|
```bash
|
||||||
sudo nixos-rebuild switch --flake github:UGA-Innovation-Factory/nixos-systems#nix-builder
|
sudo nixos-rebuild switch --flake git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#nix-builder
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Verify the runner is registered**:
|
4. **Verify the runner is registered**:
|
||||||
- Check https://github.com/UGA-Innovation-Factory/nixos-systems/settings/actions/runners
|
- Check https://git.factory.uga.edu/UGA-Innovation-Factory/athenix/settings/actions/runners
|
||||||
- The runner should appear with the `nix-builder` label
|
- The runner should appear with the `nix-builder` label
|
||||||
|
|
||||||
The runner service is configured in the nix-builder device configuration and will automatically:
|
The runner service is configured in the nix-builder device configuration and will automatically:
|
||||||
- Register with the repository on first start
|
- Register with the repository on first start
|
||||||
- Use the `nix-builder` label for workflow targeting
|
- Use the `nix-builder` label for workflow targeting
|
||||||
- Run as the `engr-ugaif` user
|
- Run as the `engr-ugaif` user
|
||||||
- Store work in `/var/lib/github-runner`
|
- Store work in `/var/lib/gitea-runner`
|
||||||
|
|
||||||
### Troubleshooting CI Failures
|
### Troubleshooting CI Failures
|
||||||
|
|
||||||
If CI fails:
|
If CI fails:
|
||||||
|
|
||||||
1. **Check the error logs** in the GitHub Actions tab
|
1. **Check the error logs** in the Gitea Actions tab
|
||||||
2. **Run the same command locally** to reproduce the issue
|
2. **Run the same command locally** to reproduce the issue
|
||||||
3. **Use `--show-trace`** for detailed error information
|
3. **Use `--show-trace`** for detailed error information
|
||||||
4. **Verify formatting** with `nix fmt` if format check fails
|
4. **Verify formatting** with `nix fmt` if format check fails
|
||||||
@@ -195,13 +195,13 @@ sudo nixos-rebuild build --flake .
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Rebuild from GitHub main branch
|
# Rebuild from GitHub main branch
|
||||||
sudo nixos-rebuild switch --flake github:UGA-Innovation-Factory/nixos-systems
|
sudo nixos-rebuild switch --flake git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git
|
||||||
|
|
||||||
# Use --impure for external user configurations with fetchGit
|
# Use --impure for external user configurations with fetchGit
|
||||||
sudo nixos-rebuild switch --flake github:UGA-Innovation-Factory/nixos-systems --impure
|
sudo nixos-rebuild switch --flake git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git --impure
|
||||||
|
|
||||||
# Rebuild specific host from GitHub
|
# Rebuild specific host from GitHub
|
||||||
sudo nixos-rebuild switch --flake github:UGA-Innovation-Factory/nixos-systems#nix-laptop1
|
sudo nixos-rebuild switch --flake git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#nix-laptop1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Boot into Previous Generation
|
### Boot into Previous Generation
|
||||||
@@ -288,13 +288,13 @@ vim sw/headless/programs.nix
|
|||||||
|
|
||||||
### Packages for Specific Hosts
|
### Packages for Specific Hosts
|
||||||
|
|
||||||
Add to `ugaif.sw.extraPackages` in `inventory.nix`:
|
Add to `athenix.sw.extraPackages` in `inventory.nix`:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
nix-laptop = {
|
nix-laptop = {
|
||||||
devices = 2;
|
devices = 2;
|
||||||
overrides = {
|
overrides = {
|
||||||
ugaif.sw.extraPackages = with pkgs; [
|
athenix.sw.extraPackages = with pkgs; [
|
||||||
vim
|
vim
|
||||||
docker
|
docker
|
||||||
kubernetes-helm
|
kubernetes-helm
|
||||||
@@ -378,7 +378,7 @@ uv pip install -r requirements.txt
|
|||||||
Python development tools are configured in `sw/python.nix` and can be controlled via:
|
Python development tools are configured in `sw/python.nix` and can be controlled via:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
ugaif.sw.python.enable = true; # Default: enabled
|
athenix.sw.python.enable = true; # Default: enabled
|
||||||
```
|
```
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
@@ -388,7 +388,7 @@ ugaif.sw.python.enable = true; # Default: enabled
|
|||||||
- Run formatter before committing: `nix fmt`
|
- Run formatter before committing: `nix fmt`
|
||||||
- Follow existing code structure and conventions
|
- Follow existing code structure and conventions
|
||||||
- Add comments for complex logic
|
- Add comments for complex logic
|
||||||
- Use the `ugaif.*` namespace for all custom options
|
- Use the `athenix.*` namespace for all custom options
|
||||||
|
|
||||||
### Testing Workflow
|
### Testing Workflow
|
||||||
|
|
||||||
|
|||||||
@@ -32,13 +32,13 @@ nix-lxc = {
|
|||||||
devices = {
|
devices = {
|
||||||
# Traditional inline configuration
|
# Traditional inline configuration
|
||||||
"local-server" = {
|
"local-server" = {
|
||||||
ugaif.users.admin.enable = true;
|
athenix.users.admin.enable = true;
|
||||||
services.nginx.enable = true;
|
services.nginx.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
# External module from Git
|
# External module from Git
|
||||||
"remote-server" = builtins.fetchGit {
|
"remote-server" = builtins.fetchGit {
|
||||||
url = "https://github.com/org/server-config";
|
url = "https://git.factory.uga.edu/org/server-config";
|
||||||
rev = "abc123..."; # Pin to specific commit
|
rev = "abc123..."; # Pin to specific commit
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -66,9 +66,9 @@ server-config/
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Use ugaif namespace options
|
# Use athenix namespace options
|
||||||
ugaif.users.admin.enable = true;
|
athenix.users.admin.enable = true;
|
||||||
ugaif.sw.type = "headless";
|
athenix.sw.type = "headless";
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ Later modules can override earlier ones using standard NixOS module precedence.
|
|||||||
Create a new system module:
|
Create a new system module:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix flake init -t github:UGA-Innovation-Factory/nixos-systems#system
|
nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#system
|
||||||
```
|
```
|
||||||
|
|
||||||
See [templates/system/](../templates/system/) for the complete template.
|
See [templates/system/](../templates/system/) for the complete template.
|
||||||
@@ -108,10 +108,10 @@ External user modules provide home-manager configurations (dotfiles, packages, p
|
|||||||
### Usage in users.nix
|
### Usage in users.nix
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
ugaif.users = {
|
athenix.users = {
|
||||||
# External user module (dotfiles, home-manager, and user options)
|
# External user module (dotfiles, home-manager, and user options)
|
||||||
myuser = builtins.fetchGit {
|
myuser = builtins.fetchGit {
|
||||||
url = "https://github.com/username/dotfiles";
|
url = "https://git.factory.uga.edu/username/dotfiles";
|
||||||
rev = "abc123...";
|
rev = "abc123...";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ dotfiles/
|
|||||||
{ config, lib, pkgs, osConfig ? null, ... }:
|
{ config, lib, pkgs, osConfig ? null, ... }:
|
||||||
{
|
{
|
||||||
# ========== User Account Configuration ==========
|
# ========== User Account Configuration ==========
|
||||||
ugaif.users.myusername = {
|
athenix.users.myusername = {
|
||||||
description = "Your Full Name";
|
description = "Your Full Name";
|
||||||
shell = pkgs.zsh;
|
shell = pkgs.zsh;
|
||||||
hashedPassword = "!";
|
hashedPassword = "!";
|
||||||
@@ -157,7 +157,7 @@ dotfiles/
|
|||||||
vim
|
vim
|
||||||
git
|
git
|
||||||
htop
|
htop
|
||||||
] ++ lib.optional (osConfig.ugaif.sw.type or null == "desktop") firefox;
|
] ++ lib.optional (osConfig.athenix.sw.type or null == "desktop") firefox;
|
||||||
|
|
||||||
programs.git = {
|
programs.git = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -216,7 +216,7 @@ username = {
|
|||||||
useNvimPlugins = true; # Apply system nvim config (default: true)
|
useNvimPlugins = true; # Apply system nvim config (default: true)
|
||||||
|
|
||||||
# Enable on specific systems (see docs/INVENTORY.md)
|
# Enable on specific systems (see docs/INVENTORY.md)
|
||||||
enable = false; # Set in inventory.nix via ugaif.users.username.enable
|
enable = false; # Set in inventory.nix via athenix.users.username.enable
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -225,7 +225,7 @@ username = {
|
|||||||
Create a new user module:
|
Create a new user module:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix flake init -t github:UGA-Innovation-Factory/nixos-systems#user
|
nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#user
|
||||||
```
|
```
|
||||||
|
|
||||||
See [templates/user/](../templates/user/) for the complete template.
|
See [templates/user/](../templates/user/) for the complete template.
|
||||||
@@ -303,7 +303,7 @@ Use local directories during development:
|
|||||||
# Initialize in new directory
|
# Initialize in new directory
|
||||||
mkdir my-server-config
|
mkdir my-server-config
|
||||||
cd my-server-config
|
cd my-server-config
|
||||||
nix flake init -t github:UGA-Innovation-Factory/nixos-systems#system
|
nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#system
|
||||||
```
|
```
|
||||||
|
|
||||||
See [templates/system/README.md](../templates/system/README.md) for detailed usage.
|
See [templates/system/README.md](../templates/system/README.md) for detailed usage.
|
||||||
@@ -314,7 +314,7 @@ See [templates/system/README.md](../templates/system/README.md) for detailed usa
|
|||||||
# Initialize in new directory
|
# Initialize in new directory
|
||||||
mkdir my-dotfiles
|
mkdir my-dotfiles
|
||||||
cd my-dotfiles
|
cd my-dotfiles
|
||||||
nix flake init -t github:UGA-Innovation-Factory/nixos-systems#user
|
nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#user
|
||||||
```
|
```
|
||||||
|
|
||||||
See [templates/user/README.md](../templates/user/README.md) for detailed usage.
|
See [templates/user/README.md](../templates/user/README.md) for detailed usage.
|
||||||
@@ -337,7 +337,7 @@ External system modules are imported and merged into the NixOS configuration:
|
|||||||
import externalModulePath { inherit inputs; }
|
import externalModulePath { inherit inputs; }
|
||||||
```
|
```
|
||||||
|
|
||||||
They can use all standard NixOS options plus `ugaif.*` namespace options.
|
They can use all standard NixOS options plus `athenix.*` namespace options.
|
||||||
|
|
||||||
### User Module Integration
|
### User Module Integration
|
||||||
|
|
||||||
@@ -346,7 +346,7 @@ External user modules are loaded in two contexts:
|
|||||||
**User options (NixOS module context):**
|
**User options (NixOS module context):**
|
||||||
```nix
|
```nix
|
||||||
import (externalPath + "/user.nix") { inherit inputs; }
|
import (externalPath + "/user.nix") { inherit inputs; }
|
||||||
# Evaluated as NixOS module to extract ugaif.users.<username> options
|
# Evaluated as NixOS module to extract athenix.users.<username> options
|
||||||
```
|
```
|
||||||
|
|
||||||
**Home-manager configuration:**
|
**Home-manager configuration:**
|
||||||
@@ -369,13 +369,13 @@ You can mix external modules with local overrides:
|
|||||||
nix-lxc = {
|
nix-lxc = {
|
||||||
devices = {
|
devices = {
|
||||||
"server" = builtins.fetchGit {
|
"server" = builtins.fetchGit {
|
||||||
url = "https://github.com/org/base-config";
|
url = "https://git.factory.uga.edu/org/base-config";
|
||||||
rev = "abc123...";
|
rev = "abc123...";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
overrides = {
|
overrides = {
|
||||||
# Apply to all devices, including external ones
|
# Apply to all devices, including external ones
|
||||||
ugaif.users.admin.enable = true;
|
athenix.users.admin.enable = true;
|
||||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -389,7 +389,7 @@ nix-lxc = {
|
|||||||
{ config, lib, pkgs, osConfig ? null, ... }:
|
{ config, lib, pkgs, osConfig ? null, ... }:
|
||||||
{
|
{
|
||||||
# User account options
|
# User account options
|
||||||
ugaif.users.myusername = {
|
athenix.users.myusername = {
|
||||||
description = "My Name";
|
description = "My Name";
|
||||||
shell = pkgs.zsh;
|
shell = pkgs.zsh;
|
||||||
hashedPassword = "!";
|
hashedPassword = "!";
|
||||||
@@ -418,7 +418,7 @@ dotfiles/
|
|||||||
{ config, lib, pkgs, osConfig ? null, ... }:
|
{ config, lib, pkgs, osConfig ? null, ... }:
|
||||||
{
|
{
|
||||||
# User account configuration
|
# User account configuration
|
||||||
ugaif.users.myusername = {
|
athenix.users.myusername = {
|
||||||
description = "My Full Name";
|
description = "My Full Name";
|
||||||
shell = pkgs.zsh;
|
shell = pkgs.zsh;
|
||||||
extraGroups = [ "wheel" "networkmanager" ];
|
extraGroups = [ "wheel" "networkmanager" ];
|
||||||
@@ -433,7 +433,7 @@ dotfiles/
|
|||||||
ripgrep
|
ripgrep
|
||||||
fd
|
fd
|
||||||
bat
|
bat
|
||||||
] ++ lib.optional (osConfig.ugaif.sw.type or null == "desktop") firefox;
|
] ++ lib.optional (osConfig.athenix.sw.type or null == "desktop") firefox;
|
||||||
|
|
||||||
programs.git = {
|
programs.git = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ The `inventory.nix` file defines all hosts in the fleet using a flexible system.
|
|||||||
|
|
||||||
- **Numeric suffixes**: no dash (e.g., `nix-laptop1`, `nix-laptop2`)
|
- **Numeric suffixes**: no dash (e.g., `nix-laptop1`, `nix-laptop2`)
|
||||||
- **Non-numeric suffixes**: with dash (e.g., `nix-laptop-alpha`, `nix-laptop-beta`)
|
- **Non-numeric suffixes**: with dash (e.g., `nix-laptop-alpha`, `nix-laptop-beta`)
|
||||||
- **Custom hostnames**: Set `ugaif.host.useHostPrefix = false` to use suffix as full hostname
|
- **Custom hostnames**: Set `athenix.host.useHostPrefix = false` to use suffix as full hostname
|
||||||
|
|
||||||
## Adding Hosts
|
## Adding Hosts
|
||||||
|
|
||||||
@@ -37,8 +37,8 @@ nix-laptop = {
|
|||||||
devices = 5;
|
devices = 5;
|
||||||
overrides = {
|
overrides = {
|
||||||
# Applied to ALL nix-laptop hosts
|
# Applied to ALL nix-laptop hosts
|
||||||
ugaif.users.student.enable = true;
|
athenix.users.student.enable = true;
|
||||||
ugaif.sw.extraPackages = with pkgs; [ vim git ];
|
athenix.sw.extraPackages = with pkgs; [ vim git ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -48,9 +48,9 @@ nix-laptop = {
|
|||||||
```nix
|
```nix
|
||||||
nix-surface = {
|
nix-surface = {
|
||||||
devices = {
|
devices = {
|
||||||
"1".ugaif.sw.kioskUrl = "https://dashboard1.example.com";
|
"1".athenix.sw.kioskUrl = "https://dashboard1.example.com";
|
||||||
"2".ugaif.sw.kioskUrl = "https://dashboard2.example.com";
|
"2".athenix.sw.kioskUrl = "https://dashboard2.example.com";
|
||||||
"3".ugaif.sw.kioskUrl = "https://dashboard3.example.com";
|
"3".athenix.sw.kioskUrl = "https://dashboard3.example.com";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -62,12 +62,12 @@ nix-surface = {
|
|||||||
defaultCount = 2; # Creates nix-surface1, nix-surface2
|
defaultCount = 2; # Creates nix-surface1, nix-surface2
|
||||||
devices = {
|
devices = {
|
||||||
"special" = { # Creates nix-surface-special
|
"special" = { # Creates nix-surface-special
|
||||||
ugaif.sw.kioskUrl = "https://special-dashboard.example.com";
|
athenix.sw.kioskUrl = "https://special-dashboard.example.com";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
overrides = {
|
overrides = {
|
||||||
# Applied to all devices (including "special")
|
# Applied to all devices (including "special")
|
||||||
ugaif.sw.kioskUrl = "https://default-dashboard.example.com";
|
athenix.sw.kioskUrl = "https://default-dashboard.example.com";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -76,15 +76,15 @@ nix-surface = {
|
|||||||
|
|
||||||
### Direct Configuration (Recommended)
|
### Direct Configuration (Recommended)
|
||||||
|
|
||||||
Use any NixOS or `ugaif.*` option:
|
Use any NixOS or `athenix.*` option:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
"1" = {
|
"1" = {
|
||||||
# UGAIF options
|
# Athenix options
|
||||||
ugaif.users.myuser.enable = true;
|
athenix.users.myuser.enable = true;
|
||||||
ugaif.host.filesystem.swapSize = "64G";
|
athenix.host.filesystem.swapSize = "64G";
|
||||||
ugaif.sw.extraPackages = with pkgs; [ docker ];
|
athenix.sw.extraPackages = with pkgs; [ docker ];
|
||||||
ugaif.sw.kioskUrl = "https://example.com";
|
athenix.sw.kioskUrl = "https://example.com";
|
||||||
|
|
||||||
# Standard NixOS options
|
# Standard NixOS options
|
||||||
networking.firewall.enable = false;
|
networking.firewall.enable = false;
|
||||||
@@ -93,14 +93,14 @@ Use any NixOS or `ugaif.*` option:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Convenience: `ugaif.forUser`
|
### Convenience: `athenix.forUser`
|
||||||
|
|
||||||
Quick setup for single-user systems (especially WSL):
|
Quick setup for single-user systems (especially WSL):
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
nix-wsl = {
|
nix-wsl = {
|
||||||
devices = {
|
devices = {
|
||||||
"alice".ugaif.forUser = "alice-username";
|
"alice".athenix.forUser = "alice-username";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -115,7 +115,7 @@ For complex configurations, use external modules (see [EXTERNAL_MODULES.md](../E
|
|||||||
nix-lxc = {
|
nix-lxc = {
|
||||||
devices = {
|
devices = {
|
||||||
"special-server" = builtins.fetchGit {
|
"special-server" = builtins.fetchGit {
|
||||||
url = "https://github.com/org/server-config";
|
url = "https://git.factory.uga.edu/org/server-config";
|
||||||
rev = "abc123...";
|
rev = "abc123...";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -130,7 +130,7 @@ nix-lxc = {
|
|||||||
nix-laptop = {
|
nix-laptop = {
|
||||||
devices = 10; # Creates nix-laptop1 through nix-laptop10
|
devices = 10; # Creates nix-laptop1 through nix-laptop10
|
||||||
overrides = {
|
overrides = {
|
||||||
ugaif.users.student.enable = true;
|
athenix.users.student.enable = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -142,13 +142,13 @@ nix-surface = {
|
|||||||
defaultCount = 5; # nix-surface1 through nix-surface5 (default config)
|
defaultCount = 5; # nix-surface1 through nix-surface5 (default config)
|
||||||
devices = {
|
devices = {
|
||||||
"admin" = { # nix-surface-admin (special config)
|
"admin" = { # nix-surface-admin (special config)
|
||||||
ugaif.sw.type = "desktop"; # Full desktop instead of kiosk
|
athenix.sw.type = "desktop"; # Full desktop instead of kiosk
|
||||||
ugaif.users.admin.enable = true;
|
athenix.users.admin.enable = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
overrides = {
|
overrides = {
|
||||||
ugaif.sw.type = "tablet-kiosk";
|
athenix.sw.type = "tablet-kiosk";
|
||||||
ugaif.sw.kioskUrl = "https://dashboard.factory.uga.edu";
|
athenix.sw.kioskUrl = "https://dashboard.factory.uga.edu";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -159,15 +159,15 @@ nix-surface = {
|
|||||||
nix-lxc = {
|
nix-lxc = {
|
||||||
devices = {
|
devices = {
|
||||||
"nix-builder" = {
|
"nix-builder" = {
|
||||||
ugaif.sw.type = "headless";
|
athenix.sw.type = "headless";
|
||||||
};
|
};
|
||||||
"webserver" = {
|
"webserver" = {
|
||||||
ugaif.sw.type = "headless";
|
athenix.sw.type = "headless";
|
||||||
services.nginx.enable = true;
|
services.nginx.enable = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
overrides = {
|
overrides = {
|
||||||
ugaif.host.useHostPrefix = false; # Use exact device key as hostname
|
athenix.host.useHostPrefix = false; # Use exact device key as hostname
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -177,8 +177,8 @@ nix-lxc = {
|
|||||||
```nix
|
```nix
|
||||||
nix-wsl = {
|
nix-wsl = {
|
||||||
devices = {
|
devices = {
|
||||||
"alice".ugaif.forUser = "alice-uga";
|
"alice".athenix.forUser = "alice-uga";
|
||||||
"bob".ugaif.forUser = "bob-uga";
|
"bob".athenix.forUser = "bob-uga";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -187,4 +187,4 @@ nix-wsl = {
|
|||||||
|
|
||||||
- [USER_CONFIGURATION.md](USER_CONFIGURATION.md) - User account management
|
- [USER_CONFIGURATION.md](USER_CONFIGURATION.md) - User account management
|
||||||
- [EXTERNAL_MODULES.md](EXTERNAL_MODULES.md) - External configuration modules
|
- [EXTERNAL_MODULES.md](EXTERNAL_MODULES.md) - External configuration modules
|
||||||
- [Configuration Namespace Reference](NAMESPACE.md) - All `ugaif.*` options
|
- [Configuration Namespace Reference](NAMESPACE.md) - All `athenix.*` options
|
||||||
|
|||||||
@@ -1,36 +1,36 @@
|
|||||||
# Configuration Namespace Reference
|
# Configuration Namespace Reference
|
||||||
|
|
||||||
All UGA Innovation Factory-specific options are under the `ugaif` namespace to avoid conflicts with standard NixOS options.
|
All UGA Innovation Factory-specific options are under the `athenix` namespace to avoid conflicts with standard NixOS options.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Host Configuration (`ugaif.host`)](#host-configuration-ugaifhost)
|
- [Host Configuration (`athenix.host`)](#host-configuration-athenixhost)
|
||||||
- [Software Configuration (`ugaif.sw`)](#software-configuration-ugaifsw)
|
- [Software Configuration (`athenix.sw`)](#software-configuration-athenixsw)
|
||||||
- [User Management (`ugaif.users`)](#user-management-ugaifusers)
|
- [User Management (`athenix.users`)](#user-management-athenixusers)
|
||||||
- [System Configuration (`ugaif.system`)](#system-configuration-ugaifsystem)
|
- [System Configuration (`athenix.system`)](#system-configuration-athenixsystem)
|
||||||
- [Convenience Options](#convenience-options)
|
- [Convenience Options](#convenience-options)
|
||||||
|
|
||||||
## Host Configuration (`ugaif.host`)
|
## Host Configuration (`athenix.host`)
|
||||||
|
|
||||||
Hardware and host-specific settings.
|
Hardware and host-specific settings.
|
||||||
|
|
||||||
### `ugaif.host.filesystem`
|
### `athenix.host.filesystem`
|
||||||
|
|
||||||
Disk and storage configuration.
|
Disk and storage configuration.
|
||||||
|
|
||||||
**Options:**
|
**Options:**
|
||||||
- `ugaif.host.filesystem.device` - Boot disk device (default: `/dev/sda`)
|
- `athenix.host.filesystem.device` - Boot disk device (default: `/dev/sda`)
|
||||||
- `ugaif.host.filesystem.swapSize` - Swap file size (default: `"32G"`)
|
- `athenix.host.filesystem.swapSize` - Swap file size (default: `"32G"`)
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.host.filesystem = {
|
athenix.host.filesystem = {
|
||||||
device = "/dev/nvme0n1";
|
device = "/dev/nvme0n1";
|
||||||
swapSize = "64G";
|
swapSize = "64G";
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### `ugaif.host.buildMethods`
|
### `athenix.host.buildMethods`
|
||||||
|
|
||||||
List of supported build artifact types for this host.
|
List of supported build artifact types for this host.
|
||||||
|
|
||||||
@@ -42,10 +42,10 @@ List of supported build artifact types for this host.
|
|||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.host.buildMethods = [ "lxc" "proxmox" ];
|
athenix.host.buildMethods = [ "lxc" "proxmox" ];
|
||||||
```
|
```
|
||||||
|
|
||||||
### `ugaif.host.useHostPrefix`
|
### `athenix.host.useHostPrefix`
|
||||||
|
|
||||||
Whether to prepend the host type prefix to the hostname (used in inventory generation).
|
Whether to prepend the host type prefix to the hostname (used in inventory generation).
|
||||||
|
|
||||||
@@ -55,26 +55,26 @@ Whether to prepend the host type prefix to the hostname (used in inventory gener
|
|||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.host.useHostPrefix = false; # "builder" instead of "nix-lxc-builder"
|
athenix.host.useHostPrefix = false; # "builder" instead of "nix-lxc-builder"
|
||||||
```
|
```
|
||||||
|
|
||||||
### `ugaif.host.wsl`
|
### `athenix.host.wsl`
|
||||||
|
|
||||||
WSL-specific configuration options.
|
WSL-specific configuration options.
|
||||||
|
|
||||||
**Options:**
|
**Options:**
|
||||||
- `ugaif.host.wsl.user` - Default WSL user for this instance
|
- `athenix.host.wsl.user` - Default WSL user for this instance
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.host.wsl.user = "myusername";
|
athenix.host.wsl.user = "myusername";
|
||||||
```
|
```
|
||||||
|
|
||||||
## Software Configuration (`ugaif.sw`)
|
## Software Configuration (`athenix.sw`)
|
||||||
|
|
||||||
System software and application configuration.
|
System software and application configuration.
|
||||||
|
|
||||||
### `ugaif.sw.enable`
|
### `athenix.sw.enable`
|
||||||
|
|
||||||
Enable the software configuration module.
|
Enable the software configuration module.
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ Enable the software configuration module.
|
|||||||
|
|
||||||
**Default:** `true`
|
**Default:** `true`
|
||||||
|
|
||||||
### `ugaif.sw.type`
|
### `athenix.sw.type`
|
||||||
|
|
||||||
System type that determines the software profile.
|
System type that determines the software profile.
|
||||||
|
|
||||||
@@ -98,10 +98,10 @@ System type that determines the software profile.
|
|||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.sw.type = "headless";
|
athenix.sw.type = "headless";
|
||||||
```
|
```
|
||||||
|
|
||||||
### `ugaif.sw.kioskUrl`
|
### `athenix.sw.kioskUrl`
|
||||||
|
|
||||||
URL to display in kiosk mode browsers (for `tablet-kiosk` and `stateless-kiosk` types).
|
URL to display in kiosk mode browsers (for `tablet-kiosk` and `stateless-kiosk` types).
|
||||||
|
|
||||||
@@ -111,38 +111,38 @@ URL to display in kiosk mode browsers (for `tablet-kiosk` and `stateless-kiosk`
|
|||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.sw.kioskUrl = "https://dashboard.example.com";
|
athenix.sw.kioskUrl = "https://dashboard.example.com";
|
||||||
```
|
```
|
||||||
|
|
||||||
### `ugaif.sw.python`
|
### `athenix.sw.python`
|
||||||
|
|
||||||
Python development tools configuration.
|
Python development tools configuration.
|
||||||
|
|
||||||
**Options:**
|
**Options:**
|
||||||
- `ugaif.sw.python.enable` - Enable Python tools (pixi, uv) (default: `true`)
|
- `athenix.sw.python.enable` - Enable Python tools (pixi, uv) (default: `true`)
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.sw.python.enable = true;
|
athenix.sw.python.enable = true;
|
||||||
```
|
```
|
||||||
|
|
||||||
### `ugaif.sw.remoteBuild`
|
### `athenix.sw.remoteBuild`
|
||||||
|
|
||||||
Remote build server configuration for offloading builds.
|
Remote build server configuration for offloading builds.
|
||||||
|
|
||||||
**Options:**
|
**Options:**
|
||||||
- `ugaif.sw.remoteBuild.enable` - Use remote builders (default: enabled on tablets)
|
- `athenix.sw.remoteBuild.enable` - Use remote builders (default: enabled on tablets)
|
||||||
- `ugaif.sw.remoteBuild.hosts` - List of build server hostnames
|
- `athenix.sw.remoteBuild.hosts` - List of build server hostnames
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.sw.remoteBuild = {
|
athenix.sw.remoteBuild = {
|
||||||
enable = true;
|
enable = true;
|
||||||
hosts = [ "nix-builder" "nix-builder2" ];
|
hosts = [ "nix-builder" "nix-builder2" ];
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### `ugaif.sw.extraPackages`
|
### `athenix.sw.extraPackages`
|
||||||
|
|
||||||
Additional system packages to install beyond the type defaults.
|
Additional system packages to install beyond the type defaults.
|
||||||
|
|
||||||
@@ -152,14 +152,14 @@ Additional system packages to install beyond the type defaults.
|
|||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.sw.extraPackages = with pkgs; [
|
athenix.sw.extraPackages = with pkgs; [
|
||||||
vim
|
vim
|
||||||
htop
|
htop
|
||||||
docker
|
docker
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
|
|
||||||
### `ugaif.sw.excludePackages`
|
### `athenix.sw.excludePackages`
|
||||||
|
|
||||||
Packages to exclude from the default list for this system type.
|
Packages to exclude from the default list for this system type.
|
||||||
|
|
||||||
@@ -169,16 +169,16 @@ Packages to exclude from the default list for this system type.
|
|||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.sw.excludePackages = with pkgs; [
|
athenix.sw.excludePackages = with pkgs; [
|
||||||
firefox # Remove Firefox from default desktop packages
|
firefox # Remove Firefox from default desktop packages
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
|
|
||||||
## User Management (`ugaif.users`)
|
## User Management (`athenix.users`)
|
||||||
|
|
||||||
User account configuration and management.
|
User account configuration and management.
|
||||||
|
|
||||||
### `ugaif.users.<username>.enable`
|
### `athenix.users.<username>.enable`
|
||||||
|
|
||||||
Enable a specific user account on this system.
|
Enable a specific user account on this system.
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ Enable a specific user account on this system.
|
|||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.users = {
|
athenix.users = {
|
||||||
myuser.enable = true;
|
myuser.enable = true;
|
||||||
student.enable = true;
|
student.enable = true;
|
||||||
};
|
};
|
||||||
@@ -200,7 +200,7 @@ Each user in `users.nix` can be configured with:
|
|||||||
|
|
||||||
```nix
|
```nix
|
||||||
# Option 1: Define inline in users.nix
|
# Option 1: Define inline in users.nix
|
||||||
ugaif.users.myuser = {
|
athenix.users.myuser = {
|
||||||
description = "Full Name";
|
description = "Full Name";
|
||||||
isNormalUser = true; # Default: true
|
isNormalUser = true; # Default: true
|
||||||
extraGroups = [ "wheel" "docker" ]; # Additional groups
|
extraGroups = [ "wheel" "docker" ]; # Additional groups
|
||||||
@@ -214,30 +214,30 @@ ugaif.users.myuser = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
# Option 2: Use external configuration (recommended)
|
# Option 2: Use external configuration (recommended)
|
||||||
# The external user.nix can set ugaif.users.myuser options directly
|
# The external user.nix can set athenix.users.myuser options directly
|
||||||
ugaif.users.anotheruser.external = builtins.fetchGit {
|
athenix.users.anotheruser.external = builtins.fetchGit {
|
||||||
url = "https://github.com/username/dotfiles";
|
url = "https://git.factory.uga.edu/username/dotfiles";
|
||||||
rev = "abc123...";
|
rev = "abc123...";
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## System Configuration (`ugaif.system`)
|
## System Configuration (`athenix.system`)
|
||||||
|
|
||||||
System-wide settings and services.
|
System-wide settings and services.
|
||||||
|
|
||||||
### `ugaif.system.gc`
|
### `athenix.system.gc`
|
||||||
|
|
||||||
Automatic garbage collection configuration.
|
Automatic garbage collection configuration.
|
||||||
|
|
||||||
**Options:**
|
**Options:**
|
||||||
- `ugaif.system.gc.enable` - Enable automatic garbage collection (default: `true`)
|
- `athenix.system.gc.enable` - Enable automatic garbage collection (default: `true`)
|
||||||
- `ugaif.system.gc.frequency` - How often to run (default: `"weekly"`)
|
- `athenix.system.gc.frequency` - How often to run (default: `"weekly"`)
|
||||||
- `ugaif.system.gc.retentionDays` - Days to keep old generations (default: `30`)
|
- `athenix.system.gc.retentionDays` - Days to keep old generations (default: `30`)
|
||||||
- `ugaif.system.gc.optimise` - Optimize Nix store automatically (default: `true`)
|
- `athenix.system.gc.optimise` - Optimize Nix store automatically (default: `true`)
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.system.gc = {
|
athenix.system.gc = {
|
||||||
enable = true;
|
enable = true;
|
||||||
frequency = "daily";
|
frequency = "daily";
|
||||||
retentionDays = 14;
|
retentionDays = 14;
|
||||||
@@ -247,7 +247,7 @@ ugaif.system.gc = {
|
|||||||
|
|
||||||
## Convenience Options
|
## Convenience Options
|
||||||
|
|
||||||
### `ugaif.forUser`
|
### `athenix.forUser`
|
||||||
|
|
||||||
Quick setup option that enables a user account in one line.
|
Quick setup option that enables a user account in one line.
|
||||||
|
|
||||||
@@ -257,14 +257,14 @@ Quick setup option that enables a user account in one line.
|
|||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```nix
|
```nix
|
||||||
ugaif.forUser = "myusername"; # Equivalent to ugaif.users.myusername.enable = true
|
athenix.forUser = "myusername"; # Equivalent to athenix.users.myusername.enable = true
|
||||||
```
|
```
|
||||||
|
|
||||||
**Usage in inventory.nix:**
|
**Usage in inventory.nix:**
|
||||||
```nix
|
```nix
|
||||||
nix-wsl = {
|
nix-wsl = {
|
||||||
devices = {
|
devices = {
|
||||||
"alice".ugaif.forUser = "alice-uga";
|
"alice".athenix.forUser = "alice-uga";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Users are defined in `users.nix` but are **not enabled by default** on all syste
|
|||||||
### 1. Define User in users.nix
|
### 1. Define User in users.nix
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
ugaif.users = {
|
athenix.users = {
|
||||||
# Option 1: Inline definition
|
# Option 1: Inline definition
|
||||||
myuser = {
|
myuser = {
|
||||||
description = "My Full Name";
|
description = "My Full Name";
|
||||||
@@ -40,7 +40,7 @@ ugaif.users = {
|
|||||||
|
|
||||||
# Option 2: External configuration (recommended for personalization)
|
# Option 2: External configuration (recommended for personalization)
|
||||||
myuser.external = builtins.fetchGit {
|
myuser.external = builtins.fetchGit {
|
||||||
url = "https://github.com/username/dotfiles";
|
url = "https://git.factory.uga.edu/username/dotfiles";
|
||||||
rev = "abc123..."; # Pin to specific commit
|
rev = "abc123..."; # Pin to specific commit
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -53,20 +53,20 @@ In `inventory.nix`:
|
|||||||
```nix
|
```nix
|
||||||
nix-laptop = {
|
nix-laptop = {
|
||||||
devices = 2;
|
devices = 2;
|
||||||
overrides.ugaif.users.myuser.enable = true; # Enables on all nix-laptop hosts
|
overrides.athenix.users.myuser.enable = true; # Enables on all nix-laptop hosts
|
||||||
};
|
};
|
||||||
|
|
||||||
# Or for specific devices
|
# Or for specific devices
|
||||||
nix-desktop = {
|
nix-desktop = {
|
||||||
devices = {
|
devices = {
|
||||||
"1".ugaif.users.myuser.enable = true;
|
"1".athenix.users.myuser.enable = true;
|
||||||
"2".ugaif.users.otheruser.enable = true;
|
"2".athenix.users.otheruser.enable = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Or use convenience option
|
# Or use convenience option
|
||||||
nix-wsl = {
|
nix-wsl = {
|
||||||
devices."alice".ugaif.forUser = "alice-user"; # Automatically enables user
|
devices."alice".athenix.forUser = "alice-user"; # Automatically enables user
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ myuser = {
|
|||||||
|
|
||||||
# Point to external configuration repository
|
# Point to external configuration repository
|
||||||
external = builtins.fetchGit {
|
external = builtins.fetchGit {
|
||||||
url = "https://github.com/username/dotfiles";
|
url = "https://git.factory.uga.edu/username/dotfiles";
|
||||||
rev = "abc123..."; # Pin to specific commit
|
rev = "abc123..."; # Pin to specific commit
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -153,7 +153,7 @@ dotfiles/
|
|||||||
{
|
{
|
||||||
# ========== User Account Configuration ==========
|
# ========== User Account Configuration ==========
|
||||||
# These options define the user account itself
|
# These options define the user account itself
|
||||||
ugaif.users.myuser = {
|
athenix.users.myuser = {
|
||||||
description = "My Full Name";
|
description = "My Full Name";
|
||||||
extraGroups = [ "wheel" "docker" ];
|
extraGroups = [ "wheel" "docker" ];
|
||||||
shell = pkgs.zsh;
|
shell = pkgs.zsh;
|
||||||
@@ -171,7 +171,7 @@ dotfiles/
|
|||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
vim
|
vim
|
||||||
ripgrep
|
ripgrep
|
||||||
] ++ lib.optional (osConfig.ugaif.sw.type or null == "desktop") firefox;
|
] ++ lib.optional (osConfig.athenix.sw.type or null == "desktop") firefox;
|
||||||
|
|
||||||
programs.git = {
|
programs.git = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -210,7 +210,7 @@ dotfiles/
|
|||||||
|
|
||||||
The `user.nix` module serves a dual purpose and is imported in **two contexts**:
|
The `user.nix` module serves a dual purpose and is imported in **two contexts**:
|
||||||
|
|
||||||
1. **NixOS Module Context (User Options)**: The module is imported as a NixOS module where `ugaif.users.<username>` options are read to define the user account (description, shell, groups, SSH keys, etc.). These options override any defaults set in `users.nix`.
|
1. **NixOS Module Context (User Options)**: The module is imported as a NixOS module where `athenix.users.<username>` options are read to define the user account (description, shell, groups, SSH keys, etc.). These options override any defaults set in `users.nix`.
|
||||||
|
|
||||||
2. **Home-Manager Context**: The same module is imported into home-manager where `home.*`, `programs.*`, and `services.*` options configure the user's environment, packages, and dotfiles.
|
2. **Home-Manager Context**: The same module is imported into home-manager where `home.*`, `programs.*`, and `services.*` options configure the user's environment, packages, and dotfiles.
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ external = /home/username/dev/dotfiles;
|
|||||||
### Create User Template
|
### Create User Template
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix flake init -t github:UGA-Innovation-Factory/nixos-systems#user
|
nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#user
|
||||||
```
|
```
|
||||||
|
|
||||||
See [templates/user/README.md](../templates/user/README.md) for complete template.
|
See [templates/user/README.md](../templates/user/README.md) for complete template.
|
||||||
@@ -251,7 +251,7 @@ Users must be explicitly enabled on each host in `inventory.nix`.
|
|||||||
nix-laptop = {
|
nix-laptop = {
|
||||||
devices = 5;
|
devices = 5;
|
||||||
overrides = {
|
overrides = {
|
||||||
ugaif.users.student.enable = true; # All 5 laptops get this user
|
athenix.users.student.enable = true; # All 5 laptops get this user
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -261,30 +261,30 @@ nix-laptop = {
|
|||||||
```nix
|
```nix
|
||||||
nix-desktop = {
|
nix-desktop = {
|
||||||
devices = {
|
devices = {
|
||||||
"1".ugaif.users.alice.enable = true;
|
"1".athenix.users.alice.enable = true;
|
||||||
"2".ugaif.users.bob.enable = true;
|
"2".athenix.users.bob.enable = true;
|
||||||
"3" = {
|
"3" = {
|
||||||
ugaif.users.alice.enable = true;
|
athenix.users.alice.enable = true;
|
||||||
ugaif.users.bob.enable = true;
|
athenix.users.bob.enable = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Method 3: Convenience Option (ugaif.forUser)
|
### Method 3: Convenience Option (athenix.forUser)
|
||||||
|
|
||||||
Quick setup for single-user systems:
|
Quick setup for single-user systems:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
nix-wsl = {
|
nix-wsl = {
|
||||||
devices = {
|
devices = {
|
||||||
"alice".ugaif.forUser = "alice-user"; # Automatically enables alice-user
|
"alice".athenix.forUser = "alice-user"; # Automatically enables alice-user
|
||||||
"bob".ugaif.forUser = "bob-user";
|
"bob".athenix.forUser = "bob-user";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
This is equivalent to `ugaif.users.alice-user.enable = true`.
|
This is equivalent to `athenix.users.alice-user.enable = true`.
|
||||||
|
|
||||||
## Password Management
|
## Password Management
|
||||||
|
|
||||||
@@ -390,7 +390,7 @@ developer = {
|
|||||||
shell = pkgs.zsh;
|
shell = pkgs.zsh;
|
||||||
hashedPassword = "$6$...";
|
hashedPassword = "$6$...";
|
||||||
external = builtins.fetchGit {
|
external = builtins.fetchGit {
|
||||||
url = "https://github.com/username/dotfiles";
|
url = "https://git.factory.uga.edu/username/dotfiles";
|
||||||
rev = "abc123def456...";
|
rev = "abc123def456...";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -405,7 +405,7 @@ wsl-user = {
|
|||||||
shell = pkgs.zsh;
|
shell = pkgs.zsh;
|
||||||
hashedPassword = "$6$...";
|
hashedPassword = "$6$...";
|
||||||
external = builtins.fetchGit {
|
external = builtins.fetchGit {
|
||||||
url = "https://github.com/username/dotfiles";
|
url = "https://git.factory.uga.edu/username/dotfiles";
|
||||||
rev = "abc123...";
|
rev = "abc123...";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -414,7 +414,7 @@ wsl-user = {
|
|||||||
Enable in inventory.nix:
|
Enable in inventory.nix:
|
||||||
```nix
|
```nix
|
||||||
nix-wsl = {
|
nix-wsl = {
|
||||||
devices."my-wsl".ugaif.forUser = "wsl-user";
|
devices."my-wsl".athenix.forUser = "wsl-user";
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -464,7 +464,7 @@ Disable if you want to configure Neovim yourself.
|
|||||||
|
|
||||||
**Check if enabled on host:**
|
**Check if enabled on host:**
|
||||||
```bash
|
```bash
|
||||||
nix eval .#nixosConfigurations.nix-laptop1.config.ugaif.users.myuser.enable
|
nix eval .#nixosConfigurations.nix-laptop1.config.athenix.users.myuser.enable
|
||||||
```
|
```
|
||||||
|
|
||||||
**Check if user exists:**
|
**Check if user exists:**
|
||||||
@@ -489,7 +489,7 @@ nix eval .#nixosConfigurations.nix-laptop1.config.users.users.myuser.openssh.aut
|
|||||||
|
|
||||||
**Check repository access:**
|
**Check repository access:**
|
||||||
```bash
|
```bash
|
||||||
git ls-remote https://github.com/username/dotfiles
|
git ls-remote https://git.factory.uga.edu/username/dotfiles
|
||||||
```
|
```
|
||||||
|
|
||||||
**Verify structure:**
|
**Verify structure:**
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# Flake Entry Point
|
# Flake Entry Point
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# This file defines the inputs (dependencies) and outputs (configurations)
|
# This file defines the inputs (dependencies) and outputs (configurations)
|
||||||
# for the NixOS systems. It ties together the hardware, software, and user
|
# for Athenix. It ties together the hardware, software, and user
|
||||||
# configurations into deployable systems.
|
# configurations into deployable systems.
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
|
|||||||
@@ -12,14 +12,14 @@
|
|||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
options.ugaif = {
|
options.athenix = {
|
||||||
forUser = lib.mkOption {
|
forUser = lib.mkOption {
|
||||||
type = lib.types.nullOr lib.types.str;
|
type = lib.types.nullOr lib.types.str;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
Convenience option to configure a host for a specific user.
|
Convenience option to configure a host for a specific user.
|
||||||
Automatically enables the user (sets ugaif.users.username.enable = true).
|
Automatically enables the user (sets athenix.users.username.enable = true).
|
||||||
Value should be a username from ugaif.users.accounts.
|
Value should be a username from athenix.users.accounts.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,8 +80,8 @@
|
|||||||
|
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
# Enable forUser if specified
|
# Enable forUser if specified
|
||||||
(lib.mkIf (config.ugaif.forUser != null) {
|
(lib.mkIf (config.athenix.forUser != null) {
|
||||||
ugaif.users.${config.ugaif.forUser}.enable = true;
|
athenix.users.${config.athenix.forUser}.enable = true;
|
||||||
})
|
})
|
||||||
|
|
||||||
# Main configuration
|
# Main configuration
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
disko.devices = {
|
disko.devices = {
|
||||||
disk.main = {
|
disk.main = {
|
||||||
type = "disk";
|
type = "disk";
|
||||||
device = config.ugaif.host.filesystem.device;
|
device = config.athenix.host.filesystem.device;
|
||||||
content = {
|
content = {
|
||||||
type = "gpt";
|
type = "gpt";
|
||||||
partitions = {
|
partitions = {
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
swap = {
|
swap = {
|
||||||
name = "swap";
|
name = "swap";
|
||||||
label = "swap";
|
label = "swap";
|
||||||
size = config.ugaif.host.filesystem.swapSize;
|
size = config.athenix.host.filesystem.swapSize;
|
||||||
content = {
|
content = {
|
||||||
type = "swap";
|
type = "swap";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -36,12 +36,12 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
# Automatic Garbage Collection
|
# Automatic Garbage Collection
|
||||||
nix.gc = lib.mkIf config.ugaif.system.gc.enable {
|
nix.gc = lib.mkIf config.athenix.system.gc.enable {
|
||||||
automatic = true;
|
automatic = true;
|
||||||
dates = config.ugaif.system.gc.frequency;
|
dates = config.athenix.system.gc.frequency;
|
||||||
options = "--delete-older-than ${toString config.ugaif.system.gc.retentionDays}d";
|
options = "--delete-older-than ${toString config.athenix.system.gc.retentionDays}d";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Optimize storage
|
# Optimize storage
|
||||||
nix.optimise.automatic = config.ugaif.system.gc.optimise;
|
nix.optimise.automatic = config.athenix.system.gc.optimise;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
# "my-hostname" = {
|
# "my-hostname" = {
|
||||||
# type = "nix-desktop"; # Host type module to use
|
# type = "nix-desktop"; # Host type module to use
|
||||||
# system = "x86_64-linux"; # Optional
|
# system = "x86_64-linux"; # Optional
|
||||||
# # ... any ugaif.* options or device-specific config
|
# # ... any athenix.* options or device-specific config
|
||||||
# };
|
# };
|
||||||
#
|
#
|
||||||
# "lab-prefix" = {
|
# "lab-prefix" = {
|
||||||
@@ -44,7 +44,7 @@ let
|
|||||||
# Load users.nix to find external user modules
|
# Load users.nix to find external user modules
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
usersData = import ../users.nix { inherit pkgs; };
|
usersData = import ../users.nix { inherit pkgs; };
|
||||||
accounts = usersData.ugaif.users or { };
|
accounts = usersData.athenix.users or { };
|
||||||
|
|
||||||
# Build a map of user names to their nixos module paths (if they exist)
|
# Build a map of user names to their nixos module paths (if they exist)
|
||||||
# We'll use this to conditionally import modules based on user.enable
|
# We'll use this to conditionally import modules based on user.enable
|
||||||
@@ -90,7 +90,7 @@ let
|
|||||||
if lib.isFunction importedModuleFunc then importedModuleFunc args else importedModuleFunc;
|
if lib.isFunction importedModuleFunc then importedModuleFunc args else importedModuleFunc;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = lib.mkIf (config.ugaif.users.${name}.enable or false) importedModule;
|
config = lib.mkIf (config.athenix.users.${name}.enable or false) importedModule;
|
||||||
}
|
}
|
||||||
) userNixosModulePaths;
|
) userNixosModulePaths;
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ let
|
|||||||
externalPathModule =
|
externalPathModule =
|
||||||
if externalModulePath != null then import externalModulePath { inherit inputs; } else { };
|
if externalModulePath != null then import externalModulePath { inherit inputs; } else { };
|
||||||
|
|
||||||
# Config override module - translate special keys to ugaif options
|
# Config override module - translate special keys to athenix options
|
||||||
overrideModule =
|
overrideModule =
|
||||||
{ ... }:
|
{ ... }:
|
||||||
let
|
let
|
||||||
@@ -119,7 +119,7 @@ let
|
|||||||
"buildMethods"
|
"buildMethods"
|
||||||
];
|
];
|
||||||
specialConfig = lib.optionalAttrs (configOverrides ? buildMethods) {
|
specialConfig = lib.optionalAttrs (configOverrides ? buildMethods) {
|
||||||
ugaif.host.buildMethods = configOverrides.buildMethods;
|
athenix.host.buildMethods = configOverrides.buildMethods;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@@ -220,7 +220,7 @@ let
|
|||||||
lib.recursiveUpdate (lib.recursiveUpdate baseConfig overrides) deviceConfig;
|
lib.recursiveUpdate (lib.recursiveUpdate baseConfig overrides) deviceConfig;
|
||||||
|
|
||||||
# Check useHostPrefix from the merged config
|
# Check useHostPrefix from the merged config
|
||||||
usePrefix = mergedConfig.ugaif.host.useHostPrefix or true;
|
usePrefix = mergedConfig.athenix.host.useHostPrefix or true;
|
||||||
hostName = mkHostName prefix deviceKey usePrefix;
|
hostName = mkHostName prefix deviceKey usePrefix;
|
||||||
|
|
||||||
# If external module, also add a default.nix path for import
|
# If external module, also add a default.nix path for import
|
||||||
|
|||||||
@@ -38,15 +38,15 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
# ========== Filesystem Configuration ==========
|
# ========== Filesystem Configuration ==========
|
||||||
ugaif.host.filesystem.swapSize = lib.mkDefault "16G";
|
athenix.host.filesystem.swapSize = lib.mkDefault "16G";
|
||||||
ugaif.host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
|
athenix.host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
|
||||||
ugaif.host.buildMethods = lib.mkDefault [ "installer-iso" ];
|
athenix.host.buildMethods = lib.mkDefault [ "installer-iso" ];
|
||||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
|
||||||
# ========== Hardware Configuration ==========
|
# ========== Hardware Configuration ==========
|
||||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
|
||||||
# ========== Software Profile ==========
|
# ========== Software Profile ==========
|
||||||
ugaif.sw.enable = lib.mkDefault true;
|
athenix.sw.enable = lib.mkDefault true;
|
||||||
ugaif.sw.type = lib.mkDefault "desktop";
|
athenix.sw.type = lib.mkDefault "desktop";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,9 @@
|
|||||||
|
|
||||||
# ========== Ephemeral Configuration ==========
|
# ========== Ephemeral Configuration ==========
|
||||||
# No persistent storage - everything runs from RAM
|
# No persistent storage - everything runs from RAM
|
||||||
ugaif.host.filesystem.swapSize = lib.mkForce "0G";
|
athenix.host.filesystem.swapSize = lib.mkForce "0G";
|
||||||
ugaif.host.filesystem.device = lib.mkForce "/dev/null"; # Dummy device
|
athenix.host.filesystem.device = lib.mkForce "/dev/null"; # Dummy device
|
||||||
ugaif.host.buildMethods = lib.mkDefault [
|
athenix.host.buildMethods = lib.mkDefault [
|
||||||
"iso" # Live ISO image
|
"iso" # Live ISO image
|
||||||
"ipxe" # Network boot
|
"ipxe" # Network boot
|
||||||
];
|
];
|
||||||
@@ -63,6 +63,6 @@
|
|||||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
|
||||||
ugaif.sw.enable = lib.mkDefault true;
|
athenix.sw.enable = lib.mkDefault true;
|
||||||
ugaif.sw.type = lib.mkDefault "stateless-kiosk";
|
athenix.sw.type = lib.mkDefault "stateless-kiosk";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,9 +46,9 @@
|
|||||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
|
||||||
# ========== Filesystem Configuration ==========
|
# ========== Filesystem Configuration ==========
|
||||||
ugaif.host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
|
athenix.host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
|
||||||
ugaif.host.filesystem.swapSize = lib.mkDefault "34G"; # Larger swap for hibernation
|
athenix.host.filesystem.swapSize = lib.mkDefault "34G"; # Larger swap for hibernation
|
||||||
ugaif.host.buildMethods = lib.mkDefault [ "installer-iso" ];
|
athenix.host.buildMethods = lib.mkDefault [ "installer-iso" ];
|
||||||
|
|
||||||
# ========== Power Management ==========
|
# ========== Power Management ==========
|
||||||
services.upower.enable = lib.mkDefault true;
|
services.upower.enable = lib.mkDefault true;
|
||||||
@@ -60,6 +60,6 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
ugaif.sw.enable = lib.mkDefault true;
|
athenix.sw.enable = lib.mkDefault true;
|
||||||
ugaif.sw.type = lib.mkDefault "desktop";
|
athenix.sw.type = lib.mkDefault "desktop";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,11 +52,11 @@
|
|||||||
|
|
||||||
# ========== System Configuration ==========
|
# ========== System Configuration ==========
|
||||||
system.stateVersion = "25.11";
|
system.stateVersion = "25.11";
|
||||||
ugaif.host.buildMethods = lib.mkDefault [
|
athenix.host.buildMethods = lib.mkDefault [
|
||||||
"lxc" # LXC container tarball
|
"lxc" # LXC container tarball
|
||||||
"proxmox" # Proxmox VMA archive
|
"proxmox" # Proxmox VMA archive
|
||||||
];
|
];
|
||||||
|
|
||||||
ugaif.sw.enable = lib.mkDefault true;
|
athenix.sw.enable = lib.mkDefault true;
|
||||||
ugaif.sw.type = lib.mkDefault "headless";
|
athenix.sw.type = lib.mkDefault "headless";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,15 +56,15 @@ in
|
|||||||
boot.kernelPackages = lib.mkForce refKernelPackages;
|
boot.kernelPackages = lib.mkForce refKernelPackages;
|
||||||
|
|
||||||
# ========== Filesystem Configuration ==========
|
# ========== Filesystem Configuration ==========
|
||||||
ugaif.host.filesystem.swapSize = lib.mkDefault "8G";
|
athenix.host.filesystem.swapSize = lib.mkDefault "8G";
|
||||||
ugaif.host.filesystem.device = lib.mkDefault "/dev/mmcblk0"; # eMMC storage # eMMC storage
|
athenix.host.filesystem.device = lib.mkDefault "/dev/mmcblk0"; # eMMC storage # eMMC storage
|
||||||
ugaif.host.buildMethods = lib.mkDefault [ "installer-iso" ];
|
athenix.host.buildMethods = lib.mkDefault [ "installer-iso" ];
|
||||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
|
||||||
# ========== Hardware Configuration ==========
|
# ========== Hardware Configuration ==========
|
||||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
|
||||||
# ========== Software Profile ==========
|
# ========== Software Profile ==========
|
||||||
ugaif.sw.enable = lib.mkDefault true;
|
athenix.sw.enable = lib.mkDefault true;
|
||||||
ugaif.sw.type = lib.mkDefault "tablet-kiosk"; # Touch-optimized kiosk mode
|
athenix.sw.type = lib.mkDefault "tablet-kiosk"; # Touch-optimized kiosk mode
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
# ========== Options ==========
|
# ========== Options ==========
|
||||||
options.ugaif.host.wsl.user = lib.mkOption {
|
options.athenix.host.wsl.user = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "engr-ugaif";
|
default = "engr-ugaif";
|
||||||
description = "The default user to log in as in WSL.";
|
description = "The default user to log in as in WSL.";
|
||||||
@@ -29,11 +29,11 @@
|
|||||||
wsl.enable = true;
|
wsl.enable = true;
|
||||||
# Use forUser if set, otherwise fall back to wsl.user option
|
# Use forUser if set, otherwise fall back to wsl.user option
|
||||||
wsl.defaultUser =
|
wsl.defaultUser =
|
||||||
if config.ugaif.forUser != null then config.ugaif.forUser else config.ugaif.host.wsl.user;
|
if config.athenix.forUser != null then config.athenix.forUser else config.athenix.host.wsl.user;
|
||||||
|
|
||||||
# ========== Software Profile ==========
|
# ========== Software Profile ==========
|
||||||
ugaif.sw.enable = lib.mkDefault true;
|
athenix.sw.enable = lib.mkDefault true;
|
||||||
ugaif.sw.type = lib.mkDefault "headless";
|
athenix.sw.type = lib.mkDefault "headless";
|
||||||
|
|
||||||
# ========== Remote Development ==========
|
# ========== Remote Development ==========
|
||||||
services.vscode-server.enable = true;
|
services.vscode-server.enable = true;
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
systemd.network.enable = lib.mkForce false;
|
systemd.network.enable = lib.mkForce false;
|
||||||
|
|
||||||
# Provide dummy values for required options from boot.nix
|
# Provide dummy values for required options from boot.nix
|
||||||
ugaif.host.filesystem.device = "/dev/null";
|
athenix.host.filesystem.device = "/dev/null";
|
||||||
ugaif.host.filesystem.swapSize = "0G";
|
athenix.host.filesystem.swapSize = "0G";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
let
|
let
|
||||||
# Load users.nix to get account definitions
|
# Load users.nix to get account definitions
|
||||||
usersData = import ../users.nix { inherit pkgs; };
|
usersData = import ../users.nix { inherit pkgs; };
|
||||||
accounts = usersData.ugaif.users or { };
|
accounts = usersData.athenix.users or { };
|
||||||
|
|
||||||
# Helper: Resolve external module path from fetchGit/fetchTarball/path
|
# Helper: Resolve external module path from fetchGit/fetchTarball/path
|
||||||
resolveExternalPath =
|
resolveExternalPath =
|
||||||
@@ -35,7 +35,7 @@ let
|
|||||||
&& (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 ugaif.users options from external user.nix modules
|
# Extract athenix.users options from external user.nix modules
|
||||||
# First, build a cache of options per user from their external user.nix (if any).
|
# First, build a cache of options per user from their external user.nix (if any).
|
||||||
externalUserModuleOptions = lib.genAttrs (lib.attrNames accounts) (
|
externalUserModuleOptions = lib.genAttrs (lib.attrNames accounts) (
|
||||||
name:
|
name:
|
||||||
@@ -53,10 +53,10 @@ let
|
|||||||
inherit lib pkgs;
|
inherit lib pkgs;
|
||||||
osConfig = null;
|
osConfig = null;
|
||||||
};
|
};
|
||||||
# Extract just the ugaif.users.<name> options
|
# Extract just the athenix.users.<name> options
|
||||||
ugaifUsers = evaluatedModule.ugaif.users or { };
|
athenixUsers = evaluatedModule.athenix.users or { };
|
||||||
in
|
in
|
||||||
ugaifUsers.${name} or { }
|
athenixUsers.${name} or { }
|
||||||
else
|
else
|
||||||
{ }
|
{ }
|
||||||
);
|
);
|
||||||
@@ -116,7 +116,7 @@ let
|
|||||||
- A fetchGit/fetchTarball result pointing to a repository
|
- A fetchGit/fetchTarball result pointing to a repository
|
||||||
|
|
||||||
The external module can contain:
|
The external module can contain:
|
||||||
- user.nix (optional): Sets ugaif.users.<name> options AND home-manager config
|
- user.nix (optional): Sets athenix.users.<name> options AND home-manager config
|
||||||
- nixos.nix (optional): System-level NixOS configuration
|
- nixos.nix (optional): System-level NixOS configuration
|
||||||
|
|
||||||
Example: builtins.fetchGit { url = "https://github.com/user/dotfiles"; rev = "..."; }
|
Example: builtins.fetchGit { url = "https://github.com/user/dotfiles"; rev = "..."; }
|
||||||
@@ -157,7 +157,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|
||||||
options.ugaif.users = lib.mkOption {
|
options.athenix.users = lib.mkOption {
|
||||||
type = lib.types.attrsOf userSubmodule;
|
type = lib.types.attrsOf userSubmodule;
|
||||||
default = { };
|
default = { };
|
||||||
description = "User accounts configuration. Set enable=true for users that should exist on this system.";
|
description = "User accounts configuration. Set enable=true for users that should exist on this system.";
|
||||||
@@ -166,7 +166,7 @@ in
|
|||||||
config = {
|
config = {
|
||||||
# Merge user definitions from users.nix with options from external user.nix modules
|
# Merge user definitions from users.nix with options from external user.nix modules
|
||||||
# External options take precedence over users.nix (which uses lib.mkDefault)
|
# External options take precedence over users.nix (which uses lib.mkDefault)
|
||||||
ugaif.users = lib.mapAttrs (
|
athenix.users = lib.mapAttrs (
|
||||||
name: user:
|
name: user:
|
||||||
user
|
user
|
||||||
// {
|
// {
|
||||||
@@ -180,7 +180,7 @@ in
|
|||||||
# Generate NixOS users
|
# Generate NixOS users
|
||||||
users.users =
|
users.users =
|
||||||
let
|
let
|
||||||
enabledAccounts = lib.filterAttrs (_: user: user.enable) config.ugaif.users;
|
enabledAccounts = lib.filterAttrs (_: user: user.enable) config.athenix.users;
|
||||||
in
|
in
|
||||||
lib.mapAttrs (
|
lib.mapAttrs (
|
||||||
name: user:
|
name: user:
|
||||||
@@ -209,7 +209,7 @@ in
|
|||||||
|
|
||||||
users =
|
users =
|
||||||
let
|
let
|
||||||
enabledAccounts = lib.filterAttrs (_: user: user.enable) config.ugaif.users;
|
enabledAccounts = lib.filterAttrs (_: user: user.enable) config.athenix.users;
|
||||||
in
|
in
|
||||||
lib.mapAttrs (
|
lib.mapAttrs (
|
||||||
name: user:
|
name: user:
|
||||||
@@ -220,13 +220,13 @@ in
|
|||||||
userNixPath = if externalPath != null then externalPath + "/user.nix" else null;
|
userNixPath = if externalPath != null then externalPath + "/user.nix" else null;
|
||||||
hasExternalUser = isValidPath userNixPath;
|
hasExternalUser = isValidPath userNixPath;
|
||||||
|
|
||||||
# Import external user.nix for home-manager (filter out ugaif.* options)
|
# Import external user.nix for home-manager (filter out athenix.* options)
|
||||||
externalUserModule =
|
externalUserModule =
|
||||||
if hasExternalUser then
|
if hasExternalUser then
|
||||||
let
|
let
|
||||||
fullModule = import userNixPath { inherit inputs; };
|
fullModule = import userNixPath { inherit inputs; };
|
||||||
in
|
in
|
||||||
# Only pass through non-ugaif options to home-manager
|
# Only pass through non-athenix options to home-manager
|
||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
@@ -244,7 +244,7 @@ in
|
|||||||
;
|
;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
lib.filterAttrs (attrName: _: attrName != "ugaif") evaluated
|
lib.filterAttrs (attrName: _: attrName != "athenix") evaluated
|
||||||
else
|
else
|
||||||
{ };
|
{ };
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ Add the host to `inventory.nix` with the `nix-lxc` type or ensure it has the app
|
|||||||
"my-container" = { };
|
"my-container" = { };
|
||||||
};
|
};
|
||||||
overrides = {
|
overrides = {
|
||||||
ugaif.host.useHostPrefix = false;
|
athenix.host.useHostPrefix = false;
|
||||||
ugaif.host.buildMethods = [ "lxc" ];
|
athenix.host.buildMethods = [ "lxc" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -291,7 +291,7 @@ nix eval .#nixosConfigurations.nix-builder.config.boot.isContainer
|
|||||||
# Should output: true
|
# Should output: true
|
||||||
|
|
||||||
# Check build methods
|
# Check build methods
|
||||||
nix eval .#nixosConfigurations.nix-builder.config.ugaif.host.buildMethods
|
nix eval .#nixosConfigurations.nix-builder.config.athenix.host.buildMethods
|
||||||
# Should include: "lxc"
|
# Should include: "lxc"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -386,7 +386,7 @@ Inside the container:
|
|||||||
The script works with any host in your `nixosConfigurations` that:
|
The script works with any host in your `nixosConfigurations` that:
|
||||||
|
|
||||||
1. Has `boot.isContainer = true`
|
1. Has `boot.isContainer = true`
|
||||||
2. Has `"lxc"` in `ugaif.host.buildMethods`
|
2. Has `"lxc"` in `athenix.host.buildMethods`
|
||||||
3. Imports the Proxmox LXC module
|
3. Imports the Proxmox LXC module
|
||||||
|
|
||||||
Your `artifacts.nix` automatically exposes these as `lxc-<hostname>` packages.
|
Your `artifacts.nix` automatically exposes these as `lxc-<hostname>` packages.
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ let
|
|||||||
let
|
let
|
||||||
cfg = hosts.nixosConfigurations.${name};
|
cfg = hosts.nixosConfigurations.${name};
|
||||||
in
|
in
|
||||||
if lib.elem "installer-iso" cfg.config.ugaif.host.buildMethods then
|
if lib.elem "installer-iso" cfg.config.athenix.host.buildMethods then
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name = "installer-iso-${name}";
|
name = "installer-iso-${name}";
|
||||||
@@ -98,7 +98,7 @@ let
|
|||||||
let
|
let
|
||||||
cfg = hosts.nixosConfigurations.${name};
|
cfg = hosts.nixosConfigurations.${name};
|
||||||
in
|
in
|
||||||
if lib.elem "iso" cfg.config.ugaif.host.buildMethods then
|
if lib.elem "iso" cfg.config.athenix.host.buildMethods then
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name = "iso-${name}";
|
name = "iso-${name}";
|
||||||
@@ -117,7 +117,7 @@ let
|
|||||||
let
|
let
|
||||||
cfg = hosts.nixosConfigurations.${name};
|
cfg = hosts.nixosConfigurations.${name};
|
||||||
in
|
in
|
||||||
if lib.elem "ipxe" cfg.config.ugaif.host.buildMethods then
|
if lib.elem "ipxe" cfg.config.athenix.host.buildMethods then
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name = "ipxe-${name}";
|
name = "ipxe-${name}";
|
||||||
@@ -147,7 +147,7 @@ let
|
|||||||
let
|
let
|
||||||
cfg = hosts.nixosConfigurations.${name};
|
cfg = hosts.nixosConfigurations.${name};
|
||||||
in
|
in
|
||||||
if lib.elem "lxc" cfg.config.ugaif.host.buildMethods then
|
if lib.elem "lxc" cfg.config.athenix.host.buildMethods then
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name = "lxc-${name}";
|
name = "lxc-${name}";
|
||||||
@@ -166,7 +166,7 @@ let
|
|||||||
let
|
let
|
||||||
cfg = hosts.nixosConfigurations.${name};
|
cfg = hosts.nixosConfigurations.${name};
|
||||||
in
|
in
|
||||||
if lib.elem "proxmox" cfg.config.ugaif.host.buildMethods then
|
if lib.elem "proxmox" cfg.config.athenix.host.buildMethods then
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name = "proxmox-${name}";
|
name = "proxmox-${name}";
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
# # Neovim module (requires user parameter):
|
# # Neovim module (requires user parameter):
|
||||||
# home-manager.users.myuser.imports = [
|
# home-manager.users.myuser.imports = [
|
||||||
# (inputs.nixos-systems.homeManagerModules.nvim {
|
# (inputs.nixos-systems.homeManagerModules.nvim {
|
||||||
# user = config.ugaif.users.accounts.myuser;
|
# user = config.athenix.users.accounts.myuser;
|
||||||
# })
|
# })
|
||||||
# ];
|
# ];
|
||||||
|
|
||||||
@@ -37,9 +37,9 @@
|
|||||||
nix-ephemeral = import ../hosts/types/nix-ephemeral.nix { inherit inputs; }; # Diskless/RAM-only
|
nix-ephemeral = import ../hosts/types/nix-ephemeral.nix { inherit inputs; }; # Diskless/RAM-only
|
||||||
|
|
||||||
# ========== Software Configuration Module ==========
|
# ========== Software Configuration Module ==========
|
||||||
# Main software module with all ugaif.sw options
|
# Main software module with all athenix.sw options
|
||||||
# Use ugaif.sw.type to select profile: "desktop", "tablet-kiosk", "headless", "stateless-kiosk"
|
# Use athenix.sw.type to select profile: "desktop", "tablet-kiosk", "headless", "stateless-kiosk"
|
||||||
# Use ugaif.sw.extraPackages to add additional packages
|
# Use athenix.sw.extraPackages to add additional packages
|
||||||
# Use ugaif.sw.kioskUrl to set kiosk mode URL
|
# Use athenix.sw.kioskUrl to set kiosk mode URL
|
||||||
sw = { inputs, ... }@args: (import ../sw/default.nix (args // { inherit inputs; }));
|
sw = { inputs, ... }@args: (import ../sw/default.nix (args // { inherit inputs; }));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
# Hostname generation rules:
|
# Hostname generation rules:
|
||||||
# - Numeric suffixes: no dash (e.g., "nix-surface1", "nix-surface2")
|
# - Numeric suffixes: no dash (e.g., "nix-surface1", "nix-surface2")
|
||||||
# - Non-numeric suffixes: add dash (e.g., "nix-surface-alpha", "nix-surface-beta")
|
# - Non-numeric suffixes: add dash (e.g., "nix-surface-alpha", "nix-surface-beta")
|
||||||
# - Set ugaif.host.useHostPrefix = false to use suffix as full hostname
|
# - Set athenix.host.useHostPrefix = false to use suffix as full hostname
|
||||||
#
|
#
|
||||||
# Format:
|
# Format:
|
||||||
# "prefix" = {
|
# "prefix" = {
|
||||||
@@ -29,19 +29,19 @@
|
|||||||
# "1" = { ... }; # Creates: prefix1
|
# "1" = { ... }; # Creates: prefix1
|
||||||
# "alpha" = { ... }; # Creates: prefix-alpha
|
# "alpha" = { ... }; # Creates: prefix-alpha
|
||||||
# "custom" = { # Creates: custom (no prefix)
|
# "custom" = { # Creates: custom (no prefix)
|
||||||
# ugaif.host.useHostPrefix = false;
|
# athenix.host.useHostPrefix = false;
|
||||||
# };
|
# };
|
||||||
# };
|
# };
|
||||||
#
|
#
|
||||||
# # Common config for all devices in this group
|
# # Common config for all devices in this group
|
||||||
# overrides = {
|
# overrides = {
|
||||||
# ugaif.users.user1.enable = true; # Applied to all devices in this group
|
# athenix.users.user1.enable = true; # Applied to all devices in this group
|
||||||
# # ... any other config
|
# # ... any other config
|
||||||
# };
|
# };
|
||||||
# };
|
# };
|
||||||
#
|
#
|
||||||
# Convenience options:
|
# Convenience options:
|
||||||
# ugaif.forUser = "username"; # Automatically enables user (sets ugaif.users.username.enable = true)
|
# athenix.forUser = "username"; # Automatically enables user (sets athenix.users.username.enable = true)
|
||||||
#
|
#
|
||||||
# External modules (instead of config):
|
# External modules (instead of config):
|
||||||
# Device values can be either a config attrset OR a fetchGit/fetchurl call
|
# Device values can be either a config attrset OR a fetchGit/fetchurl call
|
||||||
@@ -56,22 +56,22 @@
|
|||||||
# };
|
# };
|
||||||
# "laptop" = {
|
# "laptop" = {
|
||||||
# devices = 5;
|
# devices = 5;
|
||||||
# overrides.ugaif.users.student.enable = true; # All 5 laptops get this user
|
# overrides.athenix.users.student.enable = true; # All 5 laptops get this user
|
||||||
# };
|
# };
|
||||||
# "wsl" = {
|
# "wsl" = {
|
||||||
# devices."alice".ugaif.forUser = "alice123"; # Sets up for user alice123
|
# devices."alice".athenix.forUser = "alice123"; # Sets up for user alice123
|
||||||
# };
|
# };
|
||||||
# "external" = {
|
# "external" = {
|
||||||
# devices."remote" = builtins.fetchGit { # External module via Git
|
# devices."remote" = builtins.fetchGit { # External module via Git
|
||||||
# url = "https://github.com/example/config";
|
# url = "https://github.com/example/config";
|
||||||
# rev = "abc123...";
|
# rev = "e1ccd7cc3e709afe4f50b0627e1c4bde49165014";
|
||||||
# };
|
# };
|
||||||
# }; # ========== Lab Laptops ==========
|
# }; # ========== Lab Laptops ==========
|
||||||
# Creates: nix-laptop1, nix-laptop2
|
# Creates: nix-laptop1, nix-laptop2
|
||||||
# Both get hdh20267 user via overrides
|
# Both get hdh20267 user via overrides
|
||||||
nix-laptop = {
|
nix-laptop = {
|
||||||
devices = 2;
|
devices = 2;
|
||||||
overrides.ugaif.users.hdh20267.enable = true;
|
overrides.athenix.users.hdh20267.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
# ========== Desktop ==========
|
# ========== Desktop ==========
|
||||||
@@ -85,10 +85,10 @@
|
|||||||
nix-surface = {
|
nix-surface = {
|
||||||
defaultCount = 3;
|
defaultCount = 3;
|
||||||
devices = {
|
devices = {
|
||||||
"1".ugaif.sw.kioskUrl = "https://google.com";
|
"1".athenix.sw.kioskUrl = "https://google.com";
|
||||||
};
|
};
|
||||||
overrides = {
|
overrides = {
|
||||||
ugaif.sw.kioskUrl = "https://yahoo.com";
|
athenix.sw.kioskUrl = "https://yahoo.com";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -97,37 +97,37 @@
|
|||||||
nix-lxc = {
|
nix-lxc = {
|
||||||
devices = {
|
devices = {
|
||||||
"nix-builder" = {
|
"nix-builder" = {
|
||||||
# GitHub Actions self-hosted runner configuration
|
# Gitea Actions self-hosted runner configuration
|
||||||
ugaif.sw = {
|
athenix.sw = {
|
||||||
type = [
|
type = [
|
||||||
"headless"
|
"headless"
|
||||||
"builders"
|
"builders"
|
||||||
];
|
];
|
||||||
builders.githubRunner = {
|
builders.giteaRunner = {
|
||||||
enable = true;
|
enable = true;
|
||||||
url = "https://github.com/UGA-Innovation-Factory/nixos-systems";
|
url = "https://git.factory.uga.edu";
|
||||||
# Token file must be created manually at this path with a GitHub PAT
|
# Token file must be created manually at this path with a Gitea runner token
|
||||||
# that has repo access. Generate at: https://github.com/settings/tokens
|
# Generate in repository settings: Settings > Actions > Runners > Create new Runner
|
||||||
# echo "YOUR_TOKEN_HERE" | sudo tee /var/lib/github-runner-token > /dev/null
|
# echo "TOKEN=YOUR_TOKEN_HERE" | sudo tee /var/lib/gitea-runner-token > /dev/null
|
||||||
tokenFile = "/var/lib/github-runner-token";
|
tokenFile = "/var/lib/gitea-runner-token";
|
||||||
# Labels to identify this runner in workflows
|
# Labels to identify this runner in workflows
|
||||||
extraLabels = [ "nix-builder" ];
|
extraLabels = [
|
||||||
# User to run the runner as
|
"self-hosted"
|
||||||
user = "engr-ugaif";
|
"nix-builder"
|
||||||
# Working directory for runner
|
];
|
||||||
workDir = "/var/lib/github-runner";
|
|
||||||
# Runner service name
|
# Runner service name
|
||||||
name = "nixos-systems";
|
name = "athenix";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"usda-dash" = builtins.fetchGit {
|
"usda-dash" = builtins.fetchGit {
|
||||||
url = "https://git.factory.uga.edu/MODEL/usda-dash-config.git";
|
url = "git@factory.uga.edu:MODEL/usda-dash-config.git";
|
||||||
rev = "c47ab8fe295ba38cf3baa8670812b23a09fb4d53";
|
rev = "49cded91cff4a956d4e01ac6b8fe4efa86f82182";
|
||||||
|
submodules = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
overrides = {
|
overrides = {
|
||||||
ugaif.host.useHostPrefix = false;
|
athenix.host.useHostPrefix = false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
# Creates: nix-wsl-alireza
|
# Creates: nix-wsl-alireza
|
||||||
nix-wsl = {
|
nix-wsl = {
|
||||||
devices = {
|
devices = {
|
||||||
"alireza".ugaif.forUser = "sv22900";
|
"alireza".athenix.forUser = "sv22900";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@
|
|||||||
# # Option 1: fetchGit with specific revision (recommended for reproducibility)
|
# # Option 1: fetchGit with specific revision (recommended for reproducibility)
|
||||||
# "prod-server" = builtins.fetchGit {
|
# "prod-server" = builtins.fetchGit {
|
||||||
# url = "https://github.com/example/server-config";
|
# url = "https://github.com/example/server-config";
|
||||||
# rev = "abc123def456..."; # Full commit hash
|
# rev = "e1ccd7cc3e709afe4f50b0627e1c4bde49165014"; # Full commit hash
|
||||||
# ref = "main"; # Optional: branch/tag name
|
# ref = "main"; # Optional: branch/tag name
|
||||||
# };
|
# };
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Builders Software Configuration
|
# Builders Software Configuration
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Imports builder-specific programs and services (GitHub Actions runners, etc.)
|
# Imports builder-specific programs and services (Gitea Actions runners, etc.)
|
||||||
|
|
||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
|
|||||||
@@ -9,11 +9,24 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.ugaif.sw;
|
cfg = config.athenix.sw;
|
||||||
basePackages = with pkgs; [
|
basePackages = with pkgs; [
|
||||||
# Build-related packages can be added here if needed
|
# Build-related packages can be added here if needed
|
||||||
];
|
];
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
environment.systemPackages = subtractLists cfg.excludePackages (basePackages ++ cfg.extraPackages);
|
environment.systemPackages = subtractLists cfg.excludePackages (basePackages ++ cfg.extraPackages);
|
||||||
|
|
||||||
|
programs.ssh.knownHosts."factory.uga.edu" = {
|
||||||
|
hostNames = [ "factory.uga.edu" ];
|
||||||
|
publicKey = ''
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGcrA7pAz+JGn7/7PqPR4aCZJB5c3aVMTvGXWjg/BqST
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
programs.ssh.knownHosts."github.com" = {
|
||||||
|
hostNames = [ "github.com" ];
|
||||||
|
publicKey = ''
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||||
|
'';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,122 +8,66 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.ugaif.sw;
|
cfg = config.athenix.sw;
|
||||||
builderCfg = cfg.builders;
|
builderCfg = cfg.builders;
|
||||||
in
|
in
|
||||||
mkIf builderCfg.githubRunner.enable {
|
mkIf builderCfg.giteaRunner.enable {
|
||||||
services.github-runners.${builderCfg.githubRunner.name} = {
|
services.gitea-actions-runner.instances.${builderCfg.giteaRunner.name} = {
|
||||||
enable = true;
|
enable = true;
|
||||||
url = builderCfg.githubRunner.url;
|
url = builderCfg.giteaRunner.url;
|
||||||
tokenFile = builderCfg.githubRunner.tokenFile;
|
tokenFile = builderCfg.giteaRunner.tokenFile;
|
||||||
extraLabels = builderCfg.githubRunner.extraLabels;
|
labels = builderCfg.giteaRunner.extraLabels;
|
||||||
user = builderCfg.githubRunner.user;
|
name = builderCfg.giteaRunner.name;
|
||||||
workDir = builderCfg.githubRunner.workDir;
|
|
||||||
replace = builderCfg.githubRunner.replace;
|
# Run as engr-ugaif user to access SSH keys
|
||||||
|
settings = {
|
||||||
|
runner = {
|
||||||
|
user = "engr-ugaif";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Configure the systemd service for better handling of cleanup and restarts
|
# Configure the systemd service for better handling in LXC containers
|
||||||
systemd.services."github-runner-${builderCfg.githubRunner.name}" = {
|
systemd.services."gitea-runner-${builderCfg.giteaRunner.name}" = {
|
||||||
unitConfig = {
|
unitConfig = {
|
||||||
# Only start the service if token file exists
|
# Only start the service if token file exists
|
||||||
# This allows graceful deployment before the token is manually installed
|
# This allows graceful deployment before the token is manually installed
|
||||||
ConditionPathExists = builderCfg.githubRunner.tokenFile;
|
ConditionPathExists = builderCfg.giteaRunner.tokenFile;
|
||||||
};
|
};
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
# Run as engr-ugaif user
|
||||||
|
User = mkForce "engr-ugaif";
|
||||||
|
Group = mkForce "users";
|
||||||
|
|
||||||
# Give the service more time to stop cleanly
|
# Give the service more time to stop cleanly
|
||||||
TimeoutStopSec = 60;
|
TimeoutStopSec = mkForce 60;
|
||||||
# Restart on failure, but not immediately
|
|
||||||
RestartSec = 10;
|
# Add Node.js and other tools to PATH for GitHub Actions compatibility
|
||||||
|
Environment = [
|
||||||
|
"PATH=${pkgs.nodejs}/bin:${pkgs.bash}/bin:${pkgs.coreutils}/bin:${pkgs.git}/bin:${pkgs.nix}/bin:/run/current-system/sw/bin"
|
||||||
|
"HOME=/home/engr-ugaif"
|
||||||
|
];
|
||||||
|
|
||||||
# Disable all namespace isolation features that don't work in LXC containers
|
# Disable all namespace isolation features that don't work in LXC containers
|
||||||
|
# Remove systemd security features that conflict with home directory access
|
||||||
|
DynamicUser = mkForce false;
|
||||||
PrivateMounts = mkForce false;
|
PrivateMounts = mkForce false;
|
||||||
MountAPIVFS = mkForce false;
|
MountAPIVFS = mkForce false;
|
||||||
BindPaths = mkForce [ ];
|
BindPaths = mkForce [ ];
|
||||||
BindReadOnlyPaths = mkForce [ ];
|
BindReadOnlyPaths = mkForce [ ];
|
||||||
|
ReadWritePaths = mkForce [ ];
|
||||||
|
ReadOnlyPaths = mkForce [ ];
|
||||||
|
InaccessiblePaths = mkForce [ ];
|
||||||
PrivateTmp = mkForce false;
|
PrivateTmp = mkForce false;
|
||||||
PrivateDevices = mkForce false;
|
PrivateDevices = mkForce false;
|
||||||
ProtectSystem = mkForce false;
|
ProtectSystem = mkForce false;
|
||||||
ProtectHome = mkForce false;
|
ProtectHome = mkForce false;
|
||||||
ReadOnlyPaths = mkForce [ ];
|
|
||||||
InaccessiblePaths = mkForce [ ];
|
|
||||||
PrivateUsers = mkForce false;
|
PrivateUsers = mkForce false;
|
||||||
ProtectKernelTunables = mkForce false;
|
ProtectKernelTunables = mkForce false;
|
||||||
ProtectKernelModules = mkForce false;
|
ProtectKernelModules = mkForce false;
|
||||||
ProtectControlGroups = mkForce false;
|
ProtectControlGroups = mkForce false;
|
||||||
|
RestrictAddressFamilies = mkForce [ ];
|
||||||
# Use LoadCredential to securely pass the token file to the service
|
SystemCallFilter = mkForce [ ];
|
||||||
# This allows the service to read the token even when running as non-root
|
|
||||||
LoadCredential = "token:${builderCfg.githubRunner.tokenFile}";
|
|
||||||
|
|
||||||
# Don't override ExecStartPre - let the default module handle configuration
|
|
||||||
# Just make the cleanup more tolerant by wrapping the original script
|
|
||||||
ExecStartPre = mkForce (
|
|
||||||
let
|
|
||||||
# Get the runner package and scripts
|
|
||||||
runnerPkg = pkgs.github-runner;
|
|
||||||
|
|
||||||
# Create wrapper scripts that are failure-tolerant
|
|
||||||
unconfigureWrapper = pkgs.writeShellScript "github-runner-unconfigure-wrapper.sh" ''
|
|
||||||
set +e # Don't fail on errors
|
|
||||||
|
|
||||||
runnerDir="$1"
|
|
||||||
stateDir="$2"
|
|
||||||
logDir="$3"
|
|
||||||
|
|
||||||
# If directory is busy, just skip cleanup with a warning
|
|
||||||
if [ -d "$runnerDir" ]; then
|
|
||||||
echo "Attempting cleanup of $runnerDir..."
|
|
||||||
find "$runnerDir" -mindepth 1 -maxdepth 1 -delete 2>/dev/null || {
|
|
||||||
echo "Warning: Cleanup had issues (directory may be in use), continuing anyway..."
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
'';
|
|
||||||
|
|
||||||
configureScript = pkgs.writeShellScript "github-runner-configure.sh" ''
|
|
||||||
set -e
|
|
||||||
|
|
||||||
runnerDir="${builderCfg.githubRunner.workDir}/${builderCfg.githubRunner.name}"
|
|
||||||
|
|
||||||
# Read token from systemd credential (passed via LoadCredential)
|
|
||||||
if [ -n "''${CREDENTIALS_DIRECTORY:-}" ] && [ -f "''${CREDENTIALS_DIRECTORY}/token" ]; then
|
|
||||||
token=$(cat "''${CREDENTIALS_DIRECTORY}/token")
|
|
||||||
else
|
|
||||||
echo "Error: Token credential not available"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$runnerDir"
|
|
||||||
|
|
||||||
# Configure the runner, optionally replacing existing registration
|
|
||||||
if [ ! -f ".runner" ] || [ "${
|
|
||||||
if builderCfg.githubRunner.replace then "true" else "false"
|
|
||||||
}" = "true" ]; then
|
|
||||||
echo "Configuring GitHub Actions runner..."
|
|
||||||
${runnerPkg}/bin/Runner.Listener configure \
|
|
||||||
--unattended \
|
|
||||||
--url "${builderCfg.githubRunner.url}" \
|
|
||||||
--token "$token" \
|
|
||||||
--name "$(hostname)" \
|
|
||||||
--labels "${lib.concatStringsSep "," builderCfg.githubRunner.extraLabels}" \
|
|
||||||
--work "_work" \
|
|
||||||
${if builderCfg.githubRunner.replace then "--replace" else ""}
|
|
||||||
else
|
|
||||||
echo "Runner already configured, skipping configuration."
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
[
|
|
||||||
"-${unconfigureWrapper} ${builderCfg.githubRunner.workDir}/${builderCfg.githubRunner.name} ${builderCfg.githubRunner.workDir} /var/log/github-runner/${builderCfg.githubRunner.name}"
|
|
||||||
"${configureScript}"
|
|
||||||
]
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Ensure the work directory exists with proper ownership
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"d ${builderCfg.githubRunner.workDir} 0755 ${builderCfg.githubRunner.user} ${builderCfg.githubRunner.user} -"
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.ugaif.sw;
|
cfg = config.athenix.sw;
|
||||||
|
|
||||||
# Normalize type to always be a list
|
# Normalize type to always be a list
|
||||||
swTypes = if isList cfg.type then cfg.type else [ cfg.type ];
|
swTypes = if isList cfg.type then cfg.type else [ cfg.type ];
|
||||||
@@ -29,9 +29,10 @@ in
|
|||||||
./python.nix
|
./python.nix
|
||||||
./ghostty.nix
|
./ghostty.nix
|
||||||
./updater.nix
|
./updater.nix
|
||||||
|
./update-ref.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
options.ugaif.sw = {
|
options.athenix.sw = {
|
||||||
enable = mkEnableOption "Standard Workstation Configuration";
|
enable = mkEnableOption "Standard Workstation Configuration";
|
||||||
|
|
||||||
type = mkOption {
|
type = mkOption {
|
||||||
@@ -79,21 +80,21 @@ in
|
|||||||
builders = mkOption {
|
builders = mkOption {
|
||||||
type = types.submodule {
|
type = types.submodule {
|
||||||
options = {
|
options = {
|
||||||
githubRunner = {
|
giteaRunner = {
|
||||||
enable = mkEnableOption "GitHub Actions self-hosted runner";
|
enable = mkEnableOption "Gitea Actions self-hosted runner";
|
||||||
|
|
||||||
url = mkOption {
|
url = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = "GitHub repository URL for the runner";
|
description = "Gitea instance URL for the runner";
|
||||||
};
|
};
|
||||||
|
|
||||||
tokenFile = mkOption {
|
tokenFile = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "/var/lib/github-runner-token";
|
default = "/var/lib/gitea-runner-token";
|
||||||
description = ''
|
description = ''
|
||||||
Path to file containing GitHub PAT token.
|
Path to file containing Gitea runner token.
|
||||||
Generate at: https://github.com/settings/tokens
|
Generate in Gitea repository settings under Actions > Runners.
|
||||||
The token must have repo access.
|
The token must have runner registration access.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -103,28 +104,10 @@ in
|
|||||||
description = "Extra labels to identify this runner in workflows";
|
description = "Extra labels to identify this runner in workflows";
|
||||||
};
|
};
|
||||||
|
|
||||||
user = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "engr-ugaif";
|
|
||||||
description = "User to run the runner as";
|
|
||||||
};
|
|
||||||
|
|
||||||
workDir = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "/var/lib/github-runner";
|
|
||||||
description = "Working directory for runner";
|
|
||||||
};
|
|
||||||
|
|
||||||
name = mkOption {
|
name = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "nixos-systems";
|
default = "athenix";
|
||||||
description = "Name of the GitHub runner service";
|
description = "Name of the Gitea runner service";
|
||||||
};
|
|
||||||
|
|
||||||
replace = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = "Replace existing runner registration on start";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.ugaif.sw;
|
cfg = config.athenix.sw;
|
||||||
basePackages = with pkgs; [
|
basePackages = with pkgs; [
|
||||||
tmux
|
tmux
|
||||||
man
|
man
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
}:
|
}:
|
||||||
|
|
||||||
{
|
{
|
||||||
ugaif.sw.python.enable = lib.mkDefault true;
|
athenix.sw.python.enable = lib.mkDefault true;
|
||||||
|
|
||||||
services.displayManager.sddm.enable = true;
|
services.displayManager.sddm.enable = true;
|
||||||
services.desktopManager.plasma6.enable = true;
|
services.desktopManager.plasma6.enable = true;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.ugaif.sw;
|
cfg = config.athenix.sw;
|
||||||
basePackages = with pkgs; [
|
basePackages = with pkgs; [
|
||||||
tmux
|
tmux
|
||||||
man
|
man
|
||||||
|
|||||||
@@ -15,10 +15,10 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.ugaif.sw.python;
|
cfg = config.athenix.sw.python;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.ugaif.sw.python = {
|
options.athenix.sw.python = {
|
||||||
enable = mkEnableOption "Python development tools (pixi, uv)" // {
|
enable = mkEnableOption "Python development tools (pixi, uv)" // {
|
||||||
default = true;
|
default = true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.ugaif.sw;
|
cfg = config.athenix.sw;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
programs.dconf = {
|
programs.dconf = {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.ugaif.sw;
|
cfg = config.athenix.sw;
|
||||||
basePackages = with pkgs; [
|
basePackages = with pkgs; [
|
||||||
libcamera
|
libcamera
|
||||||
chromium
|
chromium
|
||||||
|
|||||||
@@ -155,7 +155,7 @@
|
|||||||
--noerrdialogs \
|
--noerrdialogs \
|
||||||
--disable-session-crashed-bubble \
|
--disable-session-crashed-bubble \
|
||||||
--disable-infobars \
|
--disable-infobars \
|
||||||
${config.ugaif.sw.kioskUrl}
|
${config.athenix.sw.kioskUrl}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
487
sw/update-ref.nix
Normal file
487
sw/update-ref.nix
Normal file
@@ -0,0 +1,487 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
python3
|
||||||
|
git
|
||||||
|
(pkgs.writeShellScriptBin "update-ref" ''
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
RED='\033[31m'; YEL='\033[33m'; NC='\033[0m'
|
||||||
|
die() { printf "''${RED}error:''${NC} %s\n" "$*" >&2; exit 2; }
|
||||||
|
warn() { printf "''${YEL}warning:''${NC} %s\n" "$*" >&2; }
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat >&2 <<'EOF'
|
||||||
|
usage:
|
||||||
|
update-ref [-R PATH|--athenix-repo=PATH] [-b BRANCH|--athenix-branch=BRANCH]
|
||||||
|
[-m "msg"|--message "msg"]
|
||||||
|
[-p[=false] [remote[=URL]]|--push[=false] [remote[=URL]]]
|
||||||
|
[--make-local|-l] [--make-remote|-r]
|
||||||
|
user=<username> | system=<device-type>:<hostkey>
|
||||||
|
EOF
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- must be in a git repo (current dir) ---
|
||||||
|
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || die "This directory is not a git project"
|
||||||
|
CUR_REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||||
|
CUR_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
||||||
|
|
||||||
|
# --- athenix checkout (working tree) ---
|
||||||
|
ATHENIX_DIR="$HOME/athenix"
|
||||||
|
ATHENIX_BRANCH=""
|
||||||
|
|
||||||
|
# --- current repo automation ---
|
||||||
|
COMMIT_MSG=""
|
||||||
|
PUSH_SPEC=""
|
||||||
|
|
||||||
|
# --- push / url mode ---
|
||||||
|
PUSH_SET=0
|
||||||
|
DO_PUSH=0
|
||||||
|
MODE_FORCE="" # "", local, remote
|
||||||
|
|
||||||
|
TARGET=""
|
||||||
|
|
||||||
|
is_remote_url() {
|
||||||
|
# https://, http://, ssh://, or scp-style git@host:org/repo
|
||||||
|
printf "%s" "$1" | grep -qE '^(https?|ssh)://|^[^/@:]+@[^/:]+:'
|
||||||
|
}
|
||||||
|
|
||||||
|
derive_full_hostname() {
|
||||||
|
devtype="$1"; hostkey="$2"
|
||||||
|
if printf "%s" "$hostkey" | grep -q '-' || printf "%s" "$hostkey" | grep -q "^$devtype"; then
|
||||||
|
printf "%s" "$hostkey"
|
||||||
|
elif printf "%s" "$hostkey" | grep -qE '^[0-9]+$'; then
|
||||||
|
printf "%s" "$devtype$hostkey"
|
||||||
|
else
|
||||||
|
printf "%s" "$devtype-$hostkey"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_existing_fetch_url() {
|
||||||
|
# args: mode file username key
|
||||||
|
python3 - "$1" "$2" "$3" "$4" <<'PY'
|
||||||
|
import sys, re, pathlib
|
||||||
|
mode, file, username, key = sys.argv[1:5]
|
||||||
|
t = pathlib.Path(file).read_text()
|
||||||
|
|
||||||
|
def url_from_block(block: str) -> str:
|
||||||
|
if not block:
|
||||||
|
return ""
|
||||||
|
m = re.search(r'url\s*=\s*"([^"]+)"\s*;', block)
|
||||||
|
return m.group(1) if m else ""
|
||||||
|
|
||||||
|
if mode == "user":
|
||||||
|
m = re.search(r'(?s)\n\s*' + re.escape(username) + r'\.external\s*=\s*builtins\.fetchGit\s*\{(.*?)\n\s*\};', t)
|
||||||
|
block = m.group(1) if m else ""
|
||||||
|
print(url_from_block(block))
|
||||||
|
else:
|
||||||
|
m = re.search(r'(?s)\n\s*"' + re.escape(key) + r'"\s*=\s*builtins\.fetchGit\s*\{(.*?)\n\s*\};', t)
|
||||||
|
block = m.group(1) if m else ""
|
||||||
|
print(url_from_block(block))
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- parse args ---
|
||||||
|
while [ "$#" -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
user=*|system=*)
|
||||||
|
[ -z "$TARGET" ] || die "Only one subcommand allowed (user=... or system=...)"
|
||||||
|
TARGET="$1"; shift
|
||||||
|
;;
|
||||||
|
--athenix-repo=*)
|
||||||
|
ATHENIX_DIR="''${1#*=}"; shift
|
||||||
|
;;
|
||||||
|
-R)
|
||||||
|
[ "$#" -ge 2 ] || usage
|
||||||
|
ATHENIX_DIR="$2"; shift 2
|
||||||
|
;;
|
||||||
|
--athenix-branch=*)
|
||||||
|
ATHENIX_BRANCH="''${1#*=}"; shift
|
||||||
|
;;
|
||||||
|
-b)
|
||||||
|
[ "$#" -ge 2 ] || usage
|
||||||
|
ATHENIX_BRANCH="$2"; shift 2
|
||||||
|
;;
|
||||||
|
-m|--message)
|
||||||
|
[ "$#" -ge 2 ] || usage
|
||||||
|
COMMIT_MSG="$2"; shift 2
|
||||||
|
;;
|
||||||
|
|
||||||
|
-p|--push)
|
||||||
|
PUSH_SET=1
|
||||||
|
DO_PUSH=1
|
||||||
|
PUSH_SPEC=""
|
||||||
|
|
||||||
|
# If there is a next token, only consume it if it is a remote spec
|
||||||
|
# and not another flag or the subcommand.
|
||||||
|
if [ "$#" -ge 2 ]; then
|
||||||
|
nxt="$2"
|
||||||
|
|
||||||
|
if printf "%s" "$nxt" | grep -qE '^(user=|system=)'; then
|
||||||
|
# next token is the subcommand; don't consume it
|
||||||
|
shift
|
||||||
|
elif printf "%s" "$nxt" | grep -qE '^-'; then
|
||||||
|
# next token is another flag; don't consume it
|
||||||
|
shift
|
||||||
|
elif printf "%s" "$nxt" | grep -qE '^[A-Za-z0-9._-]+$'; then
|
||||||
|
# remote name
|
||||||
|
PUSH_SPEC="$nxt"
|
||||||
|
shift 2
|
||||||
|
elif printf "%s" "$nxt" | grep -qE '^[A-Za-z0-9._-]+=.+$'; then
|
||||||
|
# remote=URL
|
||||||
|
PUSH_SPEC="$nxt"
|
||||||
|
shift 2
|
||||||
|
else
|
||||||
|
# unknown token; treat as not-a-push-spec and don't consume it
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
-p=*|--push=*)
|
||||||
|
PUSH_SET=1
|
||||||
|
val="''${1#*=}"
|
||||||
|
case "$val" in
|
||||||
|
false|0|no|off) DO_PUSH=0 ;;
|
||||||
|
true|1|yes|on|"") DO_PUSH=1 ;;
|
||||||
|
*) die "Invalid value for --push: $val (use true/false)" ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
|
||||||
|
--make-local|-l) MODE_FORCE="local"; shift ;;
|
||||||
|
--make-remote|-r) MODE_FORCE="remote"; shift ;;
|
||||||
|
-h|--help) usage ;;
|
||||||
|
*) die "Unknown argument: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -n "$TARGET" ] || die "Missing required subcommand: user=<username> or system=<device-type>:<hostkey>"
|
||||||
|
|
||||||
|
# --- validate athenix working tree path ---
|
||||||
|
[ -d "$ATHENIX_DIR" ] || die "$ATHENIX_DIR does not exist"
|
||||||
|
git -C "$ATHENIX_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1 || die "$ATHENIX_DIR is not a git project (athenix checkout)"
|
||||||
|
|
||||||
|
# --- -b behavior: fork/switch athenix working tree into branch ---
|
||||||
|
if [ -n "$ATHENIX_BRANCH" ]; then
|
||||||
|
ATH_CUR_BRANCH="$(git -C "$ATHENIX_DIR" rev-parse --abbrev-ref HEAD)"
|
||||||
|
if [ "$ATH_CUR_BRANCH" != "$ATHENIX_BRANCH" ]; then
|
||||||
|
if git -C "$ATHENIX_DIR" show-ref --verify --quiet "refs/heads/$ATHENIX_BRANCH"; then
|
||||||
|
warn "Branch '$ATHENIX_BRANCH' already exists in $ATHENIX_DIR."
|
||||||
|
warn "Delete and recreate it from current branch '$ATH_CUR_BRANCH' state? [y/N] "
|
||||||
|
read -r ans || true
|
||||||
|
case "''${ans:-N}" in
|
||||||
|
y|Y|yes|YES)
|
||||||
|
git -C "$ATHENIX_DIR" branch -D "$ATHENIX_BRANCH"
|
||||||
|
git -C "$ATHENIX_DIR" switch -c "$ATHENIX_BRANCH"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
git -C "$ATHENIX_DIR" switch "$ATHENIX_BRANCH"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
git -C "$ATHENIX_DIR" switch -c "$ATHENIX_BRANCH"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- target file + identifiers ---
|
||||||
|
MODE=""; FILE=""; USERNAME=""; DEVTYPE=""; HOSTKEY=""
|
||||||
|
case "$TARGET" in
|
||||||
|
user=*)
|
||||||
|
MODE="user"
|
||||||
|
USERNAME="''${TARGET#user=}"
|
||||||
|
[ -n "$USERNAME" ] || die "user=<username>: username missing"
|
||||||
|
FILE="$ATHENIX_DIR/users.nix"
|
||||||
|
;;
|
||||||
|
system=*)
|
||||||
|
MODE="system"
|
||||||
|
RHS="''${TARGET#system=}"
|
||||||
|
printf "%s" "$RHS" | grep -q ':' || die "system=... must be system=<device-type>:<hostkey>"
|
||||||
|
DEVTYPE="''${RHS%%:*}"
|
||||||
|
HOSTKEY="''${RHS#*:}"
|
||||||
|
[ -n "$DEVTYPE" ] || die "system=<device-type>:<hostkey>: device-type missing"
|
||||||
|
[ -n "$HOSTKEY" ] || die "system=<device-type>:<hostkey>: hostkey missing"
|
||||||
|
FILE="$ATHENIX_DIR/inventory.nix"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
[ -f "$FILE" ] || die "File not found: $FILE"
|
||||||
|
|
||||||
|
# --- push default based on existing entry url in the target file ---
|
||||||
|
EXISTING_URL=""
|
||||||
|
ENTRY_EXISTS=0
|
||||||
|
if [ "$MODE" = "user" ]; then
|
||||||
|
EXISTING_URL="$(extract_existing_fetch_url user "$FILE" "$USERNAME" "")"
|
||||||
|
[ -n "$EXISTING_URL" ] && ENTRY_EXISTS=1 || true
|
||||||
|
else
|
||||||
|
FULL="$(derive_full_hostname "$DEVTYPE" "$HOSTKEY")"
|
||||||
|
EXISTING_URL="$(extract_existing_fetch_url system "$FILE" "" "$HOSTKEY")"
|
||||||
|
if [ -n "$EXISTING_URL" ]; then
|
||||||
|
ENTRY_EXISTS=1
|
||||||
|
elif [ "$FULL" != "$HOSTKEY" ]; then
|
||||||
|
EXISTING_URL="$(extract_existing_fetch_url system "$FILE" "" "$FULL")"
|
||||||
|
[ -n "$EXISTING_URL" ] && ENTRY_EXISTS=1 || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$PUSH_SET" -eq 0 ]; then
|
||||||
|
if [ "$ENTRY_EXISTS" -eq 1 ] && is_remote_url "$EXISTING_URL"; then
|
||||||
|
DO_PUSH=1
|
||||||
|
else
|
||||||
|
DO_PUSH=0
|
||||||
|
[ "$MODE_FORCE" = "remote" ] && DO_PUSH=1 || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ "$MODE_FORCE" = "local" ] && [ "$PUSH_SET" -eq 0 ]; then
|
||||||
|
DO_PUSH=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- if current repo dirty, prompt ---
|
||||||
|
if [ -n "$(git status --porcelain)" ]; then
|
||||||
|
warn "This branch has untracked or uncommitted changes. Would you like to add, commit''${DO_PUSH:+, and push}? [y/N] "
|
||||||
|
read -r ans || true
|
||||||
|
case "''${ans:-N}" in
|
||||||
|
y|Y|yes|YES)
|
||||||
|
git add -A
|
||||||
|
if ! git diff --cached --quiet; then
|
||||||
|
if [ -n "$COMMIT_MSG" ]; then git commit -m "$COMMIT_MSG"; else git commit; fi
|
||||||
|
else
|
||||||
|
warn "No staged changes to commit."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*) warn "Proceeding without committing. (rev will be last committed HEAD.)" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- push current repo if requested ---
|
||||||
|
PUSH_REMOTE_URL=""
|
||||||
|
if [ "$DO_PUSH" -eq 1 ]; then
|
||||||
|
if [ -n "$PUSH_SPEC" ]; then
|
||||||
|
if printf "%s" "$PUSH_SPEC" | grep -q '='; then
|
||||||
|
REM_NAME="''${PUSH_SPEC%%=*}"
|
||||||
|
REM_URL="''${PUSH_SPEC#*=}"
|
||||||
|
[ -n "$REM_NAME" ] || die "--push remote-name=URL: remote-name missing"
|
||||||
|
[ -n "$REM_URL" ] || die "--push remote-name=URL: URL missing"
|
||||||
|
if git remote get-url "$REM_NAME" >/dev/null 2>&1; then
|
||||||
|
git remote set-url "$REM_NAME" "$REM_URL"
|
||||||
|
else
|
||||||
|
git remote add "$REM_NAME" "$REM_URL"
|
||||||
|
fi
|
||||||
|
git push -u "$REM_NAME" "$CUR_BRANCH"
|
||||||
|
PUSH_REMOTE_URL="$REM_URL"
|
||||||
|
else
|
||||||
|
REM_NAME="$PUSH_SPEC"
|
||||||
|
git push -u "$REM_NAME" "$CUR_BRANCH"
|
||||||
|
PUSH_REMOTE_URL="$(git remote get-url "$REM_NAME")"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if ! git rev-parse --abbrev-ref --symbolic-full-name @{u} >/dev/null 2>&1; then
|
||||||
|
die "No upstream is set. Set a default upstream with \"git branch -u <remote>/<remote_branch_name>\""
|
||||||
|
fi
|
||||||
|
git push
|
||||||
|
UPSTREAM_REMOTE="$(git rev-parse --abbrev-ref --symbolic-full-name @{u} | cut -d/ -f1)"
|
||||||
|
PUSH_REMOTE_URL="$(git remote get-url "$UPSTREAM_REMOTE")"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
CUR_REV="$(git -C "$CUR_REPO_ROOT" rev-parse HEAD)"
|
||||||
|
|
||||||
|
# --- choose URL to write into fetchGit ---
|
||||||
|
if [ "$MODE_FORCE" = "local" ]; then
|
||||||
|
FETCH_URL="file://$CUR_REPO_ROOT"
|
||||||
|
elif [ "$MODE_FORCE" = "remote" ]; then
|
||||||
|
if [ "$DO_PUSH" -eq 1 ]; then
|
||||||
|
FETCH_URL="$PUSH_REMOTE_URL"
|
||||||
|
elif [ "$ENTRY_EXISTS" -eq 1 ] && [ -n "$EXISTING_URL" ] && is_remote_url "$EXISTING_URL"; then
|
||||||
|
FETCH_URL="$EXISTING_URL"
|
||||||
|
else
|
||||||
|
CUR_ORIGIN="$(git remote get-url origin 2>/dev/null || true)"
|
||||||
|
[ -n "$CUR_ORIGIN" ] && is_remote_url "$CUR_ORIGIN" || die "--make-remote requires a remote url (set origin or use -p remote=URL)"
|
||||||
|
FETCH_URL="$CUR_ORIGIN"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$DO_PUSH" -eq 1 ]; then FETCH_URL="$PUSH_REMOTE_URL"; else FETCH_URL="file://$CUR_REPO_ROOT"; fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- rewrite users.nix or inventory.nix ---
|
||||||
|
python3 - "$MODE" "$FILE" "$FETCH_URL" "$CUR_REV" "$USERNAME" "$DEVTYPE" "$HOSTKEY" <<'PY'
|
||||||
|
import sys, re, pathlib
|
||||||
|
|
||||||
|
mode = sys.argv[1]
|
||||||
|
path = pathlib.Path(sys.argv[2])
|
||||||
|
fetch_url = sys.argv[3]
|
||||||
|
rev = sys.argv[4]
|
||||||
|
username = sys.argv[5]
|
||||||
|
devtype = sys.argv[6]
|
||||||
|
hostkey = sys.argv[7]
|
||||||
|
text = path.read_text()
|
||||||
|
|
||||||
|
def find_matching_brace(s: str, start: int) -> int:
|
||||||
|
depth = 0
|
||||||
|
i = start
|
||||||
|
in_str = False
|
||||||
|
while i < len(s):
|
||||||
|
ch = s[i]
|
||||||
|
if in_str:
|
||||||
|
if ch == '\\':
|
||||||
|
i += 2
|
||||||
|
continue
|
||||||
|
if ch == '"':
|
||||||
|
in_str = False
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
if ch == '"':
|
||||||
|
in_str = True
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
if ch == '{':
|
||||||
|
depth += 1
|
||||||
|
elif ch == '}':
|
||||||
|
depth -= 1
|
||||||
|
if depth == 0:
|
||||||
|
return i
|
||||||
|
i += 1
|
||||||
|
raise ValueError("Could not find matching '}'")
|
||||||
|
|
||||||
|
def mk_fetch(entry_indent: str) -> str:
|
||||||
|
# entry_indent is indentation for the whole `"key" = <here>;` line.
|
||||||
|
# The attrset contents should be indented one level deeper.
|
||||||
|
inner = entry_indent + " "
|
||||||
|
return (
|
||||||
|
'builtins.fetchGit {\n'
|
||||||
|
f'{inner}url = "{fetch_url}";\n'
|
||||||
|
f'{inner}rev = "{rev}";\n'
|
||||||
|
f'{inner}submodules = true;\n'
|
||||||
|
f'{entry_indent}}}'
|
||||||
|
)
|
||||||
|
|
||||||
|
def full_hostname(devtype: str, hostkey: str) -> str:
|
||||||
|
if hostkey.startswith(devtype) or "-" in hostkey:
|
||||||
|
return hostkey
|
||||||
|
if hostkey.isdigit():
|
||||||
|
return f"{devtype}{hostkey}"
|
||||||
|
return f"{devtype}-{hostkey}"
|
||||||
|
|
||||||
|
def update_user(t: str) -> str:
|
||||||
|
mblock = re.search(r"(?s)athenix\.users\s*=\s*\{(.*?)\n\s*\};", t)
|
||||||
|
if not mblock:
|
||||||
|
raise SystemExit("error: could not locate `athenix.users = { ... };` block")
|
||||||
|
|
||||||
|
# locate the full span of the users block to edit inside it
|
||||||
|
# (re-find with groups for reconstruction)
|
||||||
|
m2 = re.search(r"(?s)(athenix\.users\s*=\s*\{)(.*?)(\n\s*\};)", t)
|
||||||
|
head, body, tail = m2.group(1), m2.group(2), m2.group(3)
|
||||||
|
|
||||||
|
entry_re = re.search(
|
||||||
|
r"(?s)(\n[ \t]*" + re.escape(username) + r"\.external\s*=\s*)builtins\.fetchGit\s*\{",
|
||||||
|
body
|
||||||
|
)
|
||||||
|
if entry_re:
|
||||||
|
brace = body.rfind("{", 0, entry_re.end())
|
||||||
|
end = find_matching_brace(body, brace)
|
||||||
|
semi = re.match(r"\s*;", body[end+1:])
|
||||||
|
if not semi:
|
||||||
|
raise SystemExit("error: expected ';' after fetchGit attrset")
|
||||||
|
semi_end = end + 1 + semi.end()
|
||||||
|
|
||||||
|
line_start = body.rfind("\n", 0, entry_re.start()) + 1
|
||||||
|
indent = re.match(r"[ \t]*", body[line_start:entry_re.start()]).group(0)
|
||||||
|
|
||||||
|
new_body = body[:entry_re.start()] + entry_re.group(1) + mk_fetch(indent) + ";" + body[semi_end:]
|
||||||
|
else:
|
||||||
|
indent = " "
|
||||||
|
new_body = body + f"\n{indent}{username}.external = {mk_fetch(indent)};\n"
|
||||||
|
|
||||||
|
return t[:m2.start()] + head + new_body + tail + t[m2.end():]
|
||||||
|
|
||||||
|
def update_system(t: str) -> str:
|
||||||
|
# Find devtype block robustly: start-of-file or newline.
|
||||||
|
m = re.search(r"(?s)(^|\n)[ \t]*" + re.escape(devtype) + r"\s*=\s*\{", t)
|
||||||
|
if not m:
|
||||||
|
raise SystemExit(f"error: could not locate `{devtype} = {{ ... }};` block")
|
||||||
|
|
||||||
|
dev_open = t.find("{", m.end() - 1)
|
||||||
|
dev_close = find_matching_brace(t, dev_open)
|
||||||
|
dev = t[dev_open:dev_close+1]
|
||||||
|
|
||||||
|
# Find devices attrset inside dev
|
||||||
|
dm = re.search(r"(?s)(^|\n)[ \t]*devices\s*=\s*\{", dev)
|
||||||
|
if not dm:
|
||||||
|
raise SystemExit(f"error: could not locate `devices = {{ ... }};` inside `{devtype}`")
|
||||||
|
|
||||||
|
devices_open = dev.find("{", dm.end() - 1)
|
||||||
|
devices_close = find_matching_brace(dev, devices_open)
|
||||||
|
devices = dev[devices_open:devices_close+1]
|
||||||
|
|
||||||
|
# indentation for entries in devices
|
||||||
|
# find indent of the 'devices' line, then add 2 spaces
|
||||||
|
|
||||||
|
candidates = [hostkey, full_hostname(devtype, hostkey)]
|
||||||
|
seen = set()
|
||||||
|
candidates = [c for c in candidates if not (c in seen or seen.add(c))]
|
||||||
|
|
||||||
|
for key in candidates:
|
||||||
|
entry = re.search(
|
||||||
|
r'(?s)\n([ ]*)"' + re.escape(key) + r'"\s*=\s*builtins\.fetchGit\s*\{',
|
||||||
|
devices
|
||||||
|
)
|
||||||
|
if entry:
|
||||||
|
entry_indent = entry.group(1)
|
||||||
|
|
||||||
|
# find the '{' we matched
|
||||||
|
brace = devices.find("{", entry.end() - 1)
|
||||||
|
end = find_matching_brace(devices, brace)
|
||||||
|
|
||||||
|
semi = re.match(r"\s*;", devices[end+1:])
|
||||||
|
if not semi:
|
||||||
|
raise SystemExit("error: expected ';' after fetchGit attrset in devices")
|
||||||
|
semi_end = end + 1 + semi.end()
|
||||||
|
|
||||||
|
# Reconstruct the prefix: newline + indent + "key" =
|
||||||
|
prefix = f'\n{entry_indent}"{key}" = '
|
||||||
|
|
||||||
|
new_devices = (
|
||||||
|
devices[:entry.start()]
|
||||||
|
+ prefix
|
||||||
|
+ mk_fetch(entry_indent)
|
||||||
|
+ ";"
|
||||||
|
+ devices[semi_end:]
|
||||||
|
)
|
||||||
|
new_dev = dev[:devices_open] + new_devices + dev[devices_close+1:]
|
||||||
|
|
||||||
|
return t[:dev_open] + new_dev + t[dev_close+1:]
|
||||||
|
|
||||||
|
# Not found: append into devices (exact hostkey)
|
||||||
|
# Indent for new entries: take indent of the closing '}' of devices, add 2 spaces.
|
||||||
|
close_line_start = devices.rfind("\n", 0, len(devices)-1) + 1
|
||||||
|
close_indent = re.match(r"[ ]*", devices[close_line_start:]).group(0)
|
||||||
|
entry_indent = close_indent + " "
|
||||||
|
|
||||||
|
insertion = f'\n{entry_indent}"{hostkey}" = {mk_fetch(entry_indent)};\n'
|
||||||
|
new_devices = devices[:-1].rstrip() + insertion + close_indent + "}"
|
||||||
|
new_dev = dev[:devices_open] + new_devices + dev[devices_close+1:]
|
||||||
|
return t[:dev_open] + new_dev + t[dev_close+1:]
|
||||||
|
|
||||||
|
if mode == "user":
|
||||||
|
out = update_user(text)
|
||||||
|
elif mode == "system":
|
||||||
|
out = update_system(text)
|
||||||
|
else:
|
||||||
|
raise SystemExit("error: unknown mode")
|
||||||
|
|
||||||
|
path.write_text(out)
|
||||||
|
PY
|
||||||
|
|
||||||
|
cd $ATHENIX_DIR
|
||||||
|
nix fmt **/*.nix
|
||||||
|
cd $CUR_REPO_ROOT
|
||||||
|
|
||||||
|
printf "updated %s\n" "$FILE" >&2
|
||||||
|
printf " url = %s\n" "$FETCH_URL" >&2
|
||||||
|
printf " rev = %s\n" "$CUR_REV" >&2
|
||||||
|
'')
|
||||||
|
];
|
||||||
|
}
|
||||||
176
sw/updater.nix
176
sw/updater.nix
@@ -8,7 +8,7 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
{
|
{
|
||||||
options.ugaif.sw.remoteBuild = lib.mkOption {
|
options.athenix.sw.remoteBuild = lib.mkOption {
|
||||||
type = types.submodule {
|
type = types.submodule {
|
||||||
options = {
|
options = {
|
||||||
hosts = mkOption {
|
hosts = mkOption {
|
||||||
@@ -29,31 +29,170 @@ with lib;
|
|||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
ugaif.sw.remoteBuild.enable = lib.mkDefault (config.ugaif.sw.type == "tablet-kiosk");
|
athenix.sw.remoteBuild.enable = lib.mkDefault (config.athenix.sw.type == "tablet-kiosk");
|
||||||
|
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
(pkgs.writeShellScriptBin "update-system" ''
|
(pkgs.writeShellScriptBin "update-system" ''
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
RED='\033[31m'; NC='\033[0m'
|
||||||
|
|
||||||
|
is_root() { [ "''${EUID:-$(id -u)}" -eq 0 ]; }
|
||||||
|
in_wheel() { id -nG 2>/dev/null | tr ' ' '\n' | grep -qx wheel; }
|
||||||
|
|
||||||
|
# Service path for unprivileged (no flags)
|
||||||
UNIT="update-system.service"
|
UNIT="update-system.service"
|
||||||
|
|
||||||
# Start following logs in the background
|
# Figure out the "real" invoking user, even under sudo.
|
||||||
journalctl -fu "$UNIT" -n 0 --output=cat &
|
INVOKER_USER="''${SUDO_USER:-$(id -un)}"
|
||||||
JPID=$!
|
INVOKER_HOME="$(getent passwd "$INVOKER_USER" | cut -d: -f6)"
|
||||||
|
if [ -z "$INVOKER_HOME" ]; then
|
||||||
# Start the service and wait for it to finish
|
# fallback if getent is weird in some containers
|
||||||
if systemctl start --wait --no-ask-password "$UNIT"; then
|
INVOKER_HOME="''${HOME:-/home/$INVOKER_USER}"
|
||||||
STATUS=$?
|
|
||||||
else
|
|
||||||
STATUS=$?
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sleep 2
|
# Defaults for flagged mode
|
||||||
|
DEFAULT_REMOTE_URL="https://git.factory.uga.edu/UGA-Innovation-Factory/athenix"
|
||||||
|
REPO_MODE="default" # default | local | remote
|
||||||
|
LOCAL_PATH=""
|
||||||
|
REMOTE_URL=""
|
||||||
|
BRANCH=""
|
||||||
|
IMPURE=0
|
||||||
|
|
||||||
# Kill the log follower
|
usage() {
|
||||||
kill "$JPID" 2>/dev/null || true
|
cat >&2 <<'EOF'
|
||||||
|
usage:
|
||||||
|
update-system
|
||||||
|
update-system [--local-repo[=PATH]] [--remote-repo=URL] [--branch=BRANCH] [--impure]
|
||||||
|
|
||||||
exit "$STATUS"
|
notes:
|
||||||
|
- No flags: runs the systemd service (works for unprivileged users via polkit).
|
||||||
|
- Any flags: only allowed for root or wheel (runs nixos-rebuild directly).
|
||||||
|
EOF
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
# No flags -> polkit-friendly systemd service route
|
||||||
|
if [ "$#" -eq 0 ]; then
|
||||||
|
journalctl -fu "$UNIT" -n 0 --output=cat &
|
||||||
|
JPID=$!
|
||||||
|
|
||||||
|
if systemctl start --wait --no-ask-password "$UNIT"; then
|
||||||
|
STATUS=$?
|
||||||
|
else
|
||||||
|
STATUS=$?
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
kill "$JPID" 2>/dev/null || true
|
||||||
|
exit "$STATUS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Flags -> require root or wheel
|
||||||
|
if ! is_root && ! in_wheel; then
|
||||||
|
printf "''${RED}error:''${NC} flags are only allowed for root or wheel. Run without flags (service path), or use sudo / add yourself to wheel.\n" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Parse flags
|
||||||
|
while [ "$#" -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--local-repo)
|
||||||
|
REPO_MODE="local"
|
||||||
|
LOCAL_PATH="$INVOKER_HOME/athenix"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--local-repo=*)
|
||||||
|
REPO_MODE="local"
|
||||||
|
LOCAL_PATH="''${1#*=}"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--remote-repo=*)
|
||||||
|
REPO_MODE="remote"
|
||||||
|
REMOTE_URL="''${1#*=}"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--branch)
|
||||||
|
[ "$#" -ge 2 ] || usage
|
||||||
|
BRANCH="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--branch=*)
|
||||||
|
BRANCH="''${1#*=}"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--impure)
|
||||||
|
IMPURE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help) usage ;;
|
||||||
|
*)
|
||||||
|
printf "''${RED}error:''${NC} unknown argument: %s\n" "$1" >&2
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$REPO_MODE" = "local" ] && [ -n "$REMOTE_URL" ]; then
|
||||||
|
printf "''${RED}error:''${NC} can't use --local-repo and --remote-repo together.\n" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
host="''${HOSTNAME:-$(hostname)}"
|
||||||
|
|
||||||
|
# Build flake ref
|
||||||
|
if [ "$REPO_MODE" = "local" ]; then
|
||||||
|
[ -n "$LOCAL_PATH" ] || LOCAL_PATH="$INVOKER_HOME/athenix"
|
||||||
|
|
||||||
|
# Clone default repo if missing
|
||||||
|
if [ ! -d "$LOCAL_PATH" ]; then
|
||||||
|
printf "local repo not found at %s, cloning %s...\n" "$LOCAL_PATH" "$DEFAULT_REMOTE_URL" >&2
|
||||||
|
if [ -n "$BRANCH" ]; then
|
||||||
|
git clone --branch "$BRANCH" "$DEFAULT_REMOTE_URL" "$LOCAL_PATH"
|
||||||
|
else
|
||||||
|
git clone "$DEFAULT_REMOTE_URL" "$LOCAL_PATH"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
flakeRef="''${LOCAL_PATH}#''${host}"
|
||||||
|
else
|
||||||
|
url="''${REMOTE_URL:-$DEFAULT_REMOTE_URL}"
|
||||||
|
|
||||||
|
if echo "$url" | grep -qE '^(https?|ssh)://'; then
|
||||||
|
base="git+''${url}"
|
||||||
|
elif echo "$url" | grep -qE '^[^/@:]+@[^/:]+:'; then
|
||||||
|
# scp-style: git@host:owner/repo(.git)
|
||||||
|
userhost="''${url%%:*}"
|
||||||
|
path="''${url#*:}"
|
||||||
|
base="git+ssh://''${userhost}/''${path}"
|
||||||
|
else
|
||||||
|
base="''${url}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$BRANCH" ]; then
|
||||||
|
if echo "$base" | grep -q '?'; then
|
||||||
|
base="''${base}&ref=''${BRANCH}"
|
||||||
|
else
|
||||||
|
base="''${base}?ref=''${BRANCH}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
flakeRef="''${base}#''${host}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
impureFlag=""
|
||||||
|
if [ "$IMPURE" -eq 1 ]; then
|
||||||
|
impureFlag="--impure"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If not root, re-exec via sudo to do the actual switch.
|
||||||
|
# Preserve our computed invoker context so sudo doesn't "helpfully" change it.
|
||||||
|
if ! is_root; then
|
||||||
|
exec sudo --preserve-env=HOME,USER,LOGNAME \
|
||||||
|
nixos-rebuild switch --refresh --print-build-logs $impureFlag --flake "$flakeRef"
|
||||||
|
else
|
||||||
|
exec nixos-rebuild switch --refresh --print-build-logs $impureFlag --flake "$flakeRef"
|
||||||
|
fi
|
||||||
'')
|
'')
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -69,11 +208,12 @@ with lib;
|
|||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
ExecStart =
|
ExecStart =
|
||||||
let
|
let
|
||||||
hosts = config.ugaif.sw.remoteBuild.hosts;
|
hosts = config.athenix.sw.remoteBuild.hosts;
|
||||||
builders = lib.strings.concatMapStringsSep ";" (x: x) hosts;
|
builders = lib.strings.concatMapStringsSep ";" (x: x) hosts;
|
||||||
rebuildCmd = "${pkgs.nixos-rebuild}/bin/nixos-rebuild switch --refresh";
|
rebuildCmd = "${pkgs.nixos-rebuild}/bin/nixos-rebuild switch --refresh";
|
||||||
source = "--flake github:UGA-Innovation-Factory/nixos-systems";
|
source = "--flake git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix";
|
||||||
remoteBuildFlags = if config.ugaif.sw.remoteBuild.enable then ''--builders "${builders}"'' else "";
|
remoteBuildFlags =
|
||||||
|
if config.athenix.sw.remoteBuild.enable then ''--builders "${builders}"'' else "";
|
||||||
in
|
in
|
||||||
"${rebuildCmd} ${remoteBuildFlags} --print-build-logs ${source}#${config.networking.hostName}";
|
"${rebuildCmd} ${remoteBuildFlags} --print-build-logs ${source}#${config.networking.hostName}";
|
||||||
User = "root";
|
User = "root";
|
||||||
|
|||||||
@@ -94,6 +94,6 @@ Your `default.nix` must:
|
|||||||
|
|
||||||
External modules are automatically integrated into the nixos-systems build:
|
External modules are automatically integrated into the nixos-systems build:
|
||||||
- They receive the same flake inputs (nixpkgs, home-manager, etc.)
|
- They receive the same flake inputs (nixpkgs, home-manager, etc.)
|
||||||
- They can use ugaif.* options if defined in the host type
|
- They can use athenix.* options if defined in the host type
|
||||||
- They are merged with local overrides and base configuration
|
- They are merged with local overrides and base configuration
|
||||||
- They work with all build methods (ISO, LXC, Proxmox, etc.)
|
- They work with all build methods (ISO, LXC, Proxmox, etc.)
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
# Example: Configure services
|
# Example: Configure services
|
||||||
# services.openssh.enable = true;
|
# services.openssh.enable = true;
|
||||||
|
|
||||||
# Example: Use ugaif options if available from nixos-systems
|
# Example: Use athenix options if available from nixos-systems
|
||||||
# ugaif.users.myuser.enable = true;
|
# athenix.users.myuser.enable = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ user-dotfiles-repo/
|
|||||||
└── vimrc
|
└── vimrc
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** The `user.nix` file is required for a functional user module. It should contain both `ugaif.users.<username>` options and home-manager configuration.
|
**Note:** The `user.nix` file is required for a functional user module. It should contain both `athenix.users.<username>` options and home-manager configuration.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ Copy the templates from this directory to your own Git repository:
|
|||||||
|
|
||||||
```nix
|
```nix
|
||||||
{
|
{
|
||||||
ugaif.users = {
|
athenix.users = {
|
||||||
# Option 1: Define inline (without external module)
|
# Option 1: Define inline (without external module)
|
||||||
inlineuser = {
|
inlineuser = {
|
||||||
description = "My Name";
|
description = "My Name";
|
||||||
@@ -42,7 +42,7 @@ Copy the templates from this directory to your own Git repository:
|
|||||||
};
|
};
|
||||||
|
|
||||||
# Option 2: Use external module (recommended for personal configs)
|
# Option 2: Use external module (recommended for personal configs)
|
||||||
# The external user.nix will set ugaif.users.myusername options
|
# The external user.nix will set athenix.users.myusername options
|
||||||
myusername.external = builtins.fetchGit {
|
myusername.external = builtins.fetchGit {
|
||||||
url = "https://github.com/username/dotfiles";
|
url = "https://github.com/username/dotfiles";
|
||||||
rev = "abc123def456..."; # Full commit hash for reproducibility
|
rev = "abc123def456..."; # Full commit hash for reproducibility
|
||||||
@@ -64,7 +64,7 @@ Enable the user in `inventory.nix`:
|
|||||||
"my-system" = {
|
"my-system" = {
|
||||||
devices = {
|
devices = {
|
||||||
"hostname" = {
|
"hostname" = {
|
||||||
ugaif.users.myusername.enable = true;
|
athenix.users.myusername.enable = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -77,12 +77,12 @@ Enable the user in `inventory.nix`:
|
|||||||
|
|
||||||
This file serves a dual purpose and is imported in **two contexts**:
|
This file serves a dual purpose and is imported in **two contexts**:
|
||||||
|
|
||||||
1. **NixOS Module Context**: Imported to read `ugaif.users.<username>` options that define the user account (description, shell, groups, SSH keys, etc.)
|
1. **NixOS Module Context**: Imported to read `athenix.users.<username>` options that define the user account (description, shell, groups, SSH keys, etc.)
|
||||||
2. **Home-Manager Context**: Imported to configure the user environment with `home.*`, `programs.*`, and `services.*` options
|
2. **Home-Manager Context**: Imported to configure the user environment with `home.*`, `programs.*`, and `services.*` options
|
||||||
|
|
||||||
**How it works:**
|
**How it works:**
|
||||||
- The same file is evaluated twice in different contexts
|
- The same file is evaluated twice in different contexts
|
||||||
- User account options (`ugaif.users.<username>`) are read during NixOS evaluation
|
- User account options (`athenix.users.<username>`) are read during NixOS evaluation
|
||||||
- Home-manager options are used when building the user's environment
|
- Home-manager options are used when building the user's environment
|
||||||
- External module options override any defaults set in `users.nix`
|
- External module options override any defaults set in `users.nix`
|
||||||
- You can conditionally include packages/config based on system type using `osConfig`
|
- You can conditionally include packages/config based on system type using `osConfig`
|
||||||
@@ -118,7 +118,7 @@ This file contains system-level NixOS configuration. Only needed for:
|
|||||||
{ config, lib, pkgs, osConfig ? null, ... }:
|
{ config, lib, pkgs, osConfig ? null, ... }:
|
||||||
{
|
{
|
||||||
# User account options
|
# User account options
|
||||||
ugaif.users.myuser = {
|
athenix.users.myuser = {
|
||||||
description = "My Name";
|
description = "My Name";
|
||||||
shell = pkgs.zsh;
|
shell = pkgs.zsh;
|
||||||
hashedPassword = "!";
|
hashedPassword = "!";
|
||||||
@@ -150,7 +150,7 @@ This file contains system-level NixOS configuration. Only needed for:
|
|||||||
{ inputs, ... }:
|
{ inputs, ... }:
|
||||||
{ config, lib, pkgs, osConfig ? null, ... }:
|
{ config, lib, pkgs, osConfig ? null, ... }:
|
||||||
{
|
{
|
||||||
ugaif.users.myuser = {
|
athenix.users.myuser = {
|
||||||
description = "My Name";
|
description = "My Name";
|
||||||
shell = pkgs.zsh;
|
shell = pkgs.zsh;
|
||||||
hashedPassword = "!";
|
hashedPassword = "!";
|
||||||
@@ -162,7 +162,7 @@ This file contains system-level NixOS configuration. Only needed for:
|
|||||||
ripgrep
|
ripgrep
|
||||||
fd
|
fd
|
||||||
bat
|
bat
|
||||||
] ++ lib.optional (osConfig.ugaif.sw.type or null == "desktop") firefox;
|
] ++ lib.optional (osConfig.athenix.sw.type or null == "desktop") firefox;
|
||||||
|
|
||||||
# Symlink dotfiles
|
# Symlink dotfiles
|
||||||
home.file.".bashrc".source = ./config/bashrc;
|
home.file.".bashrc".source = ./config/bashrc;
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
# User Configuration
|
# User Configuration
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# This file configures BOTH:
|
# This file configures BOTH:
|
||||||
# 1. User account options (ugaif.users.<username>)
|
# 1. User account options (athenix.users.<username>)
|
||||||
# 2. Home-manager configuration (home.*, programs.*, services.*)
|
# 2. Home-manager configuration (home.*, programs.*, services.*)
|
||||||
#
|
#
|
||||||
# The same file is imported in two contexts:
|
# The same file is imported in two contexts:
|
||||||
# - As a NixOS module to read ugaif.users.<username> options
|
# - As a NixOS module to read athenix.users.<username> options
|
||||||
# - As a home-manager module for user environment configuration
|
# - As a home-manager module for user environment configuration
|
||||||
#
|
#
|
||||||
# This module receives the same `inputs` flake inputs as the main
|
# This module receives the same `inputs` flake inputs as the main
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
# ========== User Account Configuration ==========
|
# ========== User Account Configuration ==========
|
||||||
# Replace "myusername" with your actual username
|
# Replace "myusername" with your actual username
|
||||||
|
|
||||||
ugaif.users.myusername = {
|
athenix.users.myusername = {
|
||||||
description = "Your Full Name";
|
description = "Your Full Name";
|
||||||
shell = pkgs.zsh;
|
shell = pkgs.zsh;
|
||||||
hashedPassword = "!"; # Locked password - use SSH keys only
|
hashedPassword = "!"; # Locked password - use SSH keys only
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
# Note: You don't need to set 'enable = true' - that's controlled
|
# Note: You don't need to set 'enable = true' - that's controlled
|
||||||
# per-host in inventory.nix via ugaif.users.myusername.enable
|
# per-host in inventory.nix via athenix.users.myusername.enable
|
||||||
|
|
||||||
# ========== Home Manager Configuration ==========
|
# ========== Home Manager Configuration ==========
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
fd
|
fd
|
||||||
bat
|
bat
|
||||||
]
|
]
|
||||||
++ lib.optional (osConfig.ugaif.sw.type or null == "desktop") firefox;
|
++ lib.optional (osConfig.athenix.sw.type or null == "desktop") firefox;
|
||||||
# Conditionally add packages based on system type
|
# Conditionally add packages based on system type
|
||||||
|
|
||||||
# ========== Programs ==========
|
# ========== Programs ==========
|
||||||
|
|||||||
10
users.nix
10
users.nix
@@ -5,7 +5,7 @@
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
# This file defines the available user accounts. These accounts are NOT
|
# This file defines the available user accounts. These accounts are NOT
|
||||||
# enabled by default on all systems. They must be enabled via the
|
# enabled by default on all systems. They must be enabled via the
|
||||||
# 'ugaif.users.enabledUsers' option in inventory.nix or system flakes.
|
# 'athenix.users.enabledUsers' option in inventory.nix or system flakes.
|
||||||
|
|
||||||
# Define the users here using the new option
|
# Define the users here using the new option
|
||||||
# To generate a password hash, run: mkpasswd -m sha-512
|
# To generate a password hash, run: mkpasswd -m sha-512
|
||||||
@@ -17,16 +17,16 @@
|
|||||||
# external = /path/to/local/config;
|
# external = /path/to/local/config;
|
||||||
#
|
#
|
||||||
# External repositories should contain:
|
# External repositories should contain:
|
||||||
# - user.nix (required): Defines ugaif.users.<name> options AND home-manager config
|
# - user.nix (required): Defines athenix.users.<name> options AND home-manager config
|
||||||
# - nixos.nix (optional): System-level NixOS configuration
|
# - nixos.nix (optional): System-level NixOS configuration
|
||||||
#
|
#
|
||||||
# The user.nix file is imported in TWO contexts:
|
# The user.nix file is imported in TWO contexts:
|
||||||
# 1. As a NixOS module to read ugaif.users.<name> options (account settings)
|
# 1. As a NixOS module to read athenix.users.<name> options (account settings)
|
||||||
# 2. As a home-manager module for home.*, programs.*, services.* (user environment)
|
# 2. As a home-manager module for home.*, programs.*, services.* (user environment)
|
||||||
#
|
#
|
||||||
# User options can be set in users.nix OR in the external module's user.nix.
|
# User options can be set in users.nix OR in the external module's user.nix.
|
||||||
# External module options take precedence over users.nix defaults.
|
# External module options take precedence over users.nix defaults.
|
||||||
ugaif.users = {
|
athenix.users = {
|
||||||
root = {
|
root = {
|
||||||
isNormalUser = false;
|
isNormalUser = false;
|
||||||
hashedPassword = "!";
|
hashedPassword = "!";
|
||||||
@@ -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 = "db96137bb4cb16acefcf59d58c9f848924f2ad43";
|
rev = "c538e0c0510045b58264627bb897fc499dc7c490";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
sv22900 = {
|
sv22900 = {
|
||||||
|
|||||||
Reference in New Issue
Block a user