at 25.11-pre 12 kB view raw
1{ 2 config, 3 pkgs, 4 lib, 5 ... 6}: 7 8with lib; 9{ 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 ]; 26 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 }; 87 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 }; 211 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 ]; 300 301 buildInputs = super.buildInputs ++ [ pkgs.libuuid ]; 302 nativeBuildInputs = super.nativeBuildInputs ++ [ pkgs.perl ]; 303 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/ 314 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 }; 323 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 }; 340 341 loader.timeout = 0; 342 initrd.availableKernelModules = [ 343 "uas" 344 "virtio_blk" 345 "virtio_pci" 346 ]; 347 }; 348 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 }; 358 359 networking = mkIf cfg.cloudInit.enable { 360 hostName = mkForce ""; 361 useDHCP = false; 362 }; 363 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 }; 372 373 proxmox.qemuExtraConf.${cfg.cloudInit.device} = 374 "${cfg.cloudInit.defaultStorage}:vm-9999-cloudinit,media=cdrom"; 375 }; 376}