1 # inspired from https://nixos.wiki/wiki/Virtualization_in_NixOS
2 { config, pkgs, lib, ... }@args:
7 target = "/etc/libvirtd/base-images";
14 target = "/var/lib/libvirt/images/buildbot-disks";
17 # pool-define-as --name zfspool --source-name zpool/libvirt --type zfs
21 <name>zpool/libvirt</name>
29 ipRange = "192.168.100";
40 <filesystem type="mount">
41 <source dir="/var/lib/caldance"/>
52 destroyVolumeOnExit = true;
55 toImage = f: "${import ./vms/base_image.nix f (args // { myEnv = config.myEnv; })}/nixos.qcow2";
58 environment.etc."libvirtd/base-images/nixos.qcow2".source = toImage ./vms/base_configuration.nix;
59 environment.etc."libvirtd/base-images/buildbot.qcow2".source = toImage ./vms/buildbot_configuration.nix;
60 systemd.services = lib.mapAttrs' (name: guest: lib.nameValuePair "libvirtd-guest-${name}" {
61 after = [ "libvirtd.service" "libvirtd-pool-${guest.pool}.service" "libvirtd-network-${guest.network}.service" ];
62 requires = [ "libvirtd.service" "libvirtd-pool-${guest.pool}.service" "libvirtd-network-${guest.network}.service" ];
63 wantedBy = [ "multi-user.target" ];
66 RemainAfterExit = "yes";
70 xml = pkgs.writeText "libvirt-guest-${name}.xml"
75 <memory unit="GiB">${guest.memory}</memory>
76 <vcpu>${guest.cpus}</vcpu>
78 <type arch="x86_64">hvm</type>
81 <emulator>/run/current-system/sw/bin/qemu-system-x86_64</emulator>
83 <source pool="${guest.pool}" volume="guest-${name}" />
84 <target dev="vda" bus="virtio"/>
86 ${guest.extraDevicesXML or ""}
87 <input type="keyboard" bus="usb"/>
88 <graphics type="vnc" port="-1" autoport="yes"/>
89 <interface type="network">
90 <source network="${guest.network}" />
99 guest.preStart or "" + ''
100 if ! ${pkgs.libvirt}/bin/virsh vol-key 'guest-${name}' --pool ${guest.pool} &> /dev/null; then
101 ${pkgs.libvirt}/bin/virsh vol-create-as --pool ${guest.pool} --name 'guest-${name}' --capacity '${guest.diskSize}'
102 volume_path=$(${pkgs.libvirt}/bin/virsh vol-path --pool ${guest.pool} --vol 'guest-${name}')
103 ${pkgs.qemu}/bin/qemu-img convert /etc/libvirtd/base-images/nixos.qcow2 $volume_path
105 uuid="$(${pkgs.libvirt}/bin/virsh domuuid '${name}' || true)"
106 ${pkgs.libvirt}/bin/virsh define <(sed "s/UUID/$uuid/" '${xml}')
107 ${pkgs.libvirt}/bin/virsh start '${name}'
110 ${pkgs.libvirt}/bin/virsh shutdown '${name}'
111 let "timeout = $(date +%s) + 10"
112 while [ "$(${pkgs.libvirt}/bin/virsh list --name | grep --count '^${name}$')" -gt 0 ]; do
113 if [ "$(date +%s)" -ge "$timeout" ]; then
114 # Meh, we warned it...
115 ${pkgs.libvirt}/bin/virsh destroy '${name}'
117 # The machine is still running, let's give it some time to shut down
121 '' + lib.optionalString (guest.destroyVolumeOnExit or false) ''
122 if ${pkgs.libvirt}/bin/virsh vol-key 'guest-${name}' --pool ${guest.pool} &> /dev/null; then
123 ${pkgs.libvirt}/bin/virsh vol-wipe --pool ${guest.pool} --vol 'guest-${name}' || true
124 ${pkgs.libvirt}/bin/virsh vol-delete --pool ${guest.pool} --vol 'guest-${name}'
127 }) guests // (lib.mapAttrs' (name: network: lib.nameValuePair "libvirtd-network-${name}" {
128 after = [ "libvirtd.service" ];
129 requires = [ "libvirtd.service" ];
130 wantedBy = [ "multi-user.target" ];
133 RemainAfterExit = "yes";
136 xml = pkgs.writeText "libvirt-network-${name}.xml" ''
140 <forward mode='nat' />
141 <bridge name='virbr${network.bridgeNumber}' />
142 <domain name='${name}' localOnly='yes'/>
143 <ip address='${network.ipRange}.1' netmask='255.255.255.0'>
145 <range start='${network.ipRange}.2' end='${network.ipRange}.254'/>
151 uuid="$(${pkgs.libvirt}/bin/virsh net-uuid '${name}' || true)"
152 ${pkgs.libvirt}/bin/virsh net-define <(sed "s/UUID/$uuid/" '${xml}')
153 ${pkgs.libvirt}/bin/virsh net-start '${name}'
156 ${pkgs.libvirt}/bin/virsh net-destroy '${name}'
158 }) networks) // (lib.mapAttrs' (name: pool: lib.nameValuePair "libvirtd-pool-${name}" {
159 after = [ "libvirtd.service" ];
160 requires = [ "libvirtd.service" ];
161 wantedBy = [ "multi-user.target" ];
164 RemainAfterExit = "yes";
167 xml = pkgs.writeText "libvirt-pool-${name}.xml" ''
168 <pool type="${pool.type}">
172 ${if pool ? target then ''
174 <path>${pool.target}</path>
179 in pool.preStart or "" + ''
180 uuid="$(${pkgs.libvirt}/bin/virsh pool-uuid '${name}' || true)"
181 ${pkgs.libvirt}/bin/virsh pool-define <(sed "s/UUID/$uuid/" '${xml}')
182 ${pkgs.libvirt}/bin/virsh pool-start '${name}' || true