aboutsummaryrefslogtreecommitdiff
path: root/machines.nix
diff options
context:
space:
mode:
Diffstat (limited to 'machines.nix')
-rw-r--r--machines.nix225
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;
+ };
+}