1{ config, pkgs, lib, ... }:
2
3with lib;
4
5{
6 options.proxmox = {
7 qemuConf = {
8 # essential configs
9 boot = mkOption {
10 type = types.str;
11 default = "";
12 example = "order=scsi0;net0";
13 description = ''
14 Default boot device. PVE will try all devices in its default order if this value is empty.
15 '';
16 };
17 scsihw = mkOption {
18 type = types.str;
19 default = "virtio-scsi-pci";
20 example = "lsi";
21 description = ''
22 SCSI controller type. Must be one of the supported values given in
23 <link xlink:href="https://pve.proxmox.com/wiki/Qemu/KVM_Virtual_Machines"/>
24 '';
25 };
26 virtio0 = mkOption {
27 type = types.str;
28 default = "local-lvm:vm-9999-disk-0";
29 example = "ceph:vm-123-disk-0";
30 description = ''
31 Configuration for the default virtio disk. It can be used as a cue for PVE to autodetect the target sotrage.
32 This parameter is required by PVE even if it isn't used.
33 '';
34 };
35 ostype = mkOption {
36 type = types.str;
37 default = "l26";
38 description = ''
39 Guest OS type
40 '';
41 };
42 cores = mkOption {
43 type = types.ints.positive;
44 default = 1;
45 description = ''
46 Guest core count
47 '';
48 };
49 memory = mkOption {
50 type = types.ints.positive;
51 default = 1024;
52 description = ''
53 Guest memory in MB
54 '';
55 };
56
57 # optional configs
58 name = mkOption {
59 type = types.str;
60 default = "nixos-${config.system.nixos.label}";
61 description = ''
62 VM name
63 '';
64 };
65 net0 = mkOption {
66 type = types.commas;
67 default = "virtio=00:00:00:00:00:00,bridge=vmbr0,firewall=1";
68 description = ''
69 Configuration for the default interface. When restoring from VMA, check the
70 "unique" box to ensure device mac is randomized.
71 '';
72 };
73 serial0 = mkOption {
74 type = types.str;
75 default = "socket";
76 example = "/dev/ttyS0";
77 description = ''
78 Create a serial device inside the VM (n is 0 to 3), and pass through a host serial device (i.e. /dev/ttyS0),
79 or create a unix socket on the host side (use qm terminal to open a terminal connection).
80 '';
81 };
82 agent = mkOption {
83 type = types.bool;
84 apply = x: if x then "1" else "0";
85 default = true;
86 description = ''
87 Expect guest to have qemu agent running
88 '';
89 };
90 };
91 qemuExtraConf = mkOption {
92 type = with types; attrsOf (oneOf [ str int ]);
93 default = {};
94 example = literalExpression ''{
95 cpu = "host";
96 onboot = 1;
97 }'';
98 description = ''
99 Additional options appended to qemu-server.conf
100 '';
101 };
102 filenameSuffix = mkOption {
103 type = types.str;
104 default = config.proxmox.qemuConf.name;
105 example = "999-nixos_template";
106 description = ''
107 Filename of the image will be vzdump-qemu-''${filenameSuffix}.vma.zstd.
108 This will also determine the default name of the VM on restoring the VMA.
109 Start this value with a number if you want the VMA to be detected as a backup of
110 any specific VMID.
111 '';
112 };
113 };
114
115 config = let
116 cfg = config.proxmox;
117 cfgLine = name: value: ''
118 ${name}: ${builtins.toString value}
119 '';
120 cfgFile = fileName: properties: pkgs.writeTextDir fileName ''
121 # generated by NixOS
122 ${lib.concatStrings (lib.mapAttrsToList cfgLine properties)}
123 #qmdump#map:virtio0:drive-virtio0:local-lvm:raw:
124 '';
125 in {
126 system.build.VMA = import ../../lib/make-disk-image.nix {
127 name = "proxmox-${cfg.filenameSuffix}";
128 postVM = let
129 # Build qemu with PVE's patch that adds support for the VMA format
130 vma = pkgs.qemu_kvm.overrideAttrs ( super: {
131 patches = let
132 rev = "cc707c362ea5c8d832aac270d1ffa7ac66a8908f";
133 path = "debian/patches/pve/0025-PVE-Backup-add-vma-backup-format-code.patch";
134 vma-patch = pkgs.fetchpatch {
135 url = "https://git.proxmox.com/?p=pve-qemu.git;a=blob_plain;hb=${rev};f=${path}";
136 sha256 = "1z467xnmfmry3pjy7p34psd5xdil9x0apnbvfz8qbj0bf9fgc8zf";
137 };
138 in super.patches ++ [ vma-patch ];
139 buildInputs = super.buildInputs ++ [ pkgs.libuuid ];
140 });
141 in
142 ''
143 ${vma}/bin/vma create "vzdump-qemu-${cfg.filenameSuffix}.vma" \
144 -c ${cfgFile "qemu-server.conf" (cfg.qemuConf // cfg.qemuExtraConf)}/qemu-server.conf drive-virtio0=$diskImage
145 rm $diskImage
146 ${pkgs.zstd}/bin/zstd "vzdump-qemu-${cfg.filenameSuffix}.vma"
147 mv "vzdump-qemu-${cfg.filenameSuffix}.vma.zst" $out/
148 '';
149 format = "raw";
150 inherit config lib pkgs;
151 };
152
153 boot = {
154 growPartition = true;
155 kernelParams = [ "console=ttyS0" ];
156 loader.grub.device = lib.mkDefault "/dev/vda";
157 loader.timeout = 0;
158 initrd.availableKernelModules = [ "uas" "virtio_blk" "virtio_pci" ];
159 };
160
161 fileSystems."/" = {
162 device = "/dev/disk/by-label/nixos";
163 autoResize = true;
164 fsType = "ext4";
165 };
166
167 services.qemuGuest.enable = lib.mkDefault true;
168 };
169}