2021-12-06 16:07:01 +00:00
|
|
|
{ config, pkgs, lib, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
{
|
|
|
|
options.proxmox = {
|
|
|
|
qemuConf = {
|
|
|
|
# essential configs
|
|
|
|
boot = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "";
|
|
|
|
example = "order=scsi0;net0";
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2021-12-06 16:07:01 +00:00
|
|
|
Default boot device. PVE will try all devices in its default order if this value is empty.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
scsihw = mkOption {
|
|
|
|
type = types.str;
|
2024-06-05 15:53:02 +00:00
|
|
|
default = "virtio-scsi-single";
|
2021-12-06 16:07:01 +00:00
|
|
|
example = "lsi";
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2021-12-06 16:07:01 +00:00
|
|
|
SCSI controller type. Must be one of the supported values given in
|
2022-08-21 13:32:41 +00:00
|
|
|
<https://pve.proxmox.com/wiki/Qemu/KVM_Virtual_Machines>
|
2021-12-06 16:07:01 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
virtio0 = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "local-lvm:vm-9999-disk-0";
|
|
|
|
example = "ceph:vm-123-disk-0";
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2022-12-28 21:21:41 +00:00
|
|
|
Configuration for the default virtio disk. It can be used as a cue for PVE to autodetect the target storage.
|
2021-12-06 16:07:01 +00:00
|
|
|
This parameter is required by PVE even if it isn't used.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
ostype = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "l26";
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2021-12-06 16:07:01 +00:00
|
|
|
Guest OS type
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
cores = mkOption {
|
|
|
|
type = types.ints.positive;
|
|
|
|
default = 1;
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2021-12-06 16:07:01 +00:00
|
|
|
Guest core count
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
memory = mkOption {
|
|
|
|
type = types.ints.positive;
|
|
|
|
default = 1024;
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2021-12-06 16:07:01 +00:00
|
|
|
Guest memory in MB
|
|
|
|
'';
|
|
|
|
};
|
2022-11-27 09:42:12 +00:00
|
|
|
bios = mkOption {
|
|
|
|
type = types.enum [ "seabios" "ovmf" ];
|
|
|
|
default = "seabios";
|
|
|
|
description = ''
|
|
|
|
Select BIOS implementation (seabios = Legacy BIOS, ovmf = UEFI).
|
|
|
|
'';
|
|
|
|
};
|
2021-12-06 16:07:01 +00:00
|
|
|
|
|
|
|
# optional configs
|
|
|
|
name = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "nixos-${config.system.nixos.label}";
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2021-12-06 16:07:01 +00:00
|
|
|
VM name
|
|
|
|
'';
|
|
|
|
};
|
2023-08-04 22:07:22 +00:00
|
|
|
additionalSpace = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "512M";
|
|
|
|
example = "2048M";
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2023-08-04 22:07:22 +00:00
|
|
|
additional disk space to be added to the image if diskSize "auto"
|
|
|
|
is used.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
bootSize = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "256M";
|
|
|
|
example = "512M";
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2023-08-04 22:07:22 +00:00
|
|
|
Size of the boot partition. Is only used if partitionTableType is
|
|
|
|
either "efi" or "hybrid".
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
diskSize = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "auto";
|
|
|
|
example = "20480";
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2023-08-04 22:07:22 +00:00
|
|
|
The size of the disk, in megabytes.
|
|
|
|
if "auto" size is calculated based on the contents copied to it and
|
|
|
|
additionalSpace is taken into account.
|
|
|
|
'';
|
|
|
|
};
|
2021-12-06 16:07:01 +00:00
|
|
|
net0 = mkOption {
|
|
|
|
type = types.commas;
|
|
|
|
default = "virtio=00:00:00:00:00:00,bridge=vmbr0,firewall=1";
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2021-12-06 16:07:01 +00:00
|
|
|
Configuration for the default interface. When restoring from VMA, check the
|
|
|
|
"unique" box to ensure device mac is randomized.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
serial0 = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "socket";
|
|
|
|
example = "/dev/ttyS0";
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2021-12-06 16:07:01 +00:00
|
|
|
Create a serial device inside the VM (n is 0 to 3), and pass through a host serial device (i.e. /dev/ttyS0),
|
|
|
|
or create a unix socket on the host side (use qm terminal to open a terminal connection).
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
agent = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
apply = x: if x then "1" else "0";
|
|
|
|
default = true;
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2021-12-06 16:07:01 +00:00
|
|
|
Expect guest to have qemu agent running
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
qemuExtraConf = mkOption {
|
|
|
|
type = with types; attrsOf (oneOf [ str int ]);
|
|
|
|
default = {};
|
2023-07-15 17:15:38 +00:00
|
|
|
example = literalExpression ''
|
|
|
|
{
|
|
|
|
cpu = "host";
|
|
|
|
onboot = 1;
|
|
|
|
}
|
|
|
|
'';
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2021-12-06 16:07:01 +00:00
|
|
|
Additional options appended to qemu-server.conf
|
|
|
|
'';
|
|
|
|
};
|
2022-11-27 09:42:12 +00:00
|
|
|
partitionTableType = mkOption {
|
|
|
|
type = types.enum [ "efi" "hybrid" "legacy" "legacy+gpt" ];
|
|
|
|
description = ''
|
|
|
|
Partition table type to use. See make-disk-image.nix partitionTableType for details.
|
|
|
|
Defaults to 'legacy' for 'proxmox.qemuConf.bios="seabios"' (default), other bios values defaults to 'efi'.
|
|
|
|
Use 'hybrid' to build grub-based hybrid bios+efi images.
|
|
|
|
'';
|
|
|
|
default = if config.proxmox.qemuConf.bios == "seabios" then "legacy" else "efi";
|
|
|
|
defaultText = lib.literalExpression ''if config.proxmox.qemuConf.bios == "seabios" then "legacy" else "efi"'';
|
|
|
|
example = "hybrid";
|
|
|
|
};
|
2021-12-06 16:07:01 +00:00
|
|
|
filenameSuffix = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = config.proxmox.qemuConf.name;
|
|
|
|
example = "999-nixos_template";
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2021-12-06 16:07:01 +00:00
|
|
|
Filename of the image will be vzdump-qemu-''${filenameSuffix}.vma.zstd.
|
|
|
|
This will also determine the default name of the VM on restoring the VMA.
|
|
|
|
Start this value with a number if you want the VMA to be detected as a backup of
|
|
|
|
any specific VMID.
|
|
|
|
'';
|
|
|
|
};
|
2024-06-05 15:53:02 +00:00
|
|
|
cloudInit = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
description = ''
|
|
|
|
Whether the VM should accept cloud init configurations from PVE.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
defaultStorage = mkOption {
|
|
|
|
default = "local-lvm";
|
|
|
|
example = "tank";
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
Default storage name for cloud init drive.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
device = mkOption {
|
|
|
|
default = "ide2";
|
|
|
|
example = "scsi0";
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
Bus/device to which the cloud init drive is attached.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
2021-12-06 16:07:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
config = let
|
|
|
|
cfg = config.proxmox;
|
|
|
|
cfgLine = name: value: ''
|
|
|
|
${name}: ${builtins.toString value}
|
|
|
|
'';
|
2023-04-29 16:46:19 +00:00
|
|
|
virtio0Storage = builtins.head (builtins.split ":" cfg.qemuConf.virtio0);
|
2021-12-06 16:07:01 +00:00
|
|
|
cfgFile = fileName: properties: pkgs.writeTextDir fileName ''
|
|
|
|
# generated by NixOS
|
|
|
|
${lib.concatStrings (lib.mapAttrsToList cfgLine properties)}
|
2023-04-29 16:46:19 +00:00
|
|
|
#qmdump#map:virtio0:drive-virtio0:${virtio0Storage}:raw:
|
2021-12-06 16:07:01 +00:00
|
|
|
'';
|
2022-11-27 09:42:12 +00:00
|
|
|
inherit (cfg) partitionTableType;
|
|
|
|
supportEfi = partitionTableType == "efi" || partitionTableType == "hybrid";
|
|
|
|
supportBios = partitionTableType == "legacy" || partitionTableType == "hybrid" || partitionTableType == "legacy+gpt";
|
|
|
|
hasBootPartition = partitionTableType == "efi" || partitionTableType == "hybrid";
|
|
|
|
hasNoFsPartition = partitionTableType == "hybrid" || partitionTableType == "legacy+gpt";
|
2021-12-06 16:07:01 +00:00
|
|
|
in {
|
2022-11-27 09:42:12 +00:00
|
|
|
assertions = [
|
|
|
|
{
|
|
|
|
assertion = config.boot.loader.systemd-boot.enable -> config.proxmox.qemuConf.bios == "ovmf";
|
|
|
|
message = "systemd-boot requires 'ovmf' bios";
|
|
|
|
}
|
|
|
|
{
|
|
|
|
assertion = partitionTableType == "efi" -> config.proxmox.qemuConf.bios == "ovmf";
|
|
|
|
message = "'efi' disk partitioning requires 'ovmf' bios";
|
|
|
|
}
|
|
|
|
{
|
|
|
|
assertion = partitionTableType == "legacy" -> config.proxmox.qemuConf.bios == "seabios";
|
|
|
|
message = "'legacy' disk partitioning requires 'seabios' bios";
|
|
|
|
}
|
|
|
|
{
|
|
|
|
assertion = partitionTableType == "legacy+gpt" -> config.proxmox.qemuConf.bios == "seabios";
|
|
|
|
message = "'legacy+gpt' disk partitioning requires 'seabios' bios";
|
|
|
|
}
|
|
|
|
];
|
2021-12-06 16:07:01 +00:00
|
|
|
system.build.VMA = import ../../lib/make-disk-image.nix {
|
|
|
|
name = "proxmox-${cfg.filenameSuffix}";
|
2023-08-04 22:07:22 +00:00
|
|
|
inherit (cfg) partitionTableType;
|
2021-12-06 16:07:01 +00:00
|
|
|
postVM = let
|
|
|
|
# Build qemu with PVE's patch that adds support for the VMA format
|
2022-09-09 14:08:57 +00:00
|
|
|
vma = (pkgs.qemu_kvm.override {
|
|
|
|
alsaSupport = false;
|
|
|
|
pulseSupport = false;
|
|
|
|
sdlSupport = false;
|
|
|
|
jackSupport = false;
|
|
|
|
gtkSupport = false;
|
|
|
|
vncSupport = false;
|
|
|
|
smartcardSupport = false;
|
|
|
|
spiceSupport = false;
|
|
|
|
ncursesSupport = false;
|
|
|
|
libiscsiSupport = false;
|
|
|
|
tpmSupport = false;
|
|
|
|
numaSupport = false;
|
|
|
|
seccompSupport = false;
|
|
|
|
guestAgentSupport = false;
|
|
|
|
}).overrideAttrs ( super: rec {
|
2024-06-05 15:53:02 +00:00
|
|
|
# Check https://github.com/proxmox/pve-qemu/tree/master for the version
|
|
|
|
# of qemu and patch to use
|
2024-07-27 06:49:29 +00:00
|
|
|
version = "9.0.0";
|
2022-07-14 12:49:19 +00:00
|
|
|
src = pkgs.fetchurl {
|
2024-06-05 15:53:02 +00:00
|
|
|
url = "https://download.qemu.org/qemu-${version}.tar.xz";
|
2024-07-27 06:49:29 +00:00
|
|
|
hash = "sha256-MnCKxmww2MiSYz6paMdxwcdtWX1w3erSGg0izPOG2mk=";
|
2022-07-14 12:49:19 +00:00
|
|
|
};
|
2022-09-09 14:08:57 +00:00
|
|
|
patches = [
|
2023-05-24 13:37:59 +00:00
|
|
|
# Proxmox' VMA tool is published as a particular patch upon QEMU
|
2024-06-05 15:53:02 +00:00
|
|
|
"${pkgs.fetchFromGitHub {
|
|
|
|
owner = "proxmox";
|
|
|
|
repo = "pve-qemu";
|
2024-07-27 06:49:29 +00:00
|
|
|
rev = "14afbdd55f04d250bd679ca1ad55d3f47cd9d4c8";
|
|
|
|
hash = "sha256-lSJQA5SHIHfxJvMLIID2drv2H43crTPMNIlIT37w9Nc=";
|
2024-06-05 15:53:02 +00:00
|
|
|
}}/debian/patches/pve/0027-PVE-Backup-add-vma-backup-format-code.patch"
|
2022-09-09 14:08:57 +00:00
|
|
|
];
|
2022-07-14 12:49:19 +00:00
|
|
|
|
2021-12-06 16:07:01 +00:00
|
|
|
buildInputs = super.buildInputs ++ [ pkgs.libuuid ];
|
2023-07-15 17:15:38 +00:00
|
|
|
nativeBuildInputs = super.nativeBuildInputs ++ [ pkgs.perl ];
|
2022-07-14 12:49:19 +00:00
|
|
|
|
2021-12-06 16:07:01 +00:00
|
|
|
});
|
|
|
|
in
|
|
|
|
''
|
|
|
|
${vma}/bin/vma create "vzdump-qemu-${cfg.filenameSuffix}.vma" \
|
|
|
|
-c ${cfgFile "qemu-server.conf" (cfg.qemuConf // cfg.qemuExtraConf)}/qemu-server.conf drive-virtio0=$diskImage
|
|
|
|
rm $diskImage
|
|
|
|
${pkgs.zstd}/bin/zstd "vzdump-qemu-${cfg.filenameSuffix}.vma"
|
|
|
|
mv "vzdump-qemu-${cfg.filenameSuffix}.vma.zst" $out/
|
2022-09-09 14:08:57 +00:00
|
|
|
|
|
|
|
mkdir -p $out/nix-support
|
2024-06-05 15:53:02 +00:00
|
|
|
echo "file vma $out/vzdump-qemu-${cfg.filenameSuffix}.vma.zst" > $out/nix-support/hydra-build-products
|
2021-12-06 16:07:01 +00:00
|
|
|
'';
|
2023-08-04 22:07:22 +00:00
|
|
|
inherit (cfg.qemuConf) additionalSpace diskSize bootSize;
|
2021-12-06 16:07:01 +00:00
|
|
|
format = "raw";
|
|
|
|
inherit config lib pkgs;
|
|
|
|
};
|
|
|
|
|
|
|
|
boot = {
|
|
|
|
growPartition = true;
|
|
|
|
kernelParams = [ "console=ttyS0" ];
|
2022-11-27 09:42:12 +00:00
|
|
|
loader.grub = {
|
|
|
|
device = lib.mkDefault (if (hasNoFsPartition || supportBios) then
|
|
|
|
# Even if there is a separate no-fs partition ("/dev/disk/by-partlabel/no-fs" i.e. "/dev/vda2"),
|
|
|
|
# which will be used the bootloader, do not set it as loader.grub.device.
|
|
|
|
# GRUB installation fails, unless the whole disk is selected.
|
|
|
|
"/dev/vda"
|
|
|
|
else
|
|
|
|
"nodev");
|
|
|
|
efiSupport = lib.mkDefault supportEfi;
|
|
|
|
efiInstallAsRemovable = lib.mkDefault supportEfi;
|
|
|
|
};
|
|
|
|
|
2021-12-06 16:07:01 +00:00
|
|
|
loader.timeout = 0;
|
|
|
|
initrd.availableKernelModules = [ "uas" "virtio_blk" "virtio_pci" ];
|
|
|
|
};
|
|
|
|
|
|
|
|
fileSystems."/" = {
|
|
|
|
device = "/dev/disk/by-label/nixos";
|
|
|
|
autoResize = true;
|
|
|
|
fsType = "ext4";
|
|
|
|
};
|
2022-11-27 09:42:12 +00:00
|
|
|
fileSystems."/boot" = lib.mkIf hasBootPartition {
|
|
|
|
device = "/dev/disk/by-label/ESP";
|
|
|
|
fsType = "vfat";
|
|
|
|
};
|
2021-12-06 16:07:01 +00:00
|
|
|
|
2024-06-05 15:53:02 +00:00
|
|
|
networking = mkIf cfg.cloudInit.enable {
|
|
|
|
hostName = mkForce "";
|
|
|
|
useDHCP = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
services = {
|
|
|
|
cloud-init = mkIf cfg.cloudInit.enable {
|
|
|
|
enable = true;
|
|
|
|
network.enable = true;
|
|
|
|
};
|
|
|
|
sshd.enable = mkDefault true;
|
|
|
|
qemuGuest.enable = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
proxmox.qemuExtraConf.${cfg.cloudInit.device} = "${cfg.cloudInit.defaultStorage}:vm-9999-cloudinit,media=cdrom";
|
2021-12-06 16:07:01 +00:00
|
|
|
};
|
|
|
|
}
|