]> git.immae.eu Git - perso/Immae/Config/Nix.git/blob - modules/private/system/dilion/vms.nix
WIP upgrade
[perso/Immae/Config/Nix.git] / modules / private / system / dilion / vms.nix
1 # inspired from https://nixos.wiki/wiki/Virtualization_in_NixOS
2 { config, pkgs, lib, ... }@args:
3 let
4 pools = {
5 niximages = {
6 type = "dir";
7 target = "/etc/libvirtd/base-images";
8 };
9 buildbot-disks = rec {
10 preStart = ''
11 mkdir -p ${target}
12 '';
13 type = "dir";
14 target = "/var/lib/libvirt/images/buildbot-disks";
15 };
16 zfspool = {
17 # pool-define-as --name zfspool --source-name zpool/libvirt --type zfs
18 type = "zfs";
19 xml = ''
20 <source>
21 <name>zpool/libvirt</name>
22 </source>
23 '';
24 };
25 };
26 networks = {
27 immae = {
28 bridgeNumber = "1";
29 ipRange = "192.168.100";
30 };
31 };
32 guests = {
33 caldance = {
34 pool = "zfspool";
35 cpus = "1";
36 memory = "2";
37 network = "immae";
38 diskSize = "10GiB";
39 extraDevicesXML = ''
40 <filesystem type="mount">
41 <source dir="/var/lib/caldance"/>
42 <target dir="home"/>
43 </filesystem>
44 '';
45 };
46 buildbot = {
47 pool = "zfspool";
48 cpus = "1";
49 memory = "3";
50 network = "immae";
51 diskSize = "10GiB";
52 destroyVolumeOnExit = true;
53 };
54 };
55 toImage = f: "${import ./vms/base_image.nix f (args // { myEnv = config.myEnv; })}/nixos.qcow2";
56 in
57 {
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" ];
64 serviceConfig = {
65 Type = "oneshot";
66 RemainAfterExit = "yes";
67 };
68 path = [ config.boot.zfs.package ];
69 script =
70 let
71 xml = pkgs.writeText "libvirt-guest-${name}.xml"
72 ''
73 <domain type="kvm">
74 <name>${name}</name>
75 <uuid>UUID</uuid>
76 <memory unit="GiB">${guest.memory}</memory>
77 <vcpu>${guest.cpus}</vcpu>
78 <os>
79 <type arch="x86_64">hvm</type>
80 </os>
81 <devices>
82 <emulator>/run/current-system/sw/bin/qemu-system-x86_64</emulator>
83 <disk type="volume">
84 <source pool="${guest.pool}" volume="guest-${name}" />
85 <target dev="vda" bus="virtio"/>
86 </disk>
87 ${guest.extraDevicesXML or ""}
88 <input type="keyboard" bus="usb"/>
89 <graphics type="vnc" port="-1" autoport="yes"/>
90 <interface type="network">
91 <source network="${guest.network}" />
92 </interface>
93 </devices>
94 <features>
95 <acpi/>
96 </features>
97 </domain>
98 '';
99 in
100 guest.preStart or "" + ''
101 if ! ${pkgs.libvirt}/bin/virsh vol-key 'guest-${name}' --pool ${guest.pool} &> /dev/null; then
102 ${pkgs.libvirt}/bin/virsh vol-create-as --pool ${guest.pool} --name 'guest-${name}' --capacity '${guest.diskSize}'
103 volume_path=$(${pkgs.libvirt}/bin/virsh vol-path --pool ${guest.pool} --vol 'guest-${name}')
104 ${pkgs.qemu}/bin/qemu-img convert /etc/libvirtd/base-images/nixos.qcow2 $volume_path
105 fi
106 uuid="$(${pkgs.libvirt}/bin/virsh domuuid '${name}' || true)"
107 ${pkgs.libvirt}/bin/virsh define <(sed "s/UUID/$uuid/" '${xml}')
108 ${pkgs.libvirt}/bin/virsh start '${name}'
109 '';
110 preStop = ''
111 ${pkgs.libvirt}/bin/virsh shutdown '${name}'
112 let "timeout = $(date +%s) + 10"
113 while [ "$(${pkgs.libvirt}/bin/virsh list --name | grep --count '^${name}$')" -gt 0 ]; do
114 if [ "$(date +%s)" -ge "$timeout" ]; then
115 # Meh, we warned it...
116 ${pkgs.libvirt}/bin/virsh destroy '${name}'
117 else
118 # The machine is still running, let's give it some time to shut down
119 sleep 0.5
120 fi
121 done
122 '' + lib.optionalString (guest.destroyVolumeOnExit or false) ''
123 if ${pkgs.libvirt}/bin/virsh vol-key 'guest-${name}' --pool ${guest.pool} &> /dev/null; then
124 ${pkgs.libvirt}/bin/virsh vol-wipe --pool ${guest.pool} --vol 'guest-${name}' || true
125 ${pkgs.libvirt}/bin/virsh vol-delete --pool ${guest.pool} --vol 'guest-${name}'
126 fi
127 '';
128 }) guests // (lib.mapAttrs' (name: network: lib.nameValuePair "libvirtd-network-${name}" {
129 after = [ "libvirtd.service" ];
130 requires = [ "libvirtd.service" ];
131 wantedBy = [ "multi-user.target" ];
132 serviceConfig = {
133 Type = "oneshot";
134 RemainAfterExit = "yes";
135 };
136 path = [ config.boot.zfs.package ];
137 script = let
138 xml = pkgs.writeText "libvirt-network-${name}.xml" ''
139 <network>
140 <name>${name}</name>
141 <uuid>UUID</uuid>
142 <forward mode='nat' />
143 <bridge name='virbr${network.bridgeNumber}' />
144 <domain name='${name}' localOnly='yes'/>
145 <ip address='${network.ipRange}.1' netmask='255.255.255.0'>
146 <dhcp>
147 <range start='${network.ipRange}.2' end='${network.ipRange}.254'/>
148 </dhcp>
149 </ip>
150 </network>
151 '';
152 in ''
153 uuid="$(${pkgs.libvirt}/bin/virsh net-uuid '${name}' || true)"
154 ${pkgs.libvirt}/bin/virsh net-define <(sed "s/UUID/$uuid/" '${xml}')
155 ${pkgs.libvirt}/bin/virsh net-start '${name}'
156 '';
157 preStop = ''
158 ${pkgs.libvirt}/bin/virsh net-destroy '${name}'
159 '';
160 }) networks) // (lib.mapAttrs' (name: pool: lib.nameValuePair "libvirtd-pool-${name}" {
161 after = [ "libvirtd.service" ];
162 requires = [ "libvirtd.service" ];
163 wantedBy = [ "multi-user.target" ];
164 serviceConfig = {
165 Type = "oneshot";
166 RemainAfterExit = "yes";
167 };
168 path = [ config.boot.zfs.package ];
169 script = let
170 xml = pkgs.writeText "libvirt-pool-${name}.xml" ''
171 <pool type="${pool.type}">
172 <name>${name}</name>
173 <uuid>UUID</uuid>
174 ${pool.xml or ""}
175 ${if pool ? target then ''
176 <target>
177 <path>${pool.target}</path>
178 </target>
179 '' else ""}
180 </pool>
181 '';
182 in pool.preStart or "" + ''
183 uuid="$(${pkgs.libvirt}/bin/virsh pool-uuid '${name}' || true)"
184 ${pkgs.libvirt}/bin/virsh pool-define <(sed "s/UUID/$uuid/" '${xml}')
185 ${pkgs.libvirt}/bin/virsh pool-start '${name}' || true
186 '';
187 }) pools);
188 }