diff options
Diffstat (limited to 'machines.nix')
| -rw-r--r-- | machines.nix | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/machines.nix b/machines.nix new file mode 100644 index 0000000..8f29ef0 --- /dev/null +++ b/machines.nix @@ -0,0 +1,225 @@ +{ + self, + config, + lib, + ... +}: +let + inherit (lib) mkOption types; +in +{ + options.flake.machines = mkOption { + description = '' + Hilfswerkzeuge um Rechner mit NixOS neu aufzusetzen und zu verwalten + + `networking.hostName` wird standardmäßig auf den Attributnamen der Maschine gesetzt. + ''; + type = + with types; + attrsOf ( + submodule ( + machine@{ name, options, ... }: + { + options = { + bootstrap-target = mkOption { + description = '' + SSH-Verbindung fürs Aufsetzen der Maschine + + Die jeweilige Maschine wird einen vorhandenen Authentifikationsmechanismus haben, z.b. SSH-Key oder Passwort, der hierfür beim Aufruf einmalig manuell genutzt wird. + ''; + type = types.str; + example = "root@example.org"; + }; + + deploy-target = mkOption { + description = '' + SSH-Verbindung für reguläres Verwaltung der Maschine + + Die Authentifizierung erfolg entsprechend der Maschinenkonfiguration, und Admins sollten die Verbindungsdaten bei sich entsprechend einrichten, z.B. über `~/.ssh/config`. + ''; + type = types.str; + example = "user@example.org"; + default = machine.config.bootstrap-target; + }; + + nixos = mkOption { + description = '' + NixOS Konfigurationsmodul für die Maschine + + Dokumentation: <https://search.nixos.org/options> + ''; + type = + with types; + deferredModuleWith { + staticModules = [ + { + _class = "nixos"; + networking.hostName = lib.mkDefault machine.name; + } + ]; + }; + }; + + vm = mkOption { + description = '' + Konfigurationsmodul zur virtuellen Maschine (VM) für lokale Tests + + Abgesehen von den hier festgelegten Einstellungen und Datenbankinhalten enspricht die virtuelle Maschine genau dem Produktionssystem. + Dies erlaubt recht zuverlässige manuelle Prüfung der Konfiguration im Vorfeld von Änderungen am Produktionssystem. + + Maschinenspezifische VM-Einstellungen werden mit den hier vorgegebenen Standardwerten zusammengefügt. + Bei Bedarf müssen die Standards explizit mit `lib.mkForce` überschrieben werden. + ''; + type = types.deferredModuleWith { + staticModules = [ options.vm.default ]; + }; + default = + { + config, + options, + modulesPath, + lib, + ... + }: + { + _class = "nixos"; + + imports = [ + "${modulesPath}/virtualisation/qemu-vm.nix" + ]; + + options = { + virtualisation.portOffset = mkOption { + description = '' + An den VM-Host exponierte Portnummern von Diensten innerhalb der VM um diesen Wert versetzen + + Dies dient dazu, Konflikte mit möglicherweise bestehenden Diensten auf dem Host zu vermeiden. + + Beispiel: SSH auf Port 22 in der VM wird beim Host exponiert auf Port ${ + toString (22 + options.virtualisation.portOffset.default) + }. + ''; + type = types.ints.positive; + default = 10000; + }; + }; + + config = { + virtualisation.forwardPorts = map (port: { + from = "host"; + guest.port = port; + host.port = port + config.virtualisation.portOffset; + proto = "tcp"; + }) config.networking.firewall.allowedTCPPorts; + + services.getty.autologinUser = lib.mkDefault "root"; + }; + }; + }; + + eval = mkOption { + readOnly = true; + internal = true; + default = lib.nixosSystem { + modules = [ machine.config.nixos ]; + }; + }; + + vm-eval = mkOption { + readOnly = true; + internal = true; + default = lib.nixosSystem { + modules = [ + machine.config.nixos + machine.config.vm + ]; + }; + }; + }; + } + ) + ); + }; + + config.flake.nixosConfigurations = lib.mapAttrs (name: machine: machine.eval) self.machines; + + config.perSystem = + { pkgs, ... }: + { + /* + Projektweite Tests, ausführen mit: + + nix flake check + */ + checks = lib.concatMapAttrs (name: machine: { + /* + Konsistenzprüfung der Partitionierung. + + Erfolgreicher Test bedeutet nicht unbedingt, dass die Konfiguration auch in der Produktionsumgebung funktioniert. + Beispielsweise muss die Konfiguration dazu passen, ob das Produktionssystem mit BIOS oder UEFI bootet. + */ + "${name}-installTest" = machine.eval.config.system.build.installTest; + }) self.machines; + + # Werkzeuge zur Verwaltung von Maschinen + packages = lib.concatMapAttrs (name: machine: { + "infect-${name}" = pkgs.writeShellApplication { + name = "infect"; + runtimeInputs = with pkgs; [ nixos-anywhere ]; + /* + ACHTUNG: Vor dem Aufsetzen erst Informationen zur Hardware abfragen und in die Konfiguration einbetten! + + nix run .#machines.infect-<machine> -- --no-reboot --generate-hardware-config nixos-hardware-config <datei> + */ + text = '' + nixos-anywhere --store-paths \ + ${machine.eval.config.system.build.diskoScript} \ + ${machine.eval.config.system.build.toplevel} \ + ${machine.bootstrap-target} "$@" + ''; + }; + + "deploy-${name}" = pkgs.writeShellApplication { + name = "deploy"; + text = + let + system = machine.eval.config.system.build.toplevel; + in + '' + ${ + "" # XXX: Keine Signaturen. Das richtig einzurichten ist für den Moment zu umständlich. + }nix copy --to ssh-ng://${machine.deploy-target} --no-check-sigs ${system} + + # shellcheck disable=SC2087 + ${ + "" + /* + ACHTUNG: Admins sollten sicherstellen, dass für diesen Host in `~/.ssh/config` folgendes enthalten ist: + + ForwardAgent: yes + + Außerdem muss der dort konfigurierte Nutzer dem Nutzer auf der jeweiligen Maschine enstprechen, und der SSH-Key zum SSH-Agent hinzugefügt sein. + Es gibt keine Passwörter und auch keine Möglichkeit eins einzugeben. + */ + }ssh ${machine.deploy-target} << EOF + sudo nix-env -p /nix/var/nix/profiles/system --set ${system} + sudo ${system}/bin/switch-to-configuration "$@" + EOF + ''; + }; + + "vm-${name}" = pkgs.writeShellApplication { + name = "vm"; + text = '' + ${ + "" # Festplattenabbild im flüchtigen Speicher erstellen, das ist deutlich schneller + }cd "$(mktemp -d)" + ${ + "" # Immer am Ende aufräumen + }trap 'rm -f nixos.qcow2' EXIT + ${lib.getExe machine.vm-eval.config.system.build.vm} "$@" + ''; + }; + }) self.machines; + }; +} |
