about summary refs log tree commit diff
path: root/nix/modules/libvirtnix/default.nix
diff options
context:
space:
mode:
authorEmile <git@emile.space>2025-02-10 23:58:05 +0100
committerEmile <git@emile.space>2025-02-10 23:58:05 +0100
commit906026e924e3aac0f0ed32ec8ab2f7468e8e1c0a (patch)
treecadcd8aa380b713a573266701d0b63b766c93b97 /nix/modules/libvirtnix/default.nix
parentf62271e0d0739cbc7a4fae21ebfcd76e0e7e9d58 (diff)
corrino: libvirtnix foo, less XML, more nix!
So I've finally started this. Let's see how far I can push this!
Diffstat (limited to 'nix/modules/libvirtnix/default.nix')
-rw-r--r--nix/modules/libvirtnix/default.nix102
1 files changed, 102 insertions, 0 deletions
diff --git a/nix/modules/libvirtnix/default.nix b/nix/modules/libvirtnix/default.nix
new file mode 100644
index 0000000..4689979
--- /dev/null
+++ b/nix/modules/libvirtnix/default.nix
@@ -0,0 +1,102 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+
+let
+  cfg = config.services.emile.libvirtnix;
+in {
+  options.services.emile.libvirtnix = with lib; {
+    enable = mkEnableOption "enable libvirtnix";
+    instances = 
+      mkOption {
+        type = types.attrsOf (types.submodule ({ name, ... }: {
+          options = {
+            enable = mkEnableOption "enable this instance";
+            domain = mkOption {
+              type = types.submodule (import ./domain.nix);
+            };
+          };
+        }));
+        default = {};
+        description = ''
+          A full libvirt config, statically defined using nix.
+        '';
+        example = ''
+          {
+            domain = {
+              name = "vm";
+            };
+          }
+        '';
+      };
+  };
+
+  config = lib.mkIf cfg.enable {
+    systemd.services = lib.mapAttrs' (
+      name: guest:
+      lib.nameValuePair "libvirtd-guest-${name}" {
+        after = [ "libvirtd.service" ];
+        requires = [ "libvirtd.service" ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          Type = "oneshot";
+          RemainAfterExit = "yes";
+        };
+        script =
+          let
+            xml = pkgs.writeText "libvirt-guest-${name}.xml" ''
+              <domain ''
+              + (lib.optionalString (guest.domain.type != "") "type='${guest.domain.type}' ")
+              + (lib.optionalString (guest.domain.id != 0) "id='${guest.domain.type}'")
+              + ''>''
+              + (lib.optionalString (guest.domain.name != "") "<name>${guest.domain.name}</name>")
+              + (lib.optionalString (guest.domain.name != "") "<name>${guest.domain.name}</name>")
+              + (lib.optionalString (guest.domain.uuid != "") "<uuid>${guest.domain.uuid}</uuid>")
+              + (lib.optionalString (guest.domain.genid != "") "<genid>${guest.domain.genid}</genid>")
+              + (lib.optionalString (guest.domain.title != "") "<title>${guest.domain.title}</title>")
+              + (lib.optionalString (guest.domain.description != "") "<description>${guest.domain.description}</description>")
+              + (lib.optionalString (guest.domain.metadata != "") "${guest.domain.metadata}")
+              + ''
+                <os>
+                  <type>hvm</type>
+                </os>
+                <memory unit="GiB">${toString guest.domain.memory}</memory>
+                <devices>
+                  <disk type="volume">
+                    <source volume="guest-${name}"/>
+                    <target dev="vda" bus="virtio"/>
+                  </disk>
+                  <graphics type="spice" autoport="yes"/>
+                  <input type="keyboard" bus="usb"/>
+                </devices>
+                <features>
+                  <acpi/>
+                </features>
+              </domain>
+            '';
+          in
+          ''
+            uuid="$(${pkgs.libvirt}/bin/virsh domuuid '${name}' || true)"
+            ${pkgs.libvirt}/bin/virsh define <(sed "s/UUID/$uuid/" '${xml}')
+            ${pkgs.libvirt}/bin/virsh start '${name}'
+          '';
+        preStop = ''
+          ${pkgs.libvirt}/bin/virsh shutdown '${name}'
+          let "timeout = $(date +%s) + 10"
+          while [ "$(${pkgs.libvirt}/bin/virsh list --name | grep --count '^${name}$')" -gt 0 ]; do
+            if [ "$(date +%s)" -ge "$timeout" ]; then
+              # Meh, we warned it...
+              ${pkgs.libvirt}/bin/virsh destroy '${name}'
+            else
+              # The machine is still running, let's give it some time to shut down
+              sleep 0.5
+            fi
+          done
+        '';
+      }
+    ) config.services.emile.libvirtnix.instances;
+  };
+}