Compare commits
36 Commits
main
...
5a8147401b
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a8147401b | |||
| 276e7a02a6 | |||
| ab969fe5de | |||
| 81732aef84 | |||
| 0f9b639c0d | |||
| d43452a8d3 | |||
| 64d22473c3 | |||
| 3f24669f78 | |||
| d0b00ada96 | |||
| fc834168aa | |||
| 119eadbfb8 | |||
| ebd61ee60d | |||
| 12f3abc11e | |||
| eef8e37fbb | |||
| 1654aef9ae | |||
| f16d041e63 | |||
| b61b8e3abf | |||
| a55592f59e | |||
| 09aee329cf | |||
| 71570edeaa | |||
| 276e4a3172 | |||
| 8493f12829 | |||
| 720ebdba63 | |||
| 9f01253d92 | |||
| 0c4e4df772 | |||
| 597dbd4369 | |||
| 1e9f1bf907 | |||
| f3494be6cc | |||
| 8cc171974a | |||
| 3c3d9d80f2 | |||
| 4c40aa12a7 | |||
| a8aa5b6fb5 | |||
| 41b9d41776 | |||
| 4a422599c7 | |||
| 5185abd8a2 | |||
| 828cc15129 |
@@ -4,13 +4,16 @@ One flake builds every machine I own.
|
|||||||
|
|
||||||
## Repository Conventions
|
## Repository Conventions
|
||||||
|
|
||||||
- Follow `docs/technical-writing.md` for comments, user-facing descriptions, commit prose, pull-request prose, and Markdown documentation.
|
- Use `docs/technical-writing.md` and `docs/dictionary.md` while authoring any file.
|
||||||
|
Apply them to comments, user-facing descriptions, commit prose, pull-request prose, and Markdown documentation.
|
||||||
- Comments posted to the forge under the operator's account must end with `— Pi`.
|
- Comments posted to the forge under the operator's account must end with `— Pi`.
|
||||||
The sign-off identifies the agent as the author instead of the operator.
|
The sign-off identifies the agent as the author instead of the operator.
|
||||||
- Commit messages follow Conventional Commits, defined in `docs/conventional-commits.md`.
|
- Commit messages follow Conventional Commits, defined in `docs/conventional-commits.md`.
|
||||||
Use a scope for the changed module or host, such as `fish`, `nvim`, or `neogaia`.
|
Use a scope for the changed module or host, such as `fish`, `nvim`, or `neogaia`.
|
||||||
- Keep commit messages about the Git history, not the forge workflow.
|
- Keep commit messages about the Git history, not the forge workflow.
|
||||||
Do not reference issue or pull-request numbers unless the commit itself requires a stable external reference.
|
Do not reference issue or pull-request numbers unless the commit itself requires a stable external reference.
|
||||||
|
- During pull-request development, add follow-up commits instead of amending existing commits.
|
||||||
|
Preserve review history until the pull request is ready to merge.
|
||||||
- Use `gitea-axi` for Gitea issues, pull requests, labels, reviews, comments, and milestones.
|
- Use `gitea-axi` for Gitea issues, pull requests, labels, reviews, comments, and milestones.
|
||||||
It resolves this repository from the `origin` remote inside the checkout.
|
It resolves this repository from the `origin` remote inside the checkout.
|
||||||
|
|
||||||
@@ -66,7 +69,7 @@ One flake builds every machine I own.
|
|||||||
- Guest modules are host-agnostic wiring, while host files own deployment-specific service configuration such as served volumes and host paths.
|
- Guest modules are host-agnostic wiring, while host files own deployment-specific service configuration such as served volumes and host paths.
|
||||||
For example, `guests/copyparty.nix` should expose options and translate them into guest mounts/service settings, while `hosts/pikachu/default.nix` chooses `/inbox`, `/media`, and their backing paths.
|
For example, `guests/copyparty.nix` should expose options and translate them into guest mounts/service settings, while `hosts/pikachu/default.nix` chooses `/inbox`, `/media`, and their backing paths.
|
||||||
Guest addresses and routes are host-level configuration because a guest module can be used on multiple hosts.
|
Guest addresses and routes are host-level configuration because a guest module can be used on multiple hosts.
|
||||||
- `self.lib.registry.collect { hosts = self.nixosConfigurations; }` reads only top-level host `config.registry` declarations.
|
- The registry collector reads only top-level host `config.registry` declarations.
|
||||||
Registry declarations inside guest interiors live under `config.containers.<guest>.config.registry`.
|
Registry declarations inside guest interiors live under `config.containers.<guest>.config.registry`.
|
||||||
The collected registry does not include those guest-interior declarations.
|
The collected registry does not include those guest-interior declarations.
|
||||||
Publish guest values from host-side code, or extend the collector to recurse into guests.
|
Publish guest values from host-side code, or extend the collector to recurse into guests.
|
||||||
|
|||||||
@@ -45,11 +45,15 @@ Use the simplest accurate word when a term is not listed.
|
|||||||
| operator | Agent tooling | The human driving the development process. Use when distinguishing the human from the agent acting on their behalf. |
|
| operator | Agent tooling | The human driving the development process. Use when distinguishing the human from the agent acting on their behalf. |
|
||||||
| guest | dotfiles | A systemd-nspawn container managed by this flake. Use for configured containers under `guests/`. |
|
| guest | dotfiles | A systemd-nspawn container managed by this flake. Use for configured containers under `guests/`. |
|
||||||
| host | dotfiles | A machine with a NixOS configuration built by this flake. |
|
| host | dotfiles | A machine with a NixOS configuration built by this flake. |
|
||||||
| module | dotfiles | In this repository, a self-contained configuration under `modules/`, usually scoped to one program, service, or subsystem. Use `Nix module` for the language-level module-system concept. |
|
| module | dotfiles | In this repository, a self-contained configuration under `modules/`. Use for one program, service, or subsystem. |
|
||||||
| registry | dotfiles | A typed configuration namespace whose entries can be collected across hosts and reused by other configuration. |
|
| registry | dotfiles | A typed configuration namespace whose entries can be collected across hosts and reused by other configuration. |
|
||||||
| Conventional Commits | Git | A commit-message format defined in `docs/conventional-commits.md`. |
|
| Conventional Commits | Git | A commit-message format defined in `docs/conventional-commits.md`. |
|
||||||
| forge | Git | A web service that hosts Git repositories, pull requests, issues, and code review comments. Use when the exact provider does not matter. |
|
| forge | Git | A web service that hosts Git repositories, pull requests, issues, and code review comments. Use when the exact provider does not matter. |
|
||||||
| flake | Nix | A Nix project with pinned inputs and declared outputs. Use for the repository-level build unit defined by `flake.nix`. |
|
| flake | Nix | A Nix project with pinned inputs and declared outputs. Use for the repository-level build unit defined by `flake.nix`. |
|
||||||
| Nix module | Nix | A Nix language unit that declares or sets options through the Nix module system. |
|
| assembly file | Nix | A Nix file under `flake/` that constructs flake outputs or arguments passed to NixOS modules. |
|
||||||
|
| assembly function | Nix | A project function exposed under `flake` because it creates modules, systems, or assembly values. |
|
||||||
|
| library file | Nix | A Nix file that defines reusable project functions instead of a NixOS module or flake output. |
|
||||||
|
| library function | Nix | A pure project function exposed under `flake.util`. |
|
||||||
|
| NixOS module | Nix | A Nix file evaluated by `nixosSystem` for a NixOS configuration. |
|
||||||
| overlay | Nix | A function that modifies a Nix package set by adding or replacing packages. |
|
| overlay | Nix | A function that modifies a Nix package set by adding or replacing packages. |
|
||||||
| workspace | Window management | A named or numbered group of windows in a graphical session. Some desktop environments call this a virtual desktop. |
|
| workspace | Window management | A named or numbered group of windows in a graphical session. Some desktop environments call this a virtual desktop. |
|
||||||
|
|||||||
270
docs/nix.md
Normal file
270
docs/nix.md
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
# Nix Conventions
|
||||||
|
|
||||||
|
This document records local Nix style and design conventions.
|
||||||
|
Use these conventions when changing this flake.
|
||||||
|
Read this document with `docs/dictionary.md`.
|
||||||
|
|
||||||
|
## Names
|
||||||
|
|
||||||
|
### Reserve `lib` for `nixpkgs.lib`
|
||||||
|
|
||||||
|
Use `lib` only for the base `nixpkgs.lib` value.
|
||||||
|
Do not use `lib` for project functions.
|
||||||
|
Use `flake.util` for library functions passed through module arguments.
|
||||||
|
Use `flake.mk<Name>` for assembly functions passed through module arguments.
|
||||||
|
|
||||||
|
Avoid:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
specialArgs = {
|
||||||
|
lib = util;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
specialArgs = {
|
||||||
|
inherit flake;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Then call project functions through `flake` inside modules:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
flake,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
networking.networkmanager.unmanaged = [ "interface-name:${flake.util.bridgeName 10}" ];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Name project function namespaces by role
|
||||||
|
|
||||||
|
Put pure project functions under `flake.util`.
|
||||||
|
Put functions that create modules, systems, or assembly values under `flake`.
|
||||||
|
This keeps data-only functions separate from functions that carry flake context.
|
||||||
|
|
||||||
|
Avoid:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
flake.util.mkGuest { name = "sample"; }
|
||||||
|
```
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
flake.mkGuest { name = "sample"; }
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Placement
|
||||||
|
|
||||||
|
### Put files in the directory that owns their role
|
||||||
|
|
||||||
|
Choose the file location before writing a Nix file.
|
||||||
|
Put assembly files under `flake/`.
|
||||||
|
Put library files under `lib/`.
|
||||||
|
Put modules under `modules/`.
|
||||||
|
Put host configurations under `hosts/<name>/`.
|
||||||
|
Put host-side guest wiring under `guests/`.
|
||||||
|
Put registry definitions under `registry/`.
|
||||||
|
Keep `flake.nix` focused on inputs and output wiring.
|
||||||
|
Do not add root-level Nix files other than `flake.nix`.
|
||||||
|
|
||||||
|
A module is self-contained configuration under `modules/`.
|
||||||
|
A module configures one program, service, or subsystem.
|
||||||
|
Files under `hosts/`, `guests/`, and `modules/` return NixOS modules.
|
||||||
|
|
||||||
|
### Use `default.nix` for module directories with support files
|
||||||
|
|
||||||
|
Use `default.nix` as the primary module when a module directory owns support files.
|
||||||
|
Keep sibling files for data or code read by that primary module.
|
||||||
|
|
||||||
|
Avoid:
|
||||||
|
|
||||||
|
```text
|
||||||
|
modules/shell/fish/fish.nix
|
||||||
|
modules/shell/fish/config.fish
|
||||||
|
```
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
```text
|
||||||
|
modules/shell/fish/default.nix
|
||||||
|
modules/shell/fish/config.fish
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use non-module `default.nix` files only for directory assembly
|
||||||
|
|
||||||
|
Outside `modules/`, use `default.nix` to connect files in its directory.
|
||||||
|
Do not define primary assembly functions in `default.nix`.
|
||||||
|
Put primary assembly functions in named files.
|
||||||
|
|
||||||
|
Avoid:
|
||||||
|
|
||||||
|
```text
|
||||||
|
flake/default.nix # defines mkHost
|
||||||
|
```
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
```text
|
||||||
|
flake/default.nix # imports ./hosts.nix
|
||||||
|
flake/hosts.nix # defines mkHosts
|
||||||
|
```
|
||||||
|
|
||||||
|
### Keep assembly files focused on one concept
|
||||||
|
|
||||||
|
Give each assembly file under `flake/` one top-level concept.
|
||||||
|
Keep helper functions private to that file when no other file needs them.
|
||||||
|
Export the constructor for the concept when the concept has one.
|
||||||
|
Name that constructor `mk<Concept>`.
|
||||||
|
|
||||||
|
Avoid:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
inherit collectNixFiles mkHost mkHosts;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
inherit mkHosts;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Function Arguments
|
||||||
|
|
||||||
|
### Use closed interfaces for assembly files and library files
|
||||||
|
|
||||||
|
Use exact function argument patterns for assembly files and library files.
|
||||||
|
The caller owns the argument set for these files.
|
||||||
|
The imported file names each accepted attribute.
|
||||||
|
The imported file rejects stale or accidental extra attributes.
|
||||||
|
|
||||||
|
Avoid:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
inputs,
|
||||||
|
lib,
|
||||||
|
self,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
```
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
inputs,
|
||||||
|
lib,
|
||||||
|
self,
|
||||||
|
}:
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pass function arguments explicitly
|
||||||
|
|
||||||
|
Pass only the values an assembly file or library file needs.
|
||||||
|
Bind `lib` to the base `nixpkgs.lib` value at the call site.
|
||||||
|
Use `inherit` only for values that keep the same name.
|
||||||
|
|
||||||
|
Avoid:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
import ./flake inputs
|
||||||
|
```
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
let
|
||||||
|
inherit (nixpkgs) lib;
|
||||||
|
in
|
||||||
|
import ./flake { inherit lib inputs self; }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Keep NixOS module interfaces open
|
||||||
|
|
||||||
|
Files under `hosts/`, `guests/`, and `modules/` return NixOS modules.
|
||||||
|
`nixosSystem` owns their argument shape.
|
||||||
|
Name each argument the module uses.
|
||||||
|
Keep `...` so the module accepts standard arguments and special arguments.
|
||||||
|
|
||||||
|
Avoid:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
registry,
|
||||||
|
}:
|
||||||
|
```
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
registry,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
```
|
||||||
|
|
||||||
|
## `let` Bindings
|
||||||
|
|
||||||
|
### Use role-specific binding names
|
||||||
|
|
||||||
|
A `let` binding name must explain the value's role in the expression.
|
||||||
|
Avoid names that describe only the value's type.
|
||||||
|
|
||||||
|
Avoid:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
let
|
||||||
|
names = lib.attrNames hosts;
|
||||||
|
in
|
||||||
|
lib.genAttrs names mkHost
|
||||||
|
```
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
let
|
||||||
|
hostNames = lib.attrNames hosts;
|
||||||
|
in
|
||||||
|
lib.genAttrs hostNames mkHost
|
||||||
|
```
|
||||||
|
|
||||||
|
## Standard Library Calls
|
||||||
|
|
||||||
|
### Qualify standard library calls in flake assembly
|
||||||
|
|
||||||
|
Use qualified standard library calls inside assembly files.
|
||||||
|
Use `lib.mapAttrs` instead of inheriting `mapAttrs` from `lib`.
|
||||||
|
This keeps the source of each function visible.
|
||||||
|
|
||||||
|
Avoid:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
let
|
||||||
|
inherit (lib) mapAttrs;
|
||||||
|
in
|
||||||
|
mapAttrs f attrs
|
||||||
|
```
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
lib.mapAttrs f attrs
|
||||||
|
```
|
||||||
|
|
||||||
@@ -76,14 +76,13 @@
|
|||||||
{ self, nixpkgs, ... }@inputs:
|
{ self, nixpkgs, ... }@inputs:
|
||||||
let
|
let
|
||||||
inherit (nixpkgs) lib;
|
inherit (nixpkgs) lib;
|
||||||
my = import ./lib { inherit lib inputs self; };
|
flake = import ./flake { inherit lib inputs self; };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# Helper functions for discovering and building hosts.
|
|
||||||
lib = my;
|
|
||||||
|
|
||||||
# Every host under hosts/ is discovered and built.
|
# Every host under hosts/ is discovered and built.
|
||||||
nixosConfigurations = my.mkHosts (self + "/hosts");
|
nixosConfigurations = flake.mkHosts {
|
||||||
|
root = self + "/hosts";
|
||||||
|
};
|
||||||
|
|
||||||
# A project shell for agent-local resources that should travel with this
|
# A project shell for agent-local resources that should travel with this
|
||||||
# checkout rather than the operator's global profile.
|
# checkout rather than the operator's global profile.
|
||||||
|
|||||||
61
flake/default.nix
Normal file
61
flake/default.nix
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
inputs,
|
||||||
|
self,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
# TODO: refactor the registry code
|
||||||
|
registryAssembly = import ./registry.nix { inherit lib self; };
|
||||||
|
|
||||||
|
util = import ../lib { inherit lib; };
|
||||||
|
mkModules = import ./module.nix { inherit util; };
|
||||||
|
|
||||||
|
modules = mkModules {
|
||||||
|
root = self + "/modules";
|
||||||
|
};
|
||||||
|
|
||||||
|
#----------------------------------------------------------
|
||||||
|
guestFiles = util.collectNixFiles (self + "/guests");
|
||||||
|
|
||||||
|
collectedRegistry = registryAssembly.collect { hosts = self.nixosConfigurations; };
|
||||||
|
|
||||||
|
specialArgs = {
|
||||||
|
inherit
|
||||||
|
flake
|
||||||
|
inputs
|
||||||
|
self
|
||||||
|
;
|
||||||
|
registry = collectedRegistry;
|
||||||
|
};
|
||||||
|
|
||||||
|
flake = {
|
||||||
|
inherit (hosts) mkHosts;
|
||||||
|
inherit (guests) mkGuest;
|
||||||
|
|
||||||
|
inherit util;
|
||||||
|
};
|
||||||
|
|
||||||
|
guests = import ./guest.nix {
|
||||||
|
inherit
|
||||||
|
inputs
|
||||||
|
lib
|
||||||
|
self
|
||||||
|
specialArgs
|
||||||
|
registryAssembly
|
||||||
|
util
|
||||||
|
;
|
||||||
|
repositoryModules = modules;
|
||||||
|
};
|
||||||
|
|
||||||
|
hosts = import ./host.nix {
|
||||||
|
inherit
|
||||||
|
inputs
|
||||||
|
lib
|
||||||
|
specialArgs
|
||||||
|
guestFiles
|
||||||
|
registryAssembly
|
||||||
|
;
|
||||||
|
repositoryModules = modules;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
flake
|
||||||
@@ -3,22 +3,12 @@
|
|||||||
lib,
|
lib,
|
||||||
self,
|
self,
|
||||||
specialArgs,
|
specialArgs,
|
||||||
bridgeName,
|
repositoryModules,
|
||||||
moduleFiles,
|
registryAssembly,
|
||||||
registry,
|
util,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) escapeShellArg mapAttrsToList;
|
mkGuest =
|
||||||
|
|
||||||
deriveMac =
|
|
||||||
name:
|
|
||||||
let
|
|
||||||
hash = builtins.hashString "sha256" name;
|
|
||||||
octet = i: builtins.substring (i * 2) 2 hash;
|
|
||||||
in
|
|
||||||
lib.concatStringsSep ":" ([ "02" ] ++ map octet [ 0 1 2 3 4 ]);
|
|
||||||
|
|
||||||
guest =
|
|
||||||
{
|
{
|
||||||
name,
|
name,
|
||||||
interior ? { },
|
interior ? { },
|
||||||
@@ -59,13 +49,13 @@ let
|
|||||||
|
|
||||||
createdMounts = lib.filterAttrs (_guestPath: m: m.create != null) cfg.mounts;
|
createdMounts = lib.filterAttrs (_guestPath: m: m.create != null) cfg.mounts;
|
||||||
mountCreateScript = lib.concatStringsSep "\n" (
|
mountCreateScript = lib.concatStringsSep "\n" (
|
||||||
mapAttrsToList (
|
lib.mapAttrsToList (
|
||||||
_guestPath: m:
|
_guestPath: m:
|
||||||
let
|
let
|
||||||
create = m.create;
|
create = m.create;
|
||||||
in
|
in
|
||||||
''
|
''
|
||||||
${config.system.path}/bin/install -d -o ${escapeShellArg (toString create.owner)} -g ${escapeShellArg create.group} -m ${escapeShellArg create.mode} ${escapeShellArg m.hostPath}
|
${config.system.path}/bin/install -d -o ${lib.escapeShellArg (toString create.owner)} -g ${lib.escapeShellArg create.group} -m ${lib.escapeShellArg create.mode} ${lib.escapeShellArg m.hostPath}
|
||||||
''
|
''
|
||||||
) createdMounts
|
) createdMounts
|
||||||
);
|
);
|
||||||
@@ -113,7 +103,7 @@ let
|
|||||||
};
|
};
|
||||||
mac = lib.mkOption {
|
mac = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = deriveMac name;
|
default = util.deriveMac name;
|
||||||
defaultText = lib.literalMD "a stable address derived from the guest's namespace path";
|
defaultText = lib.literalMD "a stable address derived from the guest's namespace path";
|
||||||
example = "bc:24:11:00:00:01";
|
example = "bc:24:11:00:00:01";
|
||||||
description = ''
|
description = ''
|
||||||
@@ -136,7 +126,7 @@ let
|
|||||||
enable = lib.mkEnableOption "a reverse-proxy route for this guest";
|
enable = lib.mkEnableOption "a reverse-proxy route for this guest";
|
||||||
|
|
||||||
route = lib.mkOption {
|
route = lib.mkOption {
|
||||||
type = self.lib.registry.definitions.route.type;
|
type = registryAssembly.definitions.route.type;
|
||||||
description = "Route registry entry published for this guest.";
|
description = "Route registry entry published for this guest.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -316,7 +306,7 @@ let
|
|||||||
}
|
}
|
||||||
(lib.mkIf networked (
|
(lib.mkIf networked (
|
||||||
let
|
let
|
||||||
bridgeDevice = "sys-subsystem-net-devices-${lib.replaceStrings [ "-" ] [ "\\x2d" ] (bridgeName cfg.vlan)}.device";
|
bridgeDevice = "sys-subsystem-net-devices-${lib.replaceStrings [ "-" ] [ "\\x2d" ] (util.bridgeName cfg.vlan)}.device";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
after = [ bridgeDevice ];
|
after = [ bridgeDevice ];
|
||||||
@@ -329,7 +319,7 @@ let
|
|||||||
containers.${machineName} = lib.mkIf (cfg.backend == "container") {
|
containers.${machineName} = lib.mkIf (cfg.backend == "container") {
|
||||||
autoStart = cfg.autoStart;
|
autoStart = cfg.autoStart;
|
||||||
privateNetwork = lib.mkDefault true;
|
privateNetwork = lib.mkDefault true;
|
||||||
hostBridge = lib.mkIf networked (bridgeName cfg.vlan);
|
hostBridge = lib.mkIf networked (util.bridgeName cfg.vlan);
|
||||||
privateUsers = lib.mkDefault "no";
|
privateUsers = lib.mkDefault "no";
|
||||||
additionalCapabilities = lib.optionals cfg.nesting [ "CAP_NET_ADMIN" ];
|
additionalCapabilities = lib.optionals cfg.nesting [ "CAP_NET_ADMIN" ];
|
||||||
allowedDevices = lib.optionals cfg.nesting [
|
allowedDevices = lib.optionals cfg.nesting [
|
||||||
@@ -349,9 +339,11 @@ let
|
|||||||
|
|
||||||
config = {
|
config = {
|
||||||
imports =
|
imports =
|
||||||
moduleFiles
|
[
|
||||||
|
repositoryModules
|
||||||
|
]
|
||||||
++ [
|
++ [
|
||||||
registry.module
|
registryAssembly.module
|
||||||
inputs.sops-nix.nixosModules.sops
|
inputs.sops-nix.nixosModules.sops
|
||||||
inputs.stylix.nixosModules.stylix
|
inputs.stylix.nixosModules.stylix
|
||||||
{
|
{
|
||||||
@@ -366,5 +358,5 @@ let
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
inherit deriveMac guest;
|
inherit mkGuest;
|
||||||
}
|
}
|
||||||
51
flake/host.nix
Normal file
51
flake/host.nix
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
inputs,
|
||||||
|
lib,
|
||||||
|
specialArgs,
|
||||||
|
repositoryModules,
|
||||||
|
|
||||||
|
# TODO refactor guests
|
||||||
|
guestFiles,
|
||||||
|
# TODO refactor registry
|
||||||
|
registryAssembly,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
mkHost =
|
||||||
|
{
|
||||||
|
root,
|
||||||
|
name,
|
||||||
|
}:
|
||||||
|
lib.nixosSystem {
|
||||||
|
inherit specialArgs;
|
||||||
|
modules =
|
||||||
|
guestFiles
|
||||||
|
++ [
|
||||||
|
inputs.chaotic.nixosModules.default
|
||||||
|
inputs.disko.nixosModules.disko
|
||||||
|
inputs.sops-nix.nixosModules.sops
|
||||||
|
inputs.stylix.nixosModules.stylix
|
||||||
|
|
||||||
|
repositoryModules
|
||||||
|
|
||||||
|
# TODO: refactor
|
||||||
|
registryAssembly.module (root + "/${name}")
|
||||||
|
|
||||||
|
{
|
||||||
|
networking.hostName = name;
|
||||||
|
modules.host.enable = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
mkHosts =
|
||||||
|
{ root }:
|
||||||
|
let
|
||||||
|
directories = lib.filterAttrs (_name: type: type == "directory") (builtins.readDir root);
|
||||||
|
names = lib.attrNames directories;
|
||||||
|
in
|
||||||
|
lib.genAttrs names (
|
||||||
|
name:
|
||||||
|
mkHost { inherit root name; }
|
||||||
|
);
|
||||||
|
}
|
||||||
5
flake/module.nix
Normal file
5
flake/module.nix
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{ util }:
|
||||||
|
{ root }:
|
||||||
|
{
|
||||||
|
imports = util.collectNixFiles root;
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
my,
|
flake,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
@@ -10,7 +10,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
(my.guest {
|
(flake.mkGuest {
|
||||||
name = "actualbudget";
|
name = "actualbudget";
|
||||||
interior = {
|
interior = {
|
||||||
modules.services.actualbudget = {
|
modules.services.actualbudget = {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
my,
|
flake,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
@@ -35,7 +35,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
(my.guest {
|
(flake.mkGuest {
|
||||||
name = "copyparty";
|
name = "copyparty";
|
||||||
interior = {
|
interior = {
|
||||||
modules.services.copyparty = {
|
modules.services.copyparty = {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
args@{ my, ... }:
|
args@{ flake, ... }:
|
||||||
# A sample guest whose interior runs an OCI container on Podman.
|
# A sample guest whose interior runs an OCI container on Podman.
|
||||||
# The image is pulled at runtime, so the guest builds with no build-time fetch.
|
# The image is pulled at runtime, so the guest builds with no build-time fetch.
|
||||||
my.guest {
|
flake.mkGuest {
|
||||||
name = "nesting-sample";
|
name = "nesting-sample";
|
||||||
interior = {
|
interior = {
|
||||||
virtualisation.oci-containers.containers.hello = {
|
virtualisation.oci-containers.containers.hello = {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
my,
|
flake,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
@@ -9,7 +9,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
(my.guest {
|
(flake.mkGuest {
|
||||||
name = "reverse-proxy";
|
name = "reverse-proxy";
|
||||||
interior = {
|
interior = {
|
||||||
modules.services.reverse-proxy.enable = true;
|
modules.services.reverse-proxy.enable = true;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
args@{ my, ... }:
|
args@{ flake, ... }:
|
||||||
# The tracer-bullet guest: the thinnest complete path from discovery to a
|
# The tracer-bullet guest: the thinnest complete path from discovery to a
|
||||||
# running nested container. Its interior is just the guest-base — the baseline
|
# running nested container. Its interior is just the guest-base — the baseline
|
||||||
# toolset and SSH access — so it proves the concept without carrying a service.
|
# toolset and SSH access — so it proves the concept without carrying a service.
|
||||||
my.guest { name = "sample"; } args
|
flake.mkGuest { name = "sample"; } args
|
||||||
|
|||||||
101
lib/default.nix
101
lib/default.nix
@@ -1,100 +1,9 @@
|
|||||||
{
|
{ lib }:
|
||||||
lib,
|
|
||||||
inputs,
|
|
||||||
self,
|
|
||||||
}:
|
|
||||||
let
|
let
|
||||||
inherit (lib)
|
files = import ./files.nix { inherit lib; };
|
||||||
attrNames
|
network = import ./network.nix { inherit lib; };
|
||||||
filterAttrs
|
|
||||||
genAttrs
|
|
||||||
flatten
|
|
||||||
hasSuffix
|
|
||||||
mapAttrsToList
|
|
||||||
;
|
|
||||||
|
|
||||||
registry = import ./registry.nix { inherit lib self; };
|
|
||||||
|
|
||||||
collectNixFiles =
|
|
||||||
dir:
|
|
||||||
flatten (
|
|
||||||
mapAttrsToList (
|
|
||||||
name: type:
|
|
||||||
let
|
|
||||||
path = dir + "/${name}";
|
|
||||||
in
|
|
||||||
if type == "directory" then
|
|
||||||
collectNixFiles path
|
|
||||||
else if type == "regular" && hasSuffix ".nix" name then
|
|
||||||
[ path ]
|
|
||||||
else
|
|
||||||
[ ]
|
|
||||||
) (builtins.readDir dir)
|
|
||||||
);
|
|
||||||
|
|
||||||
moduleFiles = collectNixFiles (self + "/modules");
|
|
||||||
guestFiles = collectNixFiles (self + "/guests");
|
|
||||||
|
|
||||||
specialArgs = {
|
|
||||||
inherit inputs self;
|
|
||||||
my = self.lib;
|
|
||||||
registry = self.lib.registry.collect { hosts = self.nixosConfigurations; };
|
|
||||||
};
|
|
||||||
|
|
||||||
bridgeName = id: "br-vlan${toString id}";
|
|
||||||
|
|
||||||
guests = import ./guests.nix {
|
|
||||||
inherit
|
|
||||||
inputs
|
|
||||||
lib
|
|
||||||
self
|
|
||||||
specialArgs
|
|
||||||
bridgeName
|
|
||||||
moduleFiles
|
|
||||||
registry
|
|
||||||
;
|
|
||||||
};
|
|
||||||
|
|
||||||
mkHost =
|
|
||||||
{
|
|
||||||
hostName,
|
|
||||||
system ? "x86_64-linux",
|
|
||||||
}:
|
|
||||||
inputs.nixpkgs.lib.nixosSystem {
|
|
||||||
inherit system specialArgs;
|
|
||||||
modules =
|
|
||||||
moduleFiles
|
|
||||||
++ guestFiles
|
|
||||||
++ [
|
|
||||||
inputs.chaotic.nixosModules.default
|
|
||||||
inputs.disko.nixosModules.disko
|
|
||||||
inputs.sops-nix.nixosModules.sops
|
|
||||||
inputs.stylix.nixosModules.stylix
|
|
||||||
registry.module
|
|
||||||
(self + "/hosts/${hostName}")
|
|
||||||
{
|
|
||||||
networking.hostName = hostName;
|
|
||||||
modules.host.enable = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
mkHosts =
|
|
||||||
hostsDir:
|
|
||||||
let
|
|
||||||
hostNames = attrNames (filterAttrs (_name: type: type == "directory") (builtins.readDir hostsDir));
|
|
||||||
in
|
|
||||||
genAttrs hostNames (hostName: mkHost { inherit hostName; });
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
inherit
|
inherit (files) collectNixFiles;
|
||||||
collectNixFiles
|
inherit (network) bridgeName deriveMac;
|
||||||
mkHost
|
|
||||||
mkHosts
|
|
||||||
bridgeName
|
|
||||||
registry
|
|
||||||
;
|
|
||||||
|
|
||||||
inherit (guests) deriveMac guest;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
22
lib/files.nix
Normal file
22
lib/files.nix
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{ lib }:
|
||||||
|
let
|
||||||
|
collectNixFiles =
|
||||||
|
dir:
|
||||||
|
lib.flatten (
|
||||||
|
lib.mapAttrsToList (
|
||||||
|
name: type:
|
||||||
|
let
|
||||||
|
path = dir + "/${name}";
|
||||||
|
in
|
||||||
|
if type == "directory" then
|
||||||
|
collectNixFiles path
|
||||||
|
else if type == "regular" && lib.hasSuffix ".nix" name then
|
||||||
|
[ path ]
|
||||||
|
else
|
||||||
|
[ ]
|
||||||
|
) (builtins.readDir dir)
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit collectNixFiles;
|
||||||
|
}
|
||||||
12
lib/network.nix
Normal file
12
lib/network.nix
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{ lib }:
|
||||||
|
{
|
||||||
|
bridgeName = id: "br-vlan${toString id}";
|
||||||
|
|
||||||
|
deriveMac =
|
||||||
|
name:
|
||||||
|
let
|
||||||
|
hash = builtins.hashString "sha256" name;
|
||||||
|
octet = i: builtins.substring (i * 2) 2 hash;
|
||||||
|
in
|
||||||
|
lib.concatStringsSep ":" ([ "02" ] ++ map octet [ 0 1 2 3 4 ]);
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
|
flake,
|
||||||
pkgs,
|
pkgs,
|
||||||
inputs,
|
inputs,
|
||||||
...
|
...
|
||||||
@@ -63,8 +64,7 @@ in
|
|||||||
useGlobalPkgs = true;
|
useGlobalPkgs = true;
|
||||||
useUserPackages = true;
|
useUserPackages = true;
|
||||||
extraSpecialArgs = {
|
extraSpecialArgs = {
|
||||||
inherit inputs;
|
inherit flake inputs;
|
||||||
my = inputs.self.lib;
|
|
||||||
};
|
};
|
||||||
users.${user.name} = {
|
users.${user.name} = {
|
||||||
home.username = user.name;
|
home.username = user.name;
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
my,
|
flake,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
# The host networking foundation: per-VLAN bridges over a tagged trunk.
|
# The host networking foundation: per-VLAN bridges over a tagged trunk.
|
||||||
let
|
let
|
||||||
cfg = config.modules.network.vlans;
|
cfg = config.modules.network.vlans;
|
||||||
|
|
||||||
inherit (my) bridgeName;
|
inherit (flake.util) bridgeName;
|
||||||
|
|
||||||
vlanName = id: "${cfg.trunk}.${toString id}";
|
vlanName = id: "${cfg.trunk}.${toString id}";
|
||||||
in
|
in
|
||||||
|
|||||||
Reference in New Issue
Block a user