nixos/virtualisation: format image-related files

This commit is contained in:
phaer 2024-10-17 18:27:37 +02:00
parent 1d7922b778
commit 88b285c01d
12 changed files with 1461 additions and 1179 deletions

View File

@ -1,12 +1,23 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkOption optionalString types versionAtLeast; inherit (lib)
mkOption
optionalString
types
versionAtLeast
;
inherit (lib.options) literalExpression; inherit (lib.options) literalExpression;
cfg = config.amazonImage; cfg = config.amazonImage;
amiBootMode = if config.ec2.efi then "uefi" else "legacy-bios"; amiBootMode = if config.ec2.efi then "uefi" else "legacy-bios";
in { in
{
imports = [ ../../../modules/virtualisation/amazon-image.nix ]; imports = [ ../../../modules/virtualisation/amazon-image.nix ];
@ -14,11 +25,11 @@ in {
# experience, which prior to 4.15 was 255. # experience, which prior to 4.15 was 255.
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nvme-ebs-volumes.html#timeout-nvme-ebs-volumes # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nvme-ebs-volumes.html#timeout-nvme-ebs-volumes
config.boot.kernelParams = config.boot.kernelParams =
let timeout = let
if versionAtLeast config.boot.kernelPackages.kernel.version "4.15" timeout =
then "4294967295" if versionAtLeast config.boot.kernelPackages.kernel.version "4.15" then "4294967295" else "255";
else "255"; in
in [ "nvme_core.io_timeout=${timeout}" ]; [ "nvme_core.io_timeout=${timeout}" ];
options.amazonImage = { options.amazonImage = {
name = mkOption { name = mkOption {
@ -34,7 +45,7 @@ in {
} }
] ]
''; '';
default = []; default = [ ];
description = '' description = ''
This option lists files to be copied to fixed locations in the This option lists files to be copied to fixed locations in the
generated image. Glob patterns work. generated image. Glob patterns work.
@ -49,15 +60,19 @@ in {
}; };
format = mkOption { format = mkOption {
type = types.enum [ "raw" "qcow2" "vpc" ]; type = types.enum [
"raw"
"qcow2"
"vpc"
];
default = "vpc"; default = "vpc";
description = "The image format to output"; description = "The image format to output";
}; };
}; };
config.system.build.amazonImage = let config.system.build.amazonImage =
configFile = pkgs.writeText "configuration.nix" let
'' configFile = pkgs.writeText "configuration.nix" ''
{ modulesPath, ... }: { { modulesPath, ... }: {
imports = [ "''${modulesPath}/virtualisation/amazon-image.nix" ]; imports = [ "''${modulesPath}/virtualisation/amazon-image.nix" ];
${optionalString config.ec2.efi '' ${optionalString config.ec2.efi ''
@ -70,91 +85,102 @@ in {
} }
''; '';
zfsBuilder = import ../../../lib/make-multi-disk-zfs-image.nix { zfsBuilder = import ../../../lib/make-multi-disk-zfs-image.nix {
inherit lib config configFile pkgs; inherit
inherit (cfg) contents format name; lib
config
configFile
pkgs
;
inherit (cfg) contents format name;
includeChannel = true; includeChannel = true;
bootSize = 1000; # 1G is the minimum EBS volume bootSize = 1000; # 1G is the minimum EBS volume
rootSize = cfg.sizeMB; rootSize = cfg.sizeMB;
rootPoolProperties = { rootPoolProperties = {
ashift = 12; ashift = 12;
autoexpand = "on"; autoexpand = "on";
};
datasets = config.ec2.zfs.datasets;
postVM = ''
extension=''${rootDiskImage##*.}
friendlyName=$out/${cfg.name}
rootDisk="$friendlyName.root.$extension"
bootDisk="$friendlyName.boot.$extension"
mv "$rootDiskImage" "$rootDisk"
mv "$bootDiskImage" "$bootDisk"
mkdir -p $out/nix-support
echo "file ${cfg.format} $bootDisk" >> $out/nix-support/hydra-build-products
echo "file ${cfg.format} $rootDisk" >> $out/nix-support/hydra-build-products
${pkgs.jq}/bin/jq -n \
--arg system_label ${lib.escapeShellArg config.system.nixos.label} \
--arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \
--arg root_logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$rootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$bootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_mode "${amiBootMode}" \
--arg root "$rootDisk" \
--arg boot "$bootDisk" \
'{}
| .label = $system_label
| .boot_mode = $boot_mode
| .system = $system
| .disks.boot.logical_bytes = $boot_logical_bytes
| .disks.boot.file = $boot
| .disks.root.logical_bytes = $root_logical_bytes
| .disks.root.file = $root
' > $out/nix-support/image-info.json
'';
}; };
datasets = config.ec2.zfs.datasets; extBuilder = import ../../../lib/make-disk-image.nix {
inherit
lib
config
configFile
pkgs
;
postVM = '' inherit (cfg) contents format name;
extension=''${rootDiskImage##*.}
friendlyName=$out/${cfg.name}
rootDisk="$friendlyName.root.$extension"
bootDisk="$friendlyName.boot.$extension"
mv "$rootDiskImage" "$rootDisk"
mv "$bootDiskImage" "$bootDisk"
mkdir -p $out/nix-support fsType = "ext4";
echo "file ${cfg.format} $bootDisk" >> $out/nix-support/hydra-build-products partitionTableType = if config.ec2.efi then "efi" else "legacy+gpt";
echo "file ${cfg.format} $rootDisk" >> $out/nix-support/hydra-build-products
${pkgs.jq}/bin/jq -n \ diskSize = cfg.sizeMB;
--arg system_label ${lib.escapeShellArg config.system.nixos.label} \
--arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \
--arg root_logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$rootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$bootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_mode "${amiBootMode}" \
--arg root "$rootDisk" \
--arg boot "$bootDisk" \
'{}
| .label = $system_label
| .boot_mode = $boot_mode
| .system = $system
| .disks.boot.logical_bytes = $boot_logical_bytes
| .disks.boot.file = $boot
| .disks.root.logical_bytes = $root_logical_bytes
| .disks.root.file = $root
' > $out/nix-support/image-info.json
'';
};
extBuilder = import ../../../lib/make-disk-image.nix { postVM = ''
inherit lib config configFile pkgs; extension=''${diskImage##*.}
friendlyName=$out/${cfg.name}.$extension
mv "$diskImage" "$friendlyName"
diskImage=$friendlyName
inherit (cfg) contents format name; mkdir -p $out/nix-support
echo "file ${cfg.format} $diskImage" >> $out/nix-support/hydra-build-products
fsType = "ext4"; ${pkgs.jq}/bin/jq -n \
partitionTableType = if config.ec2.efi then "efi" else "legacy+gpt"; --arg system_label ${lib.escapeShellArg config.system.nixos.label} \
--arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \
diskSize = cfg.sizeMB; --arg logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$diskImage" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_mode "${amiBootMode}" \
postVM = '' --arg file "$diskImage" \
extension=''${diskImage##*.} '{}
friendlyName=$out/${cfg.name}.$extension | .label = $system_label
mv "$diskImage" "$friendlyName" | .boot_mode = $boot_mode
diskImage=$friendlyName | .system = $system
| .logical_bytes = $logical_bytes
mkdir -p $out/nix-support | .file = $file
echo "file ${cfg.format} $diskImage" >> $out/nix-support/hydra-build-products | .disks.root.logical_bytes = $logical_bytes
| .disks.root.file = $file
${pkgs.jq}/bin/jq -n \ ' > $out/nix-support/image-info.json
--arg system_label ${lib.escapeShellArg config.system.nixos.label} \ '';
--arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \ };
--arg logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$diskImage" | ${pkgs.jq}/bin/jq '."virtual-size"')" \ in
--arg boot_mode "${amiBootMode}" \ if config.ec2.zfs.enable then zfsBuilder else extBuilder;
--arg file "$diskImage" \
'{}
| .label = $system_label
| .boot_mode = $boot_mode
| .system = $system
| .logical_bytes = $logical_bytes
| .file = $file
| .disks.root.logical_bytes = $logical_bytes
| .disks.root.file = $file
' > $out/nix-support/image-info.json
'';
};
in if config.ec2.zfs.enable then zfsBuilder else extBuilder;
meta.maintainers = with lib.maintainers; [ arianvp ]; meta.maintainers = with lib.maintainers; [ arianvp ];
} }

View File

@ -1,6 +1,11 @@
# nix-build '<nixpkgs/nixos>' -A config.system.build.openstackImage --arg configuration "{ imports = [ ./nixos/maintainers/scripts/openstack/openstack-image.nix ]; }" # nix-build '<nixpkgs/nixos>' -A config.system.build.openstackImage --arg configuration "{ imports = [ ./nixos/maintainers/scripts/openstack/openstack-image.nix ]; }"
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkOption types; inherit (lib) mkOption types;
copyChannel = true; copyChannel = true;
@ -12,7 +17,6 @@ in
../../../modules/virtualisation/openstack-config.nix ../../../modules/virtualisation/openstack-config.nix
] ++ (lib.optional copyChannel ../../../modules/installer/cd-dvd/channel.nix); ] ++ (lib.optional copyChannel ../../../modules/installer/cd-dvd/channel.nix);
options.openstackImage = { options.openstackImage = {
name = mkOption { name = mkOption {
type = types.str; type = types.str;
@ -33,7 +37,10 @@ in
}; };
format = mkOption { format = mkOption {
type = types.enum [ "raw" "qcow2" ]; type = types.enum [
"raw"
"qcow2"
];
default = "qcow2"; default = "qcow2";
description = "The image format to output"; description = "The image format to output";
}; };
@ -59,13 +66,12 @@ in
inherit (cfg) contents format name; inherit (cfg) contents format name;
pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package
configFile = pkgs.writeText "configuration.nix" configFile = pkgs.writeText "configuration.nix" ''
'' { modulesPath, ... }: {
{ modulesPath, ... }: { imports = [ "''${modulesPath}/virtualisation/openstack-config.nix" ];
imports = [ "''${modulesPath}/virtualisation/openstack-config.nix" ]; openstack.zfs.enable = true;
openstack.zfs.enable = true; }
} '';
'';
includeChannel = copyChannel; includeChannel = copyChannel;

View File

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
with lib; with lib;
let let
@ -35,7 +40,12 @@ in
}; };
vmGeneration = mkOption { vmGeneration = mkOption {
type = with types; enum [ "v1" "v2" ]; type =
with types;
enum [
"v1"
"v2"
];
default = "v1"; default = "v1";
description = '' description = ''
VM Generation to use. VM Generation to use.

View File

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
with lib; with lib;
let let
@ -31,7 +36,10 @@ in
}; };
virtualisation.digitalOceanImage.compressionMethod = mkOption { virtualisation.digitalOceanImage.compressionMethod = mkOption {
type = types.enum [ "gzip" "bzip2" ]; type = types.enum [
"gzip"
"bzip2"
];
default = "gzip"; default = "gzip";
example = "bzip2"; example = "bzip2";
description = '' description = ''
@ -48,23 +56,32 @@ in
system.build.digitalOceanImage = import ../../lib/make-disk-image.nix { system.build.digitalOceanImage = import ../../lib/make-disk-image.nix {
name = "digital-ocean-image"; name = "digital-ocean-image";
format = "qcow2"; format = "qcow2";
postVM = let postVM =
compress = { let
"gzip" = "${pkgs.gzip}/bin/gzip"; compress =
"bzip2" = "${pkgs.bzip2}/bin/bzip2"; {
}.${cfg.compressionMethod}; "gzip" = "${pkgs.gzip}/bin/gzip";
in '' "bzip2" = "${pkgs.bzip2}/bin/bzip2";
${compress} $diskImage }
''; .${cfg.compressionMethod};
configFile = if cfg.configFile == null in
then config.virtualisation.digitalOcean.defaultConfigFile ''
else cfg.configFile; ${compress} $diskImage
'';
configFile =
if cfg.configFile == null then
config.virtualisation.digitalOcean.defaultConfigFile
else
cfg.configFile;
inherit (cfg) diskSize; inherit (cfg) diskSize;
inherit config lib pkgs; inherit config lib pkgs;
}; };
}; };
meta.maintainers = with maintainers; [ arianvp eamsden ]; meta.maintainers = with maintainers; [
arianvp
eamsden
];
} }

View File

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
with lib; with lib;
let let
@ -64,7 +69,13 @@ in
system.build.googleComputeImage = import ../../lib/make-disk-image.nix { system.build.googleComputeImage = import ../../lib/make-disk-image.nix {
name = "google-compute-image"; name = "google-compute-image";
postVM = '' postVM = ''
PATH=$PATH:${with pkgs; lib.makeBinPath [ gnutar gzip ]} PATH=$PATH:${
with pkgs;
lib.makeBinPath [
gnutar
gzip
]
}
pushd $out pushd $out
mv $diskImage disk.raw mv $diskImage disk.raw
tar -Sc disk.raw | gzip -${toString cfg.compressionLevel} > \ tar -Sc disk.raw | gzip -${toString cfg.compressionLevel} > \

View File

@ -1,11 +1,17 @@
{ config, pkgs, lib, ... }: {
config,
pkgs,
lib,
...
}:
with lib; with lib;
let let
cfg = config.hyperv; cfg = config.hyperv;
in { in
{
options = { options = {
hyperv = { hyperv = {
baseImageSize = mkOption { baseImageSize = mkOption {

View File

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
with lib; with lib;
let let

View File

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.oci; cfg = config.oci;
@ -25,7 +30,10 @@ in
after = [ "network-online.target" ]; after = [ "network-online.target" ];
wants = [ "network-online.target" ]; wants = [ "network-online.target" ];
path = [ pkgs.coreutils pkgs.curl ]; path = [
pkgs.coreutils
pkgs.curl
];
script = '' script = ''
mkdir -m 0700 -p /root/.ssh mkdir -m 0700 -p /root/.ssh
if [ -f /root/.ssh/authorized_keys ]; then if [ -f /root/.ssh/authorized_keys ]; then

View File

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
{ {
options = { options = {
oci = { oci = {

View File

@ -1,4 +1,9 @@
{ config, pkgs, lib, ... }: {
config,
pkgs,
lib,
...
}:
with lib; with lib;
@ -54,7 +59,10 @@ with lib;
''; '';
}; };
bios = mkOption { bios = mkOption {
type = types.enum [ "seabios" "ovmf" ]; type = types.enum [
"seabios"
"ovmf"
];
default = "seabios"; default = "seabios";
description = '' description = ''
Select BIOS implementation (seabios = Legacy BIOS, ovmf = UEFI). Select BIOS implementation (seabios = Legacy BIOS, ovmf = UEFI).
@ -124,8 +132,13 @@ with lib;
}; };
}; };
qemuExtraConf = mkOption { qemuExtraConf = mkOption {
type = with types; attrsOf (oneOf [ str int ]); type =
default = {}; with types;
attrsOf (oneOf [
str
int
]);
default = { };
example = literalExpression '' example = literalExpression ''
{ {
cpu = "host"; cpu = "host";
@ -137,7 +150,12 @@ with lib;
''; '';
}; };
partitionTableType = mkOption { partitionTableType = mkOption {
type = types.enum [ "efi" "hybrid" "legacy" "legacy+gpt" ]; type = types.enum [
"efi"
"hybrid"
"legacy"
"legacy+gpt"
];
description = '' description = ''
Partition table type to use. See make-disk-image.nix partitionTableType for details. 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'. Defaults to 'legacy' for 'proxmox.qemuConf.bios="seabios"' (default), other bios values defaults to 'efi'.
@ -185,142 +203,162 @@ with lib;
}; };
}; };
config = let config =
cfg = config.proxmox; let
cfgLine = name: value: '' cfg = config.proxmox;
${name}: ${builtins.toString value} cfgLine = name: value: ''
''; ${name}: ${builtins.toString value}
virtio0Storage = builtins.head (builtins.split ":" cfg.qemuConf.virtio0);
cfgFile = fileName: properties: pkgs.writeTextDir fileName ''
# generated by NixOS
${lib.concatStrings (lib.mapAttrsToList cfgLine properties)}
#qmdump#map:virtio0:drive-virtio0:${virtio0Storage}:raw:
'';
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";
in {
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";
}
];
system.build.VMA = import ../../lib/make-disk-image.nix {
name = "proxmox-${cfg.filenameSuffix}";
inherit (cfg) partitionTableType;
postVM = let
# Build qemu with PVE's patch that adds support for the VMA format
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 {
# Check https://github.com/proxmox/pve-qemu/tree/master for the version
# of qemu and patch to use
version = "9.0.0";
src = pkgs.fetchurl {
url = "https://download.qemu.org/qemu-${version}.tar.xz";
hash = "sha256-MnCKxmww2MiSYz6paMdxwcdtWX1w3erSGg0izPOG2mk=";
};
patches = [
# Proxmox' VMA tool is published as a particular patch upon QEMU
"${pkgs.fetchFromGitHub {
owner = "proxmox";
repo = "pve-qemu";
rev = "14afbdd55f04d250bd679ca1ad55d3f47cd9d4c8";
hash = "sha256-lSJQA5SHIHfxJvMLIID2drv2H43crTPMNIlIT37w9Nc=";
}}/debian/patches/pve/0027-PVE-Backup-add-vma-backup-format-code.patch"
];
buildInputs = super.buildInputs ++ [ pkgs.libuuid ];
nativeBuildInputs = super.nativeBuildInputs ++ [ pkgs.perl ];
});
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/
mkdir -p $out/nix-support
echo "file vma $out/vzdump-qemu-${cfg.filenameSuffix}.vma.zst" > $out/nix-support/hydra-build-products
''; '';
inherit (cfg.qemuConf) additionalSpace diskSize bootSize; virtio0Storage = builtins.head (builtins.split ":" cfg.qemuConf.virtio0);
format = "raw"; cfgFile =
inherit config lib pkgs; fileName: properties:
}; pkgs.writeTextDir fileName ''
# generated by NixOS
${lib.concatStrings (lib.mapAttrsToList cfgLine properties)}
#qmdump#map:virtio0:drive-virtio0:${virtio0Storage}:raw:
'';
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";
in
{
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";
}
];
system.build.VMA = import ../../lib/make-disk-image.nix {
name = "proxmox-${cfg.filenameSuffix}";
inherit (cfg) partitionTableType;
postVM =
let
# Build qemu with PVE's patch that adds support for the VMA format
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 {
# Check https://github.com/proxmox/pve-qemu/tree/master for the version
# of qemu and patch to use
version = "9.0.0";
src = pkgs.fetchurl {
url = "https://download.qemu.org/qemu-${version}.tar.xz";
hash = "sha256-MnCKxmww2MiSYz6paMdxwcdtWX1w3erSGg0izPOG2mk=";
};
patches = [
# Proxmox' VMA tool is published as a particular patch upon QEMU
"${
pkgs.fetchFromGitHub {
owner = "proxmox";
repo = "pve-qemu";
rev = "14afbdd55f04d250bd679ca1ad55d3f47cd9d4c8";
hash = "sha256-lSJQA5SHIHfxJvMLIID2drv2H43crTPMNIlIT37w9Nc=";
}
}/debian/patches/pve/0027-PVE-Backup-add-vma-backup-format-code.patch"
];
boot = { buildInputs = super.buildInputs ++ [ pkgs.libuuid ];
growPartition = true; nativeBuildInputs = super.nativeBuildInputs ++ [ pkgs.perl ];
kernelParams = [ "console=ttyS0" ];
loader.grub = { });
device = lib.mkDefault (if (hasNoFsPartition || supportBios) then in
# 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. ${vma}/bin/vma create "vzdump-qemu-${cfg.filenameSuffix}.vma" \
# GRUB installation fails, unless the whole disk is selected. -c ${
"/dev/vda" cfgFile "qemu-server.conf" (cfg.qemuConf // cfg.qemuExtraConf)
else }/qemu-server.conf drive-virtio0=$diskImage
"nodev"); rm $diskImage
efiSupport = lib.mkDefault supportEfi; ${pkgs.zstd}/bin/zstd "vzdump-qemu-${cfg.filenameSuffix}.vma"
efiInstallAsRemovable = lib.mkDefault supportEfi; mv "vzdump-qemu-${cfg.filenameSuffix}.vma.zst" $out/
mkdir -p $out/nix-support
echo "file vma $out/vzdump-qemu-${cfg.filenameSuffix}.vma.zst" > $out/nix-support/hydra-build-products
'';
inherit (cfg.qemuConf) additionalSpace diskSize bootSize;
format = "raw";
inherit config lib pkgs;
}; };
loader.timeout = 0; boot = {
initrd.availableKernelModules = [ "uas" "virtio_blk" "virtio_pci" ]; growPartition = true;
}; kernelParams = [ "console=ttyS0" ];
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;
};
fileSystems."/" = { loader.timeout = 0;
device = "/dev/disk/by-label/nixos"; initrd.availableKernelModules = [
autoResize = true; "uas"
fsType = "ext4"; "virtio_blk"
}; "virtio_pci"
fileSystems."/boot" = lib.mkIf hasBootPartition { ];
device = "/dev/disk/by-label/ESP";
fsType = "vfat";
};
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"; fileSystems."/" = {
}; device = "/dev/disk/by-label/nixos";
autoResize = true;
fsType = "ext4";
};
fileSystems."/boot" = lib.mkIf hasBootPartition {
device = "/dev/disk/by-label/ESP";
fsType = "vfat";
};
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";
};
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,15 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.virtualbox; cfg = config.virtualbox;
in { in
{
options = { options = {
virtualbox = { virtualbox = {
@ -51,7 +57,14 @@ in {
''; '';
}; };
params = lib.mkOption { params = lib.mkOption {
type = with lib.types; attrsOf (oneOf [ str int bool (listOf str) ]); type =
with lib.types;
attrsOf (oneOf [
str
int
bool
(listOf str)
]);
example = { example = {
audio = "alsa"; audio = "alsa";
rtcuseutc = "on"; rtcuseutc = "on";
@ -64,11 +77,21 @@ in {
''; '';
}; };
exportParams = lib.mkOption { exportParams = lib.mkOption {
type = with lib.types; listOf (oneOf [ str int bool (listOf str) ]); type =
with lib.types;
listOf (oneOf [
str
int
bool
(listOf str)
]);
example = [ example = [
"--vsys" "0" "--vendor" "ACME Inc." "--vsys"
"0"
"--vendor"
"ACME Inc."
]; ];
default = []; default = [ ];
description = '' description = ''
Parameters passed to the Virtualbox export command. Parameters passed to the Virtualbox export command.
@ -86,23 +109,25 @@ in {
mountPoint = "/home/demo/storage"; mountPoint = "/home/demo/storage";
size = 100 * 1024; size = 100 * 1024;
}; };
type = lib.types.nullOr (lib.types.submodule { type = lib.types.nullOr (
options = { lib.types.submodule {
size = lib.mkOption { options = {
type = lib.types.int; size = lib.mkOption {
description = "Size in MiB"; type = lib.types.int;
description = "Size in MiB";
};
label = lib.mkOption {
type = lib.types.str;
default = "vm-extra-storage";
description = "Label for the disk partition";
};
mountPoint = lib.mkOption {
type = lib.types.str;
description = "Path where to mount this disk.";
};
}; };
label = lib.mkOption { }
type = lib.types.str; );
default = "vm-extra-storage";
description = "Label for the disk partition";
};
mountPoint = lib.mkOption {
type = lib.types.str;
description = "Path where to mount this disk.";
};
};
});
}; };
postExportCommands = lib.mkOption { postExportCommands = lib.mkOption {
type = lib.types.lines; type = lib.types.lines;
@ -122,7 +147,14 @@ in {
''; '';
}; };
storageController = lib.mkOption { storageController = lib.mkOption {
type = with lib.types; attrsOf (oneOf [ str int bool (listOf str) ]); type =
with lib.types;
attrsOf (oneOf [
str
int
bool
(listOf str)
]);
example = { example = {
name = "SCSI"; name = "SCSI";
add = "scsi"; add = "scsi";
@ -175,77 +207,80 @@ in {
diskSize = cfg.baseImageSize; diskSize = cfg.baseImageSize;
additionalSpace = "${toString cfg.baseImageFreeSpace}M"; additionalSpace = "${toString cfg.baseImageFreeSpace}M";
postVM = postVM = ''
'' export HOME=$PWD
export HOME=$PWD export PATH=${pkgs.virtualbox}/bin:$PATH
export PATH=${pkgs.virtualbox}/bin:$PATH
echo "converting image to VirtualBox format..." echo "converting image to VirtualBox format..."
VBoxManage convertfromraw $diskImage disk.vdi VBoxManage convertfromraw $diskImage disk.vdi
${lib.optionalString (cfg.extraDisk != null) '' ${lib.optionalString (cfg.extraDisk != null) ''
echo "creating extra disk: data-disk.raw" echo "creating extra disk: data-disk.raw"
dataDiskImage=data-disk.raw dataDiskImage=data-disk.raw
truncate -s ${toString cfg.extraDisk.size}M $dataDiskImage truncate -s ${toString cfg.extraDisk.size}M $dataDiskImage
parted --script $dataDiskImage -- \ parted --script $dataDiskImage -- \
mklabel msdos \ mklabel msdos \
mkpart primary ext4 1MiB -1 mkpart primary ext4 1MiB -1
eval $(partx $dataDiskImage -o START,SECTORS --nr 1 --pairs) eval $(partx $dataDiskImage -o START,SECTORS --nr 1 --pairs)
mkfs.ext4 -F -L ${cfg.extraDisk.label} $dataDiskImage -E offset=$(sectorsToBytes $START) $(sectorsToKilobytes $SECTORS)K mkfs.ext4 -F -L ${cfg.extraDisk.label} $dataDiskImage -E offset=$(sectorsToBytes $START) $(sectorsToKilobytes $SECTORS)K
echo "creating extra disk: data-disk.vdi" echo "creating extra disk: data-disk.vdi"
VBoxManage convertfromraw $dataDiskImage data-disk.vdi VBoxManage convertfromraw $dataDiskImage data-disk.vdi
''} ''}
echo "creating VirtualBox VM..." echo "creating VirtualBox VM..."
vmName="${cfg.vmName}"; vmName="${cfg.vmName}";
VBoxManage createvm --name "$vmName" --register \ VBoxManage createvm --name "$vmName" --register \
--ostype ${if pkgs.stdenv.hostPlatform.system == "x86_64-linux" then "Linux26_64" else "Linux26"} --ostype ${if pkgs.stdenv.hostPlatform.system == "x86_64-linux" then "Linux26_64" else "Linux26"}
VBoxManage modifyvm "$vmName" \ VBoxManage modifyvm "$vmName" \
--memory ${toString cfg.memorySize} \ --memory ${toString cfg.memorySize} \
${lib.cli.toGNUCommandLineShell { } cfg.params} ${lib.cli.toGNUCommandLineShell { } cfg.params}
VBoxManage storagectl "$vmName" ${lib.cli.toGNUCommandLineShell { } cfg.storageController} VBoxManage storagectl "$vmName" ${lib.cli.toGNUCommandLineShell { } cfg.storageController}
VBoxManage storageattach "$vmName" --storagectl ${cfg.storageController.name} --port 0 --device 0 --type hdd \ VBoxManage storageattach "$vmName" --storagectl ${cfg.storageController.name} --port 0 --device 0 --type hdd \
--medium disk.vdi --medium disk.vdi
${lib.optionalString (cfg.extraDisk != null) '' ${lib.optionalString (cfg.extraDisk != null) ''
VBoxManage storageattach "$vmName" --storagectl ${cfg.storageController.name} --port 1 --device 0 --type hdd \ VBoxManage storageattach "$vmName" --storagectl ${cfg.storageController.name} --port 1 --device 0 --type hdd \
--medium data-disk.vdi --medium data-disk.vdi
''} ''}
echo "exporting VirtualBox VM..." echo "exporting VirtualBox VM..."
mkdir -p $out mkdir -p $out
fn="$out/${cfg.vmFileName}" fn="$out/${cfg.vmFileName}"
VBoxManage export "$vmName" --output "$fn" --options manifest ${lib.escapeShellArgs cfg.exportParams} VBoxManage export "$vmName" --output "$fn" --options manifest ${lib.escapeShellArgs cfg.exportParams}
${cfg.postExportCommands} ${cfg.postExportCommands}
rm -v $diskImage rm -v $diskImage
mkdir -p $out/nix-support mkdir -p $out/nix-support
echo "file ova $fn" >> $out/nix-support/hydra-build-products echo "file ova $fn" >> $out/nix-support/hydra-build-products
''; '';
}; };
fileSystems = { fileSystems =
"/" = { {
device = "/dev/disk/by-label/nixos"; "/" = {
autoResize = true; device = "/dev/disk/by-label/nixos";
fsType = "ext4"; autoResize = true;
}; fsType = "ext4";
} // (lib.optionalAttrs (cfg.extraDisk != null) { };
${cfg.extraDisk.mountPoint} = { }
device = "/dev/disk/by-label/" + cfg.extraDisk.label; // (lib.optionalAttrs (cfg.extraDisk != null) {
autoResize = true; ${cfg.extraDisk.mountPoint} = {
fsType = "ext4"; device = "/dev/disk/by-label/" + cfg.extraDisk.label;
}; autoResize = true;
}); fsType = "ext4";
};
});
boot.growPartition = true; boot.growPartition = true;
boot.loader.grub.device = "/dev/sda"; boot.loader.grub.device = "/dev/sda";
swapDevices = [{ swapDevices = [
device = "/var/swap"; {
size = 2048; device = "/var/swap";
}]; size = 2048;
}
];
virtualisation.virtualbox.guest.enable = true; virtualisation.virtualbox.guest.enable = true;