]>
Commit | Line | Data |
---|---|---|
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 | } |