feat: introduce guests as nested-container definitions
Add a third auto-loaded kind beside the host and the module: the guest, a reusable definition under guests/ that a host enables like a module and that realizes its interior as a systemd-nspawn nested container. Split the shared base config so a guest can stand on it. base.nix now holds the substrate both bases share — the primary user, home-manager, and the unstable/stable overlays. system.nix keeps the host-only machinery, and a new guest.nix is the slim guest-base: it imports the full modules tree, pins the interior release, and auto-enables the toolkit bundle and SSH so any guest is workable on sight. Give modules.ssh a guest flavor. A host restores its host keys from secrets as before, while a guest sets hostKeys.restore = false, names no sops files, and self-generates a host key, so it holds no age key of its own. The lib grows a guest helper that declares the guests.<path> namespace with an enable and a backend field. Only the container backend is built; microvm is a reserved value that trips a clear build-time assertion rather than silently building nothing. A sample guest exercises the whole path, and neogaia enables it, so the guest interior builds through the existing nix flake check seam.
This commit was merged in pull request #28.
This commit is contained in:
101
lib.nix
101
lib.nix
@@ -32,30 +32,96 @@ let
|
||||
) (builtins.readDir dir)
|
||||
);
|
||||
|
||||
# Build one host: every module is imported unconditionally (inert until its
|
||||
# `enable` flag is set), alongside home-manager, chaotic, the shared base, and
|
||||
# the host's own directory.
|
||||
# The special arguments every configuration is evaluated with, host and guest
|
||||
# interior alike.
|
||||
specialArgs = {
|
||||
inherit inputs;
|
||||
my = self.lib;
|
||||
};
|
||||
|
||||
# Build one host: every module and every guest is imported unconditionally
|
||||
# (inert until its `enable` flag is set), alongside chaotic, the host base,
|
||||
# and the host's own directory.
|
||||
mkHost =
|
||||
{
|
||||
hostName,
|
||||
system ? "x86_64-linux",
|
||||
}:
|
||||
inputs.nixpkgs.lib.nixosSystem {
|
||||
inherit system;
|
||||
specialArgs = {
|
||||
inherit inputs;
|
||||
my = self.lib;
|
||||
inherit system specialArgs;
|
||||
modules =
|
||||
(collectNixFiles (self + "/modules"))
|
||||
++ (collectNixFiles (self + "/guests"))
|
||||
++ [
|
||||
inputs.chaotic.nixosModules.default
|
||||
inputs.disko.nixosModules.disko
|
||||
inputs.sops-nix.nixosModules.sops
|
||||
inputs.stylix.nixosModules.stylix
|
||||
(self + "/system.nix")
|
||||
(self + "/hosts/${hostName}")
|
||||
{ networking.hostName = hostName; }
|
||||
];
|
||||
};
|
||||
|
||||
# Build a guest: a module-shaped definition whose body realizes its interior
|
||||
# as a nested container standing on the guest-base, keyed by its namespace path.
|
||||
# `name` is the dotted namespace under `guests.` and `interior` is an extra
|
||||
# module merged into the container alongside the guest-base.
|
||||
guest =
|
||||
{
|
||||
name,
|
||||
interior ? { },
|
||||
}:
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
optionPath = [ "guests" ] ++ lib.splitString "." name;
|
||||
cfg = lib.getAttrFromPath optionPath config;
|
||||
machineName = lib.replaceStrings [ "." ] [ "-" ] name;
|
||||
in
|
||||
{
|
||||
options = lib.setAttrByPath optionPath {
|
||||
enable = lib.mkEnableOption "the ${name} guest, run in its own nested container";
|
||||
backend = lib.mkOption {
|
||||
type = lib.types.enum [
|
||||
"container"
|
||||
"microvm"
|
||||
];
|
||||
default = "container";
|
||||
description = ''
|
||||
How the guest is realized. `container` runs the guest as a
|
||||
systemd-nspawn nested container. `microvm` is reserved for a future
|
||||
hard-isolation backend and is not built yet.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.backend == "container";
|
||||
message = ''
|
||||
guests.${name}.backend = "${cfg.backend}" is not implemented. Only the "container" backend is built; "microvm" is reserved for future work.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
containers.${machineName} = lib.mkIf (cfg.backend == "container") {
|
||||
autoStart = lib.mkDefault true;
|
||||
|
||||
# The guest gets its own network namespace, so its services — its own
|
||||
# sshd included — never contend with the host's.
|
||||
privateNetwork = lib.mkDefault true;
|
||||
|
||||
inherit specialArgs;
|
||||
|
||||
config = {
|
||||
imports = [
|
||||
(self + "/guest.nix")
|
||||
interior
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
modules = (collectNixFiles (self + "/modules")) ++ [
|
||||
inputs.home-manager.nixosModules.home-manager
|
||||
inputs.chaotic.nixosModules.default
|
||||
inputs.disko.nixosModules.disko
|
||||
inputs.sops-nix.nixosModules.sops
|
||||
inputs.stylix.nixosModules.stylix
|
||||
(self + "/system.nix")
|
||||
(self + "/hosts/${hostName}")
|
||||
{ networking.hostName = hostName; }
|
||||
];
|
||||
};
|
||||
|
||||
# Discover every host (a subdirectory of `hostsDir`) and build each one.
|
||||
@@ -71,5 +137,6 @@ in
|
||||
collectNixFiles
|
||||
mkHost
|
||||
mkHosts
|
||||
guest
|
||||
;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user