xeus-cling: fix improper linking with LLVM (#351130)
[NixPkgs.git] / nixos / modules / virtualisation / proxmox-image.nix
blob5b28bccfd06456535f437cc873c055dc2b49f002
2   config,
3   pkgs,
4   lib,
5   ...
6 }:
8 with lib;
10   imports = [
11     ./disk-size-option.nix
12     ../image/file-options.nix
13     (lib.mkRenamedOptionModuleWith {
14       sinceRelease = 2411;
15       from = [
16         "proxmox"
17         "qemuConf"
18         "diskSize"
19       ];
20       to = [
21         "virtualisation"
22         "diskSize"
23       ];
24     })
25   ];
27   options.proxmox = {
28     qemuConf = {
29       # essential configs
30       boot = mkOption {
31         type = types.str;
32         default = "";
33         example = "order=scsi0;net0";
34         description = ''
35           Default boot device. PVE will try all devices in its default order if this value is empty.
36         '';
37       };
38       scsihw = mkOption {
39         type = types.str;
40         default = "virtio-scsi-single";
41         example = "lsi";
42         description = ''
43           SCSI controller type. Must be one of the supported values given in
44           <https://pve.proxmox.com/wiki/Qemu/KVM_Virtual_Machines>
45         '';
46       };
47       virtio0 = mkOption {
48         type = types.str;
49         default = "local-lvm:vm-9999-disk-0";
50         example = "ceph:vm-123-disk-0";
51         description = ''
52           Configuration for the default virtio disk. It can be used as a cue for PVE to autodetect the target storage.
53           This parameter is required by PVE even if it isn't used.
54         '';
55       };
56       ostype = mkOption {
57         type = types.str;
58         default = "l26";
59         description = ''
60           Guest OS type
61         '';
62       };
63       cores = mkOption {
64         type = types.ints.positive;
65         default = 1;
66         description = ''
67           Guest core count
68         '';
69       };
70       memory = mkOption {
71         type = types.ints.positive;
72         default = 1024;
73         description = ''
74           Guest memory in MB
75         '';
76       };
77       bios = mkOption {
78         type = types.enum [
79           "seabios"
80           "ovmf"
81         ];
82         default = "seabios";
83         description = ''
84           Select BIOS implementation (seabios = Legacy BIOS, ovmf = UEFI).
85         '';
86       };
88       # optional configs
89       name = mkOption {
90         type = types.str;
91         default = "nixos-${config.system.nixos.label}";
92         description = ''
93           VM name
94         '';
95       };
96       additionalSpace = mkOption {
97         type = types.str;
98         default = "512M";
99         example = "2048M";
100         description = ''
101           additional disk space to be added to the image if diskSize "auto"
102           is used.
103         '';
104       };
105       bootSize = mkOption {
106         type = types.str;
107         default = "256M";
108         example = "512M";
109         description = ''
110           Size of the boot partition. Is only used if partitionTableType is
111           either "efi" or "hybrid".
112         '';
113       };
114       net0 = mkOption {
115         type = types.commas;
116         default = "virtio=00:00:00:00:00:00,bridge=vmbr0,firewall=1";
117         description = ''
118           Configuration for the default interface. When restoring from VMA, check the
119           "unique" box to ensure device mac is randomized.
120         '';
121       };
122       serial0 = mkOption {
123         type = types.str;
124         default = "socket";
125         example = "/dev/ttyS0";
126         description = ''
127           Create a serial device inside the VM (n is 0 to 3), and pass through a host serial device (i.e. /dev/ttyS0),
128           or create a unix socket on the host side (use qm terminal to open a terminal connection).
129         '';
130       };
131       agent = mkOption {
132         type = types.bool;
133         apply = x: if x then "1" else "0";
134         default = true;
135         description = ''
136           Expect guest to have qemu agent running
137         '';
138       };
139     };
140     qemuExtraConf = mkOption {
141       type =
142         with types;
143         attrsOf (oneOf [
144           str
145           int
146         ]);
147       default = { };
148       example = literalExpression ''
149         {
150           cpu = "host";
151           onboot = 1;
152         }
153       '';
154       description = ''
155         Additional options appended to qemu-server.conf
156       '';
157     };
158     partitionTableType = mkOption {
159       type = types.enum [
160         "efi"
161         "hybrid"
162         "legacy"
163         "legacy+gpt"
164       ];
165       description = ''
166         Partition table type to use. See make-disk-image.nix partitionTableType for details.
167         Defaults to 'legacy' for 'proxmox.qemuConf.bios="seabios"' (default), other bios values defaults to 'efi'.
168         Use 'hybrid' to build grub-based hybrid bios+efi images.
169       '';
170       default = if config.proxmox.qemuConf.bios == "seabios" then "legacy" else "efi";
171       defaultText = lib.literalExpression ''if config.proxmox.qemuConf.bios == "seabios" then "legacy" else "efi"'';
172       example = "hybrid";
173     };
174     filenameSuffix = mkOption {
175       type = types.str;
176       default = config.proxmox.qemuConf.name;
177       example = "999-nixos_template";
178       description = ''
179         Filename of the image will be vzdump-qemu-''${filenameSuffix}.vma.zstd.
180         This will also determine the default name of the VM on restoring the VMA.
181         Start this value with a number if you want the VMA to be detected as a backup of
182         any specific VMID.
183       '';
184     };
185     cloudInit = {
186       enable = mkOption {
187         type = types.bool;
188         default = true;
189         description = ''
190           Whether the VM should accept cloud init configurations from PVE.
191         '';
192       };
193       defaultStorage = mkOption {
194         default = "local-lvm";
195         example = "tank";
196         type = types.str;
197         description = ''
198           Default storage name for cloud init drive.
199         '';
200       };
201       device = mkOption {
202         default = "ide2";
203         example = "scsi0";
204         type = types.str;
205         description = ''
206           Bus/device to which the cloud init drive is attached.
207         '';
208       };
209     };
210   };
212   config =
213     let
214       cfg = config.proxmox;
215       cfgLine = name: value: ''
216         ${name}: ${builtins.toString value}
217       '';
218       virtio0Storage = builtins.head (builtins.split ":" cfg.qemuConf.virtio0);
219       cfgFile =
220         fileName: properties:
221         pkgs.writeTextDir fileName ''
222           # generated by NixOS
223           ${lib.concatStrings (lib.mapAttrsToList cfgLine properties)}
224           #qmdump#map:virtio0:drive-virtio0:${virtio0Storage}:raw:
225         '';
226       inherit (cfg) partitionTableType;
227       supportEfi = partitionTableType == "efi" || partitionTableType == "hybrid";
228       supportBios =
229         partitionTableType == "legacy"
230         || partitionTableType == "hybrid"
231         || partitionTableType == "legacy+gpt";
232       hasBootPartition = partitionTableType == "efi" || partitionTableType == "hybrid";
233       hasNoFsPartition = partitionTableType == "hybrid" || partitionTableType == "legacy+gpt";
234     in
235     {
236       assertions = [
237         {
238           assertion = config.boot.loader.systemd-boot.enable -> config.proxmox.qemuConf.bios == "ovmf";
239           message = "systemd-boot requires 'ovmf' bios";
240         }
241         {
242           assertion = partitionTableType == "efi" -> config.proxmox.qemuConf.bios == "ovmf";
243           message = "'efi' disk partitioning requires 'ovmf' bios";
244         }
245         {
246           assertion = partitionTableType == "legacy" -> config.proxmox.qemuConf.bios == "seabios";
247           message = "'legacy' disk partitioning requires 'seabios' bios";
248         }
249         {
250           assertion = partitionTableType == "legacy+gpt" -> config.proxmox.qemuConf.bios == "seabios";
251           message = "'legacy+gpt' disk partitioning requires 'seabios' bios";
252         }
253       ];
254       image.baseName = lib.mkDefault "vzdump-qemu-${cfg.filenameSuffix}";
255       image.extension = "vma.zst";
256       system.build.image = config.system.build.VMA;
257       system.build.VMA = import ../../lib/make-disk-image.nix {
258         name = "proxmox-${cfg.filenameSuffix}";
259         baseName = config.image.baseName;
260         inherit (cfg) partitionTableType;
261         postVM =
262           let
263             # Build qemu with PVE's patch that adds support for the VMA format
264             vma =
265               (pkgs.qemu_kvm.override {
266                 alsaSupport = false;
267                 pulseSupport = false;
268                 sdlSupport = false;
269                 jackSupport = false;
270                 gtkSupport = false;
271                 vncSupport = false;
272                 smartcardSupport = false;
273                 spiceSupport = false;
274                 ncursesSupport = false;
275                 libiscsiSupport = false;
276                 tpmSupport = false;
277                 numaSupport = false;
278                 seccompSupport = false;
279                 guestAgentSupport = false;
280               }).overrideAttrs
281                 (super: rec {
282                   # Check https://github.com/proxmox/pve-qemu/tree/master for the version
283                   # of qemu and patch to use
284                   version = "9.0.0";
285                   src = pkgs.fetchurl {
286                     url = "https://download.qemu.org/qemu-${version}.tar.xz";
287                     hash = "sha256-MnCKxmww2MiSYz6paMdxwcdtWX1w3erSGg0izPOG2mk=";
288                   };
289                   patches = [
290                     # Proxmox' VMA tool is published as a particular patch upon QEMU
291                     "${
292                       pkgs.fetchFromGitHub {
293                         owner = "proxmox";
294                         repo = "pve-qemu";
295                         rev = "14afbdd55f04d250bd679ca1ad55d3f47cd9d4c8";
296                         hash = "sha256-lSJQA5SHIHfxJvMLIID2drv2H43crTPMNIlIT37w9Nc=";
297                       }
298                     }/debian/patches/pve/0027-PVE-Backup-add-vma-backup-format-code.patch"
299                   ];
301                   buildInputs = super.buildInputs ++ [ pkgs.libuuid ];
302                   nativeBuildInputs = super.nativeBuildInputs ++ [ pkgs.perl ];
304                 });
305           in
306           ''
307             ${vma}/bin/vma create "${config.image.baseName}.vma" \
308               -c ${
309                 cfgFile "qemu-server.conf" (cfg.qemuConf // cfg.qemuExtraConf)
310               }/qemu-server.conf drive-virtio0=$diskImage
311             rm $diskImage
312             ${pkgs.zstd}/bin/zstd "${config.image.baseName}.vma"
313             mv "${config.image.fileName}" $out/
315             mkdir -p $out/nix-support
316             echo "file vma $out/${config.image.fileName}" > $out/nix-support/hydra-build-products
317           '';
318         inherit (cfg.qemuConf) additionalSpace bootSize;
319         inherit (config.virtualisation) diskSize;
320         format = "raw";
321         inherit config lib pkgs;
322       };
324       boot = {
325         growPartition = true;
326         kernelParams = [ "console=ttyS0" ];
327         loader.grub = {
328           device = lib.mkDefault (
329             if (hasNoFsPartition || supportBios) then
330               # Even if there is a separate no-fs partition ("/dev/disk/by-partlabel/no-fs" i.e. "/dev/vda2"),
331               # which will be used the bootloader, do not set it as loader.grub.device.
332               # GRUB installation fails, unless the whole disk is selected.
333               "/dev/vda"
334             else
335               "nodev"
336           );
337           efiSupport = lib.mkDefault supportEfi;
338           efiInstallAsRemovable = lib.mkDefault supportEfi;
339         };
341         loader.timeout = 0;
342         initrd.availableKernelModules = [
343           "uas"
344           "virtio_blk"
345           "virtio_pci"
346         ];
347       };
349       fileSystems."/" = {
350         device = "/dev/disk/by-label/nixos";
351         autoResize = true;
352         fsType = "ext4";
353       };
354       fileSystems."/boot" = lib.mkIf hasBootPartition {
355         device = "/dev/disk/by-label/ESP";
356         fsType = "vfat";
357       };
359       networking = mkIf cfg.cloudInit.enable {
360         hostName = mkForce "";
361         useDHCP = false;
362       };
364       services = {
365         cloud-init = mkIf cfg.cloudInit.enable {
366           enable = true;
367           network.enable = true;
368         };
369         sshd.enable = mkDefault true;
370         qemuGuest.enable = true;
371       };
373       proxmox.qemuExtraConf.${cfg.cloudInit.device} = "${cfg.cloudInit.defaultStorage}:vm-9999-cloudinit,media=cdrom";
374     };