···
# `config'. By default, the Nix store is shared read-only with the
# host, which makes (re)building VMs very efficient.
7
-
{ config, lib, pkgs, options, ... }:
···
consoles = lib.concatMapStringsSep " " (c: "console=${c}") cfg.qemu.consoles;
25
-
driveOpts = { ... }: {
31
-
description = "The file image used for this drive.";
39
+
description = "The file image used for this drive.";
42
+
driveExtraOpts = mkOption {
43
+
type = types.attrsOf types.str;
45
+
description = "Extra options passed to drive flag.";
34
-
driveExtraOpts = mkOption {
35
-
type = types.attrsOf types.str;
37
-
description = "Extra options passed to drive flag.";
48
+
deviceExtraOpts = mkOption {
49
+
type = types.attrsOf types.str;
51
+
description = "Extra options passed to device flag.";
40
-
deviceExtraOpts = mkOption {
41
-
type = types.attrsOf types.str;
43
-
description = "Extra options passed to device flag.";
55
+
type = types.nullOr types.str;
57
+
description = "A name for the drive. Must be unique in the drives list. Not passed to qemu.";
47
-
type = types.nullOr types.str;
49
-
description = "A name for the drive. Must be unique in the drives list. Not passed to qemu.";
64
+
selectPartitionTableLayout =
65
+
{ useEFIBoot, useDefaultFilesystems }:
66
+
if useDefaultFilesystems then if useEFIBoot then "efi" else "legacy" else "none";
56
-
selectPartitionTableLayout = { useEFIBoot, useDefaultFilesystems }:
57
-
if useDefaultFilesystems then
58
-
if useEFIBoot then "efi" else "legacy"
61
-
driveCmdline = idx: { file, driveExtraOpts, deviceExtraOpts, ... }:
drvId = "drive${toString idx}";
64
-
mkKeyValue = generators.mkKeyValueDefault {} "=";
78
+
mkKeyValue = generators.mkKeyValueDefault { } "=";
mkOpts = opts: concatStringsSep "," (mapAttrsToList mkKeyValue opts);
66
-
driveOpts = mkOpts (driveExtraOpts // {
72
-
deviceOpts = mkOpts (deviceExtraOpts // {
80
+
driveOpts = mkOpts (
89
+
deviceOpts = mkOpts (
if cfg.qemu.diskInterface == "scsi" then
"-device lsi53c895a -device scsi-hd,${deviceOpts}"
"-device virtio-blk-pci,${deviceOpts}";
81
-
"-drive ${driveOpts} ${device}";
101
+
"-drive ${driveOpts} ${device}";
drivesCmdLine = drives: concatStringsSep "\\\n " (imap1 driveCmdline drives);
# Shell script to start the VM.
88
-
#! ${hostPkgs.runtimeShell}
107
+
#! ${hostPkgs.runtimeShell}
90
-
export PATH=${makeBinPath [ hostPkgs.coreutils ]}''${PATH:+:}$PATH
109
+
export PATH=${makeBinPath [ hostPkgs.coreutils ]}''${PATH:+:}$PATH
94
-
# Create an empty ext4 filesystem image. A filesystem image does not
95
-
# contain a partition table but just a filesystem.
96
-
createEmptyFilesystemImage() {
99
-
local temp=$(mktemp)
100
-
${qemu}/bin/qemu-img create -f raw "$temp" "$size"
101
-
${hostPkgs.e2fsprogs}/bin/mkfs.ext4 -L ${rootFilesystemLabel} "$temp"
102
-
${qemu}/bin/qemu-img convert -f raw -O qcow2 "$temp" "$name"
106
-
NIX_DISK_IMAGE=$(readlink -f "''${NIX_DISK_IMAGE:-${toString config.virtualisation.diskImage}}") || test -z "$NIX_DISK_IMAGE"
113
+
# Create an empty ext4 filesystem image. A filesystem image does not
114
+
# contain a partition table but just a filesystem.
115
+
createEmptyFilesystemImage() {
118
+
local temp=$(mktemp)
119
+
${qemu}/bin/qemu-img create -f raw "$temp" "$size"
120
+
${hostPkgs.e2fsprogs}/bin/mkfs.ext4 -L ${rootFilesystemLabel} "$temp"
121
+
${qemu}/bin/qemu-img convert -f raw -O qcow2 "$temp" "$name"
108
-
if test -n "$NIX_DISK_IMAGE" && ! test -e "$NIX_DISK_IMAGE"; then
109
-
echo "Disk image do not exist, creating the virtualisation disk image..."
125
+
NIX_DISK_IMAGE=$(readlink -f "''${NIX_DISK_IMAGE:-${toString config.virtualisation.diskImage}}") || test -z "$NIX_DISK_IMAGE"
111
-
${if (cfg.useBootLoader && cfg.useDefaultFilesystems) then ''
112
-
# Create a writable qcow2 image using the systemImage as a backing
127
+
if test -n "$NIX_DISK_IMAGE" && ! test -e "$NIX_DISK_IMAGE"; then
128
+
echo "Disk image do not exist, creating the virtualisation disk image..."
115
-
# CoW prevent size to be attributed to an image.
116
-
# FIXME: raise this issue to upstream.
117
-
${qemu}/bin/qemu-img create \
119
-
-b ${systemImage}/nixos.qcow2 \
122
-
'' else if cfg.useDefaultFilesystems then ''
123
-
createEmptyFilesystemImage "$NIX_DISK_IMAGE" "${toString cfg.diskSize}M"
125
-
# Create an empty disk image without a filesystem.
126
-
${qemu}/bin/qemu-img create -f qcow2 "$NIX_DISK_IMAGE" "${toString cfg.diskSize}M"
129
-
echo "Virtualisation disk image created."
131
+
if (cfg.useBootLoader && cfg.useDefaultFilesystems) then
133
+
# Create a writable qcow2 image using the systemImage as a backing
132
-
# Create a directory for storing temporary data of the running VM.
133
-
if [ -z "$TMPDIR" ] || [ -z "$USE_TMPDIR" ]; then
134
-
TMPDIR=$(mktemp -d nix-vm.XXXXXXXXXX --tmpdir)
136
+
# CoW prevent size to be attributed to an image.
137
+
# FIXME: raise this issue to upstream.
138
+
${qemu}/bin/qemu-img create \
140
+
-b ${systemImage}/nixos.qcow2 \
144
+
else if cfg.useDefaultFilesystems then
146
+
createEmptyFilesystemImage "$NIX_DISK_IMAGE" "${toString cfg.diskSize}M"
150
+
# Create an empty disk image without a filesystem.
151
+
${qemu}/bin/qemu-img create -f qcow2 "$NIX_DISK_IMAGE" "${toString cfg.diskSize}M"
154
+
echo "Virtualisation disk image created."
137
-
${lib.optionalString (cfg.useNixStoreImage) ''
138
-
echo "Creating Nix store image..."
157
+
# Create a directory for storing temporary data of the running VM.
158
+
if [ -z "$TMPDIR" ] || [ -z "$USE_TMPDIR" ]; then
159
+
TMPDIR=$(mktemp -d nix-vm.XXXXXXXXXX --tmpdir)
140
-
${hostPkgs.gnutar}/bin/tar --create \
142
-
--verbatim-files-from \
143
-
--transform 'flags=rSh;s|/nix/store/||' \
144
-
--transform 'flags=rSh;s|~nix~case~hack~[[:digit:]]\+||g' \
145
-
--files-from ${hostPkgs.closureInfo { rootPaths = [ config.system.build.toplevel regInfo ]; }}/store-paths \
146
-
| ${hostPkgs.erofs-utils}/bin/mkfs.erofs \
150
-
-L ${nixStoreFilesystemLabel} \
151
-
-U eb176051-bd15-49b7-9e6b-462e0b467019 \
154
-
"$TMPDIR"/store.img
162
+
${lib.optionalString (cfg.useNixStoreImage) ''
163
+
echo "Creating Nix store image..."
156
-
echo "Created Nix store image."
165
+
${hostPkgs.gnutar}/bin/tar --create \
167
+
--verbatim-files-from \
168
+
--transform 'flags=rSh;s|/nix/store/||' \
169
+
--transform 'flags=rSh;s|~nix~case~hack~[[:digit:]]\+||g' \
171
+
hostPkgs.closureInfo {
173
+
config.system.build.toplevel
178
+
| ${hostPkgs.erofs-utils}/bin/mkfs.erofs \
182
+
-L ${nixStoreFilesystemLabel} \
183
+
-U eb176051-bd15-49b7-9e6b-462e0b467019 \
186
+
"$TMPDIR"/store.img
160
-
# Create a directory for exchanging data with the VM.
161
-
mkdir -p "$TMPDIR/xchg"
188
+
echo "Created Nix store image."
163
-
${lib.optionalString cfg.useHostCerts
165
-
mkdir -p "$TMPDIR/certs"
166
-
if [ -e "$NIX_SSL_CERT_FILE" ]; then
167
-
cp -L "$NIX_SSL_CERT_FILE" "$TMPDIR"/certs/ca-certificates.crt
169
-
echo \$NIX_SSL_CERT_FILE should point to a valid file if virtualisation.useHostCerts is enabled.
191
+
# Create a directory for exchanging data with the VM.
192
+
mkdir -p "$TMPDIR/xchg"
173
-
${lib.optionalString cfg.useEFIBoot
175
-
# Expose EFI variables, it's useful even when we are not using a bootloader (!).
176
-
# We might be interested in having EFI variable storage present even if we aren't booting via UEFI, hence
177
-
# no guard against `useBootLoader`. Examples:
178
-
# - testing PXE boot or other EFI applications
179
-
# - directbooting LinuxBoot, which `kexec()s` into a UEFI environment that can boot e.g. Windows
180
-
NIX_EFI_VARS=$(readlink -f "''${NIX_EFI_VARS:-${config.system.name}-efi-vars.fd}")
181
-
# VM needs writable EFI vars
182
-
if ! test -e "$NIX_EFI_VARS"; then
183
-
${if cfg.efi.keepVariables then
184
-
# We still need the EFI var from the make-disk-image derivation
185
-
# because our "switch-to-configuration" process might
186
-
# write into it and we want to keep this data.
187
-
''cp ${systemImage}/efi-vars.fd "$NIX_EFI_VARS"''
189
-
''cp ${cfg.efi.variables} "$NIX_EFI_VARS"''
191
-
chmod 0644 "$NIX_EFI_VARS"
194
+
${lib.optionalString cfg.useHostCerts ''
195
+
mkdir -p "$TMPDIR/certs"
196
+
if [ -e "$NIX_SSL_CERT_FILE" ]; then
197
+
cp -L "$NIX_SSL_CERT_FILE" "$TMPDIR"/certs/ca-certificates.crt
199
+
echo \$NIX_SSL_CERT_FILE should point to a valid file if virtualisation.useHostCerts is enabled.
195
-
${lib.optionalString cfg.tpm.enable ''
196
-
NIX_SWTPM_DIR=$(readlink -f "''${NIX_SWTPM_DIR:-${config.system.name}-swtpm}")
197
-
mkdir -p "$NIX_SWTPM_DIR"
198
-
${lib.getExe cfg.tpm.package} \
200
-
--tpmstate dir="$NIX_SWTPM_DIR" \
201
-
--ctrl type=unixio,path="$NIX_SWTPM_DIR"/socket,terminate \
202
-
--pid file="$NIX_SWTPM_DIR"/pid --daemon \
204
-
--log file="$NIX_SWTPM_DIR"/stdout,level=6
203
+
${lib.optionalString cfg.useEFIBoot ''
204
+
# Expose EFI variables, it's useful even when we are not using a bootloader (!).
205
+
# We might be interested in having EFI variable storage present even if we aren't booting via UEFI, hence
206
+
# no guard against `useBootLoader`. Examples:
207
+
# - testing PXE boot or other EFI applications
208
+
# - directbooting LinuxBoot, which `kexec()s` into a UEFI environment that can boot e.g. Windows
209
+
NIX_EFI_VARS=$(readlink -f "''${NIX_EFI_VARS:-${config.system.name}-efi-vars.fd}")
210
+
# VM needs writable EFI vars
211
+
if ! test -e "$NIX_EFI_VARS"; then
213
+
if cfg.efi.keepVariables then
214
+
# We still need the EFI var from the make-disk-image derivation
215
+
# because our "switch-to-configuration" process might
216
+
# write into it and we want to keep this data.
217
+
''cp ${systemImage}/efi-vars.fd "$NIX_EFI_VARS"''
219
+
''cp ${cfg.efi.variables} "$NIX_EFI_VARS"''
221
+
chmod 0644 "$NIX_EFI_VARS"
206
-
# Enable `fdflags` builtin in Bash
207
-
# We will need it to perform surgical modification of the file descriptor
208
-
# passed in the coprocess to remove `FD_CLOEXEC`, i.e. close the file descriptor
210
-
# If let alone, it will trigger the coprocess to read EOF when QEMU is `exec`
211
-
# at the end of this script. To work around that, we will just clear
212
-
# the `FD_CLOEXEC` bits as a first step.
213
-
enable -f ${hostPkgs.bash}/lib/bash/fdflags fdflags
214
-
# leave a dangling subprocess because the swtpm ctrl socket has
215
-
# "terminate" when the last connection disconnects, it stops swtpm.
216
-
# When qemu stops, or if the main shell process ends, the coproc will
217
-
# get signaled by virtue of the pipe between main and coproc ending.
218
-
# Which in turns triggers a socat connect-disconnect to swtpm which
220
-
coproc waitingswtpm {
222
-
echo "" | ${lib.getExe hostPkgs.socat} STDIO UNIX-CONNECT:"$NIX_SWTPM_DIR"/socket
224
-
# Clear `FD_CLOEXEC` on the coprocess' file descriptor stdin.
225
-
fdflags -s-cloexec ''${waitingswtpm[1]}
225
+
${lib.optionalString cfg.tpm.enable ''
226
+
NIX_SWTPM_DIR=$(readlink -f "''${NIX_SWTPM_DIR:-${config.system.name}-swtpm}")
227
+
mkdir -p "$NIX_SWTPM_DIR"
228
+
${lib.getExe cfg.tpm.package} \
230
+
--tpmstate dir="$NIX_SWTPM_DIR" \
231
+
--ctrl type=unixio,path="$NIX_SWTPM_DIR"/socket,terminate \
232
+
--pid file="$NIX_SWTPM_DIR"/pid --daemon \
234
+
--log file="$NIX_SWTPM_DIR"/stdout,level=6
236
+
# Enable `fdflags` builtin in Bash
237
+
# We will need it to perform surgical modification of the file descriptor
238
+
# passed in the coprocess to remove `FD_CLOEXEC`, i.e. close the file descriptor
240
+
# If let alone, it will trigger the coprocess to read EOF when QEMU is `exec`
241
+
# at the end of this script. To work around that, we will just clear
242
+
# the `FD_CLOEXEC` bits as a first step.
243
+
enable -f ${hostPkgs.bash}/lib/bash/fdflags fdflags
244
+
# leave a dangling subprocess because the swtpm ctrl socket has
245
+
# "terminate" when the last connection disconnects, it stops swtpm.
246
+
# When qemu stops, or if the main shell process ends, the coproc will
247
+
# get signaled by virtue of the pipe between main and coproc ending.
248
+
# Which in turns triggers a socat connect-disconnect to swtpm which
250
+
coproc waitingswtpm {
252
+
echo "" | ${lib.getExe hostPkgs.socat} STDIO UNIX-CONNECT:"$NIX_SWTPM_DIR"/socket
254
+
# Clear `FD_CLOEXEC` on the coprocess' file descriptor stdin.
255
+
fdflags -s-cloexec ''${waitingswtpm[1]}
230
-
${lib.optionalString (cfg.emptyDiskImages != []) "idx=0"}
231
-
${flip concatMapStrings cfg.emptyDiskImages (size: ''
232
-
if ! test -e "empty$idx.qcow2"; then
233
-
${qemu}/bin/qemu-img create -f qcow2 "empty$idx.qcow2" "${toString size}M"
239
-
exec ${qemu-common.qemuBinary qemu} \
240
-
-name ${config.system.name} \
241
-
-m ${toString config.virtualisation.memorySize} \
242
-
-smp ${toString config.virtualisation.cores} \
243
-
-device virtio-rng-pci \
244
-
${concatStringsSep " " config.virtualisation.qemu.networkingOptions} \
245
-
${concatStringsSep " \\\n "
247
-
(tag: share: "-virtfs local,path=${share.source},security_model=${share.securityModel},mount_tag=${tag}")
248
-
config.virtualisation.sharedDirectories)} \
249
-
${drivesCmdLine config.virtualisation.qemu.drives} \
250
-
${concatStringsSep " \\\n " config.virtualisation.qemu.options} \
260
+
${lib.optionalString (cfg.emptyDiskImages != [ ]) "idx=0"}
261
+
${flip concatMapStrings cfg.emptyDiskImages (size: ''
262
+
if ! test -e "empty$idx.qcow2"; then
263
+
${qemu}/bin/qemu-img create -f qcow2 "empty$idx.qcow2" "${toString size}M"
269
+
exec ${qemu-common.qemuBinary qemu} \
270
+
-name ${config.system.name} \
271
+
-m ${toString config.virtualisation.memorySize} \
272
+
-smp ${toString config.virtualisation.cores} \
273
+
-device virtio-rng-pci \
274
+
${concatStringsSep " " config.virtualisation.qemu.networkingOptions} \
276
+
concatStringsSep " \\\n " (
279
+
"-virtfs local,path=${share.source},security_model=${share.securityModel},mount_tag=${tag}"
280
+
) config.virtualisation.sharedDirectories
283
+
${drivesCmdLine config.virtualisation.qemu.drives} \
284
+
${concatStringsSep " \\\n " config.virtualisation.qemu.options} \
regInfo = hostPkgs.closureInfo { rootPaths = config.virtualisation.additionalPaths; };
···
../profiles/qemu-guest.nix
293
-
(mkRenamedOptionModule [ "virtualisation" "pathsInNixDB" ] [ "virtualisation" "additionalPaths" ])
294
-
(mkRemovedOptionModule [ "virtualisation" "bootDevice" ] "This option was renamed to `virtualisation.rootDevice`, as it was incorrectly named and misleading. Take the time to review what you want to do and look at the new options like `virtualisation.{bootLoaderDevice, bootPartition}`, open an issue in case of issues.")
295
-
(mkRemovedOptionModule [ "virtualisation" "efiVars" ] "This option was removed, it is possible to provide a template UEFI variable with `virtualisation.efi.variables` ; if this option is important to you, open an issue")
296
-
(mkRemovedOptionModule [ "virtualisation" "persistBootDevice" ] "Boot device is always persisted if you use a bootloader through the root disk image ; if this does not work for your usecase, please examine carefully what `virtualisation.{bootDevice, rootDevice, bootPartition}` options offer you and open an issue explaining your need.`")
324
+
./disk-size-option.nix
325
+
(mkRenamedOptionModule
335
+
(mkRemovedOptionModule
340
+
"This option was renamed to `virtualisation.rootDevice`, as it was incorrectly named and misleading. Take the time to review what you want to do and look at the new options like `virtualisation.{bootLoaderDevice, bootPartition}`, open an issue in case of issues."
342
+
(mkRemovedOptionModule
347
+
"This option was removed, it is possible to provide a template UEFI variable with `virtualisation.efi.variables` ; if this option is important to you, open an issue"
349
+
(mkRemovedOptionModule
352
+
"persistBootDevice"
354
+
"Boot device is always persisted if you use a bootloader through the root disk image ; if this does not work for your usecase, please examine carefully what `virtualisation.{bootDevice, rootDevice, bootPartition}` options offer you and open an issue explaining your need.`"
virtualisation.fileSystems = options.fileSystems;
303
-
virtualisation.memorySize =
305
-
type = types.ints.positive;
308
-
The memory size in megabytes of the virtual machine.
362
+
virtualisation.memorySize = mkOption {
363
+
type = types.ints.positive;
366
+
The memory size in megabytes of the virtual machine.
312
-
virtualisation.msize =
314
-
type = types.ints.positive;
317
-
The msize (maximum packet size) option passed to 9p file systems, in
318
-
bytes. Increasing this should increase performance significantly,
319
-
at the cost of higher RAM usage.
370
+
virtualisation.msize = mkOption {
371
+
type = types.ints.positive;
374
+
The msize (maximum packet size) option passed to 9p file systems, in
375
+
bytes. Increasing this should increase performance significantly,
376
+
at the cost of higher RAM usage.
323
-
virtualisation.diskSize =
325
-
type = types.ints.positive;
328
-
The disk size in megabytes of the virtual machine.
380
+
virtualisation.diskImage = mkOption {
381
+
type = types.nullOr types.str;
382
+
default = "./${config.system.name}.qcow2";
383
+
defaultText = literalExpression ''"./''${config.system.name}.qcow2"'';
385
+
Path to the disk image containing the root filesystem.
386
+
The image will be created on startup if it does not
332
-
virtualisation.diskImage =
334
-
type = types.nullOr types.str;
335
-
default = "./${config.system.name}.qcow2";
336
-
defaultText = literalExpression ''"./''${config.system.name}.qcow2"'';
338
-
Path to the disk image containing the root filesystem.
339
-
The image will be created on startup if it does not
389
+
If null, a tmpfs will be used as the root filesystem and
390
+
the VM's state will not be persistent.
342
-
If null, a tmpfs will be used as the root filesystem and
343
-
the VM's state will not be persistent.
347
-
virtualisation.bootLoaderDevice =
350
-
default = "/dev/disk/by-id/virtio-${rootDriveSerialAttr}";
351
-
defaultText = literalExpression ''/dev/disk/by-id/virtio-${rootDriveSerialAttr}'';
352
-
example = "/dev/disk/by-id/virtio-boot-loader-device";
354
-
The path (inside th VM) to the device to boot from when legacy booting.
394
+
virtualisation.bootLoaderDevice = mkOption {
396
+
default = "/dev/disk/by-id/virtio-${rootDriveSerialAttr}";
397
+
defaultText = literalExpression ''/dev/disk/by-id/virtio-${rootDriveSerialAttr}'';
398
+
example = "/dev/disk/by-id/virtio-boot-loader-device";
400
+
The path (inside th VM) to the device to boot from when legacy booting.
358
-
virtualisation.bootPartition =
360
-
type = types.nullOr types.path;
361
-
default = if cfg.useEFIBoot then "/dev/disk/by-label/${espFilesystemLabel}" else null;
362
-
defaultText = literalExpression ''if cfg.useEFIBoot then "/dev/disk/by-label/${espFilesystemLabel}" else null'';
363
-
example = "/dev/disk/by-label/esp";
365
-
The path (inside the VM) to the device containing the EFI System Partition (ESP).
404
+
virtualisation.bootPartition = mkOption {
405
+
type = types.nullOr types.path;
406
+
default = if cfg.useEFIBoot then "/dev/disk/by-label/${espFilesystemLabel}" else null;
407
+
defaultText = literalExpression ''if cfg.useEFIBoot then "/dev/disk/by-label/${espFilesystemLabel}" else null'';
408
+
example = "/dev/disk/by-label/esp";
410
+
The path (inside the VM) to the device containing the EFI System Partition (ESP).
367
-
If you are *not* booting from a UEFI firmware, this value is, by
368
-
default, `null`. The ESP is mounted to `boot.loader.efi.efiSysMountpoint`.
412
+
If you are *not* booting from a UEFI firmware, this value is, by
413
+
default, `null`. The ESP is mounted to `boot.loader.efi.efiSysMountpoint`.
372
-
virtualisation.rootDevice =
374
-
type = types.nullOr types.path;
375
-
default = "/dev/disk/by-label/${rootFilesystemLabel}";
376
-
defaultText = literalExpression ''/dev/disk/by-label/${rootFilesystemLabel}'';
377
-
example = "/dev/disk/by-label/nixos";
379
-
The path (inside the VM) to the device containing the root filesystem.
417
+
virtualisation.rootDevice = mkOption {
418
+
type = types.nullOr types.path;
419
+
default = "/dev/disk/by-label/${rootFilesystemLabel}";
420
+
defaultText = literalExpression ''/dev/disk/by-label/${rootFilesystemLabel}'';
421
+
example = "/dev/disk/by-label/nixos";
423
+
The path (inside the VM) to the device containing the root filesystem.
383
-
virtualisation.emptyDiskImages =
385
-
type = types.listOf types.ints.positive;
388
-
Additional disk images to provide to the VM. The value is
389
-
a list of size in megabytes of each disk. These disks are
390
-
writeable by the VM.
427
+
virtualisation.emptyDiskImages = mkOption {
428
+
type = types.listOf types.ints.positive;
431
+
Additional disk images to provide to the VM. The value is
432
+
a list of size in megabytes of each disk. These disks are
433
+
writeable by the VM.
394
-
virtualisation.graphics =
399
-
Whether to run QEMU with a graphics window, or in nographic mode.
400
-
Serial console will be enabled on both settings, but this will
401
-
change the preferred console.
437
+
virtualisation.graphics = mkOption {
441
+
Whether to run QEMU with a graphics window, or in nographic mode.
442
+
Serial console will be enabled on both settings, but this will
443
+
change the preferred console.
405
-
virtualisation.resolution =
407
-
type = options.services.xserver.resolutions.type.nestedTypes.elemType;
408
-
default = { x = 1024; y = 768; };
410
-
The resolution of the virtual machine display.
447
+
virtualisation.resolution = mkOption {
448
+
type = options.services.xserver.resolutions.type.nestedTypes.elemType;
454
+
The resolution of the virtual machine display.
414
-
virtualisation.cores =
416
-
type = types.ints.positive;
419
-
Specify the number of cores the guest is permitted to use.
420
-
The number can be higher than the available cores on the
458
+
virtualisation.cores = mkOption {
459
+
type = types.ints.positive;
462
+
Specify the number of cores the guest is permitted to use.
463
+
The number can be higher than the available cores on the
425
-
virtualisation.sharedDirectories =
427
-
type = types.attrsOf
429
-
options.source = mkOption {
431
-
description = "The path of the directory to share, can be a shell variable";
433
-
options.target = mkOption {
435
-
description = "The mount point of the directory inside the virtual machine";
437
-
options.securityModel = mkOption {
438
-
type = types.enum [ "passthrough" "mapped-xattr" "mapped-file" "none" ];
439
-
default = "mapped-xattr";
441
-
The security model to use for this share:
468
+
virtualisation.sharedDirectories = mkOption {
469
+
type = types.attrsOf (
471
+
options.source = mkOption {
473
+
description = "The path of the directory to share, can be a shell variable";
475
+
options.target = mkOption {
477
+
description = "The mount point of the directory inside the virtual machine";
479
+
options.securityModel = mkOption {
480
+
type = types.enum [
486
+
default = "mapped-xattr";
488
+
The security model to use for this share:
443
-
- `passthrough`: files are stored using the same credentials as they are created on the guest (this requires QEMU to run as root)
444
-
- `mapped-xattr`: some of the file attributes like uid, gid, mode bits and link target are stored as file attributes
445
-
- `mapped-file`: the attributes are stored in the hidden .virtfs_metadata directory. Directories exported by this security model cannot interact with other unix tools
446
-
- `none`: same as "passthrough" except the sever won't report failures if it fails to set file attributes like ownership
452
-
my-share = { source = "/path/to/be/shared"; target = "/mnt/shared"; };
490
+
- `passthrough`: files are stored using the same credentials as they are created on the guest (this requires QEMU to run as root)
491
+
- `mapped-xattr`: some of the file attributes like uid, gid, mode bits and link target are stored as file attributes
492
+
- `mapped-file`: the attributes are stored in the hidden .virtfs_metadata directory. Directories exported by this security model cannot interact with other unix tools
493
+
- `none`: same as "passthrough" except the sever won't report failures if it fails to set file attributes like ownership
501
+
source = "/path/to/be/shared";
502
+
target = "/mnt/shared";
455
-
An attributes set of directories that will be shared with the
456
-
virtual machine using VirtFS (9P filesystem over VirtIO).
457
-
The attribute name will be used as the 9P mount tag.
506
+
An attributes set of directories that will be shared with the
507
+
virtual machine using VirtFS (9P filesystem over VirtIO).
508
+
The attribute name will be used as the 9P mount tag.
461
-
virtualisation.additionalPaths =
463
-
type = types.listOf types.path;
466
-
A list of paths whose closure should be made available to
512
+
virtualisation.additionalPaths = mkOption {
513
+
type = types.listOf types.path;
516
+
A list of paths whose closure should be made available to
469
-
When 9p is used, the closure is registered in the Nix
470
-
database in the VM. All other paths in the host Nix store
471
-
appear in the guest Nix store as well, but are considered
472
-
garbage (because they are not registered in the Nix
473
-
database of the guest).
519
+
When 9p is used, the closure is registered in the Nix
520
+
database in the VM. All other paths in the host Nix store
521
+
appear in the guest Nix store as well, but are considered
522
+
garbage (because they are not registered in the Nix
523
+
database of the guest).
475
-
When {option}`virtualisation.useNixStoreImage` is
476
-
set, the closure is copied to the Nix store image.
525
+
When {option}`virtualisation.useNixStoreImage` is
526
+
set, the closure is copied to the Nix store image.
virtualisation.forwardPorts = mkOption {
481
-
type = types.listOf
531
+
type = types.listOf (
options.from = mkOption {
484
-
type = types.enum [ "host" "guest" ];
534
+
type = types.enum [
487
-
Controls the direction in which the ports are mapped:
540
+
Controls the direction in which the ports are mapped:
489
-
- `"host"` means traffic from the host ports
490
-
is forwarded to the given guest port.
491
-
- `"guest"` means traffic from the guest ports
492
-
is forwarded to the given host port.
542
+
- `"host"` means traffic from the host ports
543
+
is forwarded to the given guest port.
544
+
- `"guest"` means traffic from the guest ports
545
+
is forwarded to the given host port.
options.proto = mkOption {
496
-
type = types.enum [ "tcp" "udp" ];
549
+
type = types.enum [
description = "The protocol to forward.";
···
description = "The guest port to be mapped.";
520
-
example = lib.literalExpression
577
+
example = lib.literalExpression ''
[ # forward local port 2222 -> 22, to ssh into the VM
{ from = "host"; host.port = 2222; guest.port = 22; }
···
host.address = "127.0.0.1"; host.port = 80;
533
-
When using the SLiRP user networking (default), this option allows to
534
-
forward ports to/from the host/guest.
589
+
When using the SLiRP user networking (default), this option allows to
590
+
forward ports to/from the host/guest.
537
-
If the NixOS firewall on the virtual machine is enabled, you also
538
-
have to open the guest ports to enable the traffic between host and
593
+
If the NixOS firewall on the virtual machine is enabled, you also
594
+
have to open the guest ports to enable the traffic between host and
543
-
Currently QEMU supports only IPv4 forwarding.
599
+
Currently QEMU supports only IPv4 forwarding.
548
-
virtualisation.restrictNetwork =
554
-
If this option is enabled, the guest will be isolated, i.e. it will
555
-
not be able to contact the host and no guest IP packets will be
556
-
routed over the host to the outside. This option does not affect
557
-
any explicitly set forwarding rules.
604
+
virtualisation.restrictNetwork = mkOption {
609
+
If this option is enabled, the guest will be isolated, i.e. it will
610
+
not be able to contact the host and no guest IP packets will be
611
+
routed over the host to the outside. This option does not affect
612
+
any explicitly set forwarding rules.
561
-
virtualisation.vlans =
563
-
type = types.listOf types.ints.unsigned;
564
-
default = if config.virtualisation.interfaces == {} then [ 1 ] else [ ];
565
-
defaultText = lib.literalExpression ''if config.virtualisation.interfaces == {} then [ 1 ] else [ ]'';
568
-
Virtual networks to which the VM is connected. Each
569
-
number «N» in this list causes
570
-
the VM to have a virtual Ethernet interface attached to a
571
-
separate virtual network on which it will be assigned IP
574
-
where «M» is the index of this VM
575
-
in the list of VMs.
616
+
virtualisation.vlans = mkOption {
617
+
type = types.listOf types.ints.unsigned;
618
+
default = if config.virtualisation.interfaces == { } then [ 1 ] else [ ];
619
+
defaultText = lib.literalExpression ''if config.virtualisation.interfaces == {} then [ 1 ] else [ ]'';
625
+
Virtual networks to which the VM is connected. Each
626
+
number «N» in this list causes
627
+
the VM to have a virtual Ethernet interface attached to a
628
+
separate virtual network on which it will be assigned IP
631
+
where «M» is the index of this VM
632
+
in the list of VMs.
virtualisation.interfaces = mkOption {
Network interfaces to add to the VM.
587
-
type = with types; attrsOf (submodule {
590
-
type = types.ints.unsigned;
592
-
VLAN to which the network interface is connected.
646
+
attrsOf (submodule {
649
+
type = types.ints.unsigned;
651
+
VLAN to which the network interface is connected.
596
-
assignIP = mkOption {
600
-
Automatically assign an IP address to the network interface using the same scheme as
601
-
virtualisation.vlans.
655
+
assignIP = mkOption {
659
+
Automatically assign an IP address to the network interface using the same scheme as
660
+
virtualisation.vlans.
608
-
virtualisation.writableStore =
611
-
default = cfg.mountHostNixStore;
612
-
defaultText = literalExpression "cfg.mountHostNixStore";
614
-
If enabled, the Nix store in the VM is made writable by
615
-
layering an overlay filesystem on top of the host's Nix
667
+
virtualisation.writableStore = mkOption {
669
+
default = cfg.mountHostNixStore;
670
+
defaultText = literalExpression "cfg.mountHostNixStore";
672
+
If enabled, the Nix store in the VM is made writable by
673
+
layering an overlay filesystem on top of the host's Nix
618
-
By default, this is enabled if you mount a host Nix store.
676
+
By default, this is enabled if you mount a host Nix store.
622
-
virtualisation.writableStoreUseTmpfs =
627
-
Use a tmpfs for the writable store instead of writing to the VM's
680
+
virtualisation.writableStoreUseTmpfs = mkOption {
684
+
Use a tmpfs for the writable store instead of writing to the VM's
632
-
networking.primaryIPAddress =
637
-
description = "Primary IP address used in /etc/hosts.";
689
+
networking.primaryIPAddress = mkOption {
693
+
description = "Primary IP address used in /etc/hosts.";
640
-
networking.primaryIPv6Address =
645
-
description = "Primary IPv6 address used in /etc/hosts.";
696
+
networking.primaryIPv6Address = mkOption {
700
+
description = "Primary IPv6 address used in /etc/hosts.";
virtualisation.host.pkgs = mkOption {
type = options.nixpkgs.pkgs.type;
···
664
-
type = types.package;
665
-
default = if hostPkgs.stdenv.hostPlatform.qemuArch == pkgs.stdenv.hostPlatform.qemuArch then hostPkgs.qemu_kvm else hostPkgs.qemu;
666
-
defaultText = literalExpression "if hostPkgs.stdenv.hostPlatform.qemuArch == pkgs.stdenv.hostPlatform.qemuArch then config.virtualisation.host.pkgs.qemu_kvm else config.virtualisation.host.pkgs.qemu";
667
-
example = literalExpression "pkgs.qemu_test";
668
-
description = "QEMU package to use.";
717
+
package = mkOption {
718
+
type = types.package;
720
+
if hostPkgs.stdenv.hostPlatform.qemuArch == pkgs.stdenv.hostPlatform.qemuArch then
724
+
defaultText = literalExpression "if hostPkgs.stdenv.hostPlatform.qemuArch == pkgs.stdenv.hostPlatform.qemuArch then config.virtualisation.host.pkgs.qemu_kvm else config.virtualisation.host.pkgs.qemu";
725
+
example = literalExpression "pkgs.qemu_test";
726
+
description = "QEMU package to use.";
673
-
type = types.listOf types.str;
675
-
example = [ "-vga std" ];
677
-
Options passed to QEMU.
678
-
See [QEMU User Documentation](https://www.qemu.org/docs/master/system/qemu-manpage) for a complete list.
729
+
options = mkOption {
730
+
type = types.listOf types.str;
732
+
example = [ "-vga std" ];
734
+
Options passed to QEMU.
735
+
See [QEMU User Documentation](https://www.qemu.org/docs/master/system/qemu-manpage) for a complete list.
type = types.listOf types.str;
685
-
consoles = [ "${qemu-common.qemuSerialDevice},115200n8" "tty0" ];
686
-
in if cfg.graphics then consoles else reverseList consoles;
744
+
"${qemu-common.qemuSerialDevice},115200n8"
748
+
if cfg.graphics then consoles else reverseList consoles;
example = [ "console=tty1" ];
The output console devices to pass to the kernel command line via the
···
699
-
networkingOptions =
701
-
type = types.listOf types.str;
704
-
"-net nic,netdev=user.0,model=virtio"
705
-
"-netdev user,id=user.0,\${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}"
708
-
Networking-related command-line options that should be passed to qemu.
709
-
The default is to use userspace networking (SLiRP).
710
-
See the [QEMU Wiki on Networking](https://wiki.qemu.org/Documentation/Networking) for details.
761
+
networkingOptions = mkOption {
762
+
type = types.listOf types.str;
765
+
"-net nic,netdev=user.0,model=virtio"
766
+
"-netdev user,id=user.0,\${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}"
769
+
Networking-related command-line options that should be passed to qemu.
770
+
The default is to use userspace networking (SLiRP).
771
+
See the [QEMU Wiki on Networking](https://wiki.qemu.org/Documentation/Networking) for details.
712
-
If you override this option, be advised to keep
713
-
`''${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}` (as seen in the example)
714
-
to keep the default runtime behaviour.
720
-
type = types.listOf (types.submodule driveOpts);
721
-
description = "Drives passed to qemu.";
726
-
type = types.enum [ "virtio" "scsi" "ide" ];
727
-
default = "virtio";
729
-
description = "The interface used for the virtual hard disks.";
773
+
If you override this option, be advised to keep
774
+
`''${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}` (as seen in the example)
775
+
to keep the default runtime behaviour.
732
-
guestAgent.enable =
737
-
Enable the Qemu guest agent.
779
+
drives = mkOption {
780
+
type = types.listOf (types.submodule driveOpts);
781
+
description = "Drives passed to qemu.";
746
-
Enable the virtio-keyboard device.
784
+
diskInterface = mkOption {
785
+
type = types.enum [
790
+
default = "virtio";
792
+
description = "The interface used for the virtual hard disks.";
751
-
virtualisation.useNixStoreImage =
795
+
guestAgent.enable = mkOption {
756
-
Build and use a disk image for the Nix store, instead of
757
-
accessing the host's one through 9p.
759
-
For applications which do a lot of reads from the store,
760
-
this can drastically improve performance, but at the cost of
761
-
disk space and image build time.
763
-
The Nix store image is built just-in-time right before the VM is
764
-
started. Because it does not produce another derivation, the image is
765
-
not cached between invocations and never lands in the store or binary
768
-
If you want a full disk image with a partition table and a root
769
-
filesystem instead of only a store image, enable
770
-
{option}`virtualisation.useBootLoader` instead.
799
+
Enable the Qemu guest agent.
774
-
virtualisation.mountHostNixStore =
803
+
virtioKeyboard = mkOption {
777
-
default = !cfg.useNixStoreImage && !cfg.useBootLoader;
778
-
defaultText = literalExpression "!cfg.useNixStoreImage && !cfg.useBootLoader";
780
-
Mount the host Nix store as a 9p mount.
807
+
Enable the virtio-keyboard device.
784
-
virtualisation.directBoot = {
788
-
default = !cfg.useBootLoader;
789
-
defaultText = "!cfg.useBootLoader";
791
-
If enabled, the virtual machine will boot directly into the kernel instead of through a bootloader.
792
-
Read more about this feature in the [QEMU documentation on Direct Linux Boot](https://qemu-project.gitlab.io/qemu/system/linuxboot.html)
812
+
virtualisation.useNixStoreImage = mkOption {
816
+
Build and use a disk image for the Nix store, instead of
817
+
accessing the host's one through 9p.
794
-
This is enabled by default.
795
-
If you want to test netboot, consider disabling this option.
796
-
Enable a bootloader with {option}`virtualisation.useBootLoader` if you need.
819
+
For applications which do a lot of reads from the store,
820
+
this can drastically improve performance, but at the cost of
821
+
disk space and image build time.
798
-
Relevant parameters such as those set in `boot.initrd` and `boot.kernelParams` are also passed to QEMU.
799
-
Additional parameters can be supplied on invocation through the environment variable `$QEMU_KERNEL_PARAMS`.
800
-
They are added to the `-append` option, see [QEMU User Documentation](https://www.qemu.org/docs/master/system/qemu-manpage) for details
801
-
For example, to let QEMU use the parent terminal as the serial console, set `QEMU_KERNEL_PARAMS="console=ttyS0"`.
823
+
The Nix store image is built just-in-time right before the VM is
824
+
started. Because it does not produce another derivation, the image is
825
+
not cached between invocations and never lands in the store or binary
803
-
This will not (re-)boot correctly into a system that has switched to a different configuration on disk.
809
-
default = "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
810
-
defaultText = "\${config.system.build.initialRamdisk}/\${config.system.boot.loader.initrdFile}";
812
-
In direct boot situations, you may want to influence the initrd to load
813
-
to use your own customized payload.
828
+
If you want a full disk image with a partition table and a root
829
+
filesystem instead of only a store image, enable
830
+
{option}`virtualisation.useBootLoader` instead.
815
-
This is useful if you want to test the netboot image without
816
-
testing the firmware or the loading part.
834
+
virtualisation.mountHostNixStore = mkOption {
836
+
default = !cfg.useNixStoreImage && !cfg.useBootLoader;
837
+
defaultText = literalExpression "!cfg.useNixStoreImage && !cfg.useBootLoader";
839
+
Mount the host Nix store as a 9p mount.
821
-
virtualisation.useBootLoader =
843
+
virtualisation.directBoot = {
844
+
enable = mkOption {
846
+
default = !cfg.useBootLoader;
847
+
defaultText = "!cfg.useBootLoader";
826
-
Use a boot loader to boot the system.
827
-
This allows, among other things, testing the boot loader.
849
+
If enabled, the virtual machine will boot directly into the kernel instead of through a bootloader.
850
+
Read more about this feature in the [QEMU documentation on Direct Linux Boot](https://qemu-project.gitlab.io/qemu/system/linuxboot.html)
829
-
If disabled, the kernel and initrd are directly booted,
830
-
forgoing any bootloader.
852
+
This is enabled by default.
853
+
If you want to test netboot, consider disabling this option.
854
+
Enable a bootloader with {option}`virtualisation.useBootLoader` if you need.
832
-
Check the documentation on {option}`virtualisation.directBoot.enable` for details.
856
+
Relevant parameters such as those set in `boot.initrd` and `boot.kernelParams` are also passed to QEMU.
857
+
Additional parameters can be supplied on invocation through the environment variable `$QEMU_KERNEL_PARAMS`.
858
+
They are added to the `-append` option, see [QEMU User Documentation](https://www.qemu.org/docs/master/system/qemu-manpage) for details
859
+
For example, to let QEMU use the parent terminal as the serial console, set `QEMU_KERNEL_PARAMS="console=ttyS0"`.
836
-
virtualisation.installBootLoader =
839
-
default = cfg.useBootLoader && cfg.useDefaultFilesystems;
840
-
defaultText = "cfg.useBootLoader && cfg.useDefaultFilesystems";
861
+
This will not (re-)boot correctly into a system that has switched to a different configuration on disk.
864
+
initrd = mkOption {
866
+
default = "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
867
+
defaultText = "\${config.system.build.initialRamdisk}/\${config.system.boot.loader.initrdFile}";
842
-
Install boot loader to target image.
869
+
In direct boot situations, you may want to influence the initrd to load
870
+
to use your own customized payload.
844
-
This is best-effort and may break with unconventional partition setups.
845
-
Use `virtualisation.useDefaultFilesystems` for a known-working configuration.
872
+
This is useful if you want to test the netboot image without
873
+
testing the firmware or the loading part.
878
+
virtualisation.useBootLoader = mkOption {
882
+
Use a boot loader to boot the system.
883
+
This allows, among other things, testing the boot loader.
885
+
If disabled, the kernel and initrd are directly booted,
886
+
forgoing any bootloader.
849
-
virtualisation.useEFIBoot =
854
-
If enabled, the virtual machine will provide a EFI boot
856
-
useEFIBoot is ignored if useBootLoader == false.
888
+
Check the documentation on {option}`virtualisation.directBoot.enable` for details.
892
+
virtualisation.installBootLoader = mkOption {
894
+
default = cfg.useBootLoader && cfg.useDefaultFilesystems;
895
+
defaultText = "cfg.useBootLoader && cfg.useDefaultFilesystems";
897
+
Install boot loader to target image.
899
+
This is best-effort and may break with unconventional partition setups.
900
+
Use `virtualisation.useDefaultFilesystems` for a known-working configuration.
904
+
virtualisation.useEFIBoot = mkOption {
908
+
If enabled, the virtual machine will provide a EFI boot
910
+
useEFIBoot is ignored if useBootLoader == false.
863
-
default = (pkgs.OVMF.override {
864
-
secureBoot = cfg.useSecureBoot;
866
-
defaultText = ''(pkgs.OVMF.override {
867
-
secureBoot = cfg.useSecureBoot;
918
+
(pkgs.OVMF.override {
919
+
secureBoot = cfg.useSecureBoot;
922
+
(pkgs.OVMF.override {
923
+
secureBoot = cfg.useSecureBoot;
description = "OVMF firmware package, defaults to OVMF configured with secure boot if needed.";
···
default = cfg.efi.OVMF.firmware;
defaultText = literalExpression "cfg.efi.OVMF.firmware";
877
-
Firmware binary for EFI implementation, defaults to OVMF.
933
+
Firmware binary for EFI implementation, defaults to OVMF.
···
default = cfg.efi.OVMF.variables;
defaultText = literalExpression "cfg.efi.OVMF.variables";
886
-
Platform-specific flash binary for EFI variables, implementation-dependent to the EFI firmware.
942
+
Platform-specific flash binary for EFI variables, implementation-dependent to the EFI firmware.
keepVariables = mkOption {
···
907
-
"i686-linux" = "tpm-tis";
908
-
"x86_64-linux" = "tpm-tis";
909
-
"ppc64-linux" = "tpm-spapr";
910
-
"armv7-linux" = "tpm-tis-device";
911
-
"aarch64-linux" = "tpm-tis-device";
912
-
}.${pkgs.stdenv.hostPlatform.system} or (throw "Unsupported system for TPM2 emulation in QEMU"));
964
+
"i686-linux" = "tpm-tis";
965
+
"x86_64-linux" = "tpm-tis";
966
+
"ppc64-linux" = "tpm-spapr";
967
+
"armv7-linux" = "tpm-tis-device";
968
+
"aarch64-linux" = "tpm-tis-device";
970
+
.${pkgs.stdenv.hostPlatform.system} or (throw "Unsupported system for TPM2 emulation in QEMU")
Based on the guest platform Linux system:
···
925
-
virtualisation.useDefaultFilesystems =
930
-
If enabled, the boot disk of the virtual machine will be
931
-
formatted and mounted with the default filesystems for
932
-
testing. Swap devices and LUKS will be disabled.
984
+
virtualisation.useDefaultFilesystems = mkOption {
988
+
If enabled, the boot disk of the virtual machine will be
989
+
formatted and mounted with the default filesystems for
990
+
testing. Swap devices and LUKS will be disabled.
934
-
If disabled, a root filesystem has to be specified and
935
-
formatted (for example in the initial ramdisk).
992
+
If disabled, a root filesystem has to be specified and
993
+
formatted (for example in the initial ramdisk).
939
-
virtualisation.useSecureBoot =
944
-
Enable Secure Boot support in the EFI firmware.
997
+
virtualisation.useSecureBoot = mkOption {
1001
+
Enable Secure Boot support in the EFI firmware.
948
-
virtualisation.bios =
950
-
type = types.nullOr types.package;
953
-
An alternate BIOS (such as `qboot`) with which to start the VM.
954
-
Should contain a file named `bios.bin`.
955
-
If `null`, QEMU's builtin SeaBIOS will be used.
1005
+
virtualisation.bios = mkOption {
1006
+
type = types.nullOr types.package;
1009
+
An alternate BIOS (such as `qboot`) with which to start the VM.
1010
+
Should contain a file named `bios.bin`.
1011
+
If `null`, QEMU's builtin SeaBIOS will be used.
959
-
virtualisation.useHostCerts =
964
-
If enabled, when `NIX_SSL_CERT_FILE` is set on the host,
965
-
pass the CA certificates from the host to the VM.
1015
+
virtualisation.useHostCerts = mkOption {
1016
+
type = types.bool;
1019
+
If enabled, when `NIX_SSL_CERT_FILE` is set on the host,
1020
+
pass the CA certificates from the host to the VM.
974
-
lib.concatLists (lib.flip lib.imap cfg.forwardPorts (i: rule:
976
-
{ assertion = rule.from == "guest" -> rule.proto == "tcp";
1030
+
lib.flip lib.imap cfg.forwardPorts (
1033
+
assertion = rule.from == "guest" -> rule.proto == "tcp";
Invalid virtualisation.forwardPorts.<entry ${toString i}>.proto:
Guest forwarding supports only TCP connections.
983
-
{ assertion = rule.from == "guest" -> lib.hasPrefix "10.0.2." rule.guest.address;
1040
+
assertion = rule.from == "guest" -> lib.hasPrefix "10.0.2." rule.guest.address;
Invalid virtualisation.forwardPorts.<entry ${toString i}>.guest.address:
The address must be in the default VLAN (10.0.2.0/24).
991
-
{ assertion = pkgs.stdenv.hostPlatform.is32bit -> cfg.memorySize < 2047;
993
-
virtualisation.memorySize is above 2047, but qemu is only able to allocate 2047MB RAM on 32bit max.
996
-
{ assertion = cfg.directBoot.enable || cfg.directBoot.initrd == options.virtualisation.directBoot.initrd.default;
999
-
You changed the default of `virtualisation.directBoot.initrd` but you are not
1000
-
using QEMU direct boot. This initrd will not be used in your current
1001
-
boot configuration.
1051
+
assertion = pkgs.stdenv.hostPlatform.is32bit -> cfg.memorySize < 2047;
1053
+
virtualisation.memorySize is above 2047, but qemu is only able to allocate 2047MB RAM on 32bit max.
1058
+
cfg.directBoot.enable || cfg.directBoot.initrd == options.virtualisation.directBoot.initrd.default;
1060
+
You changed the default of `virtualisation.directBoot.initrd` but you are not
1061
+
using QEMU direct boot. This initrd will not be used in your current
1062
+
boot configuration.
1003
-
Either do not mutate `virtualisation.directBoot.initrd` or enable direct boot.
1064
+
Either do not mutate `virtualisation.directBoot.initrd` or enable direct boot.
1005
-
If you have a more advanced usecase, please open an issue or a pull request.
1009
-
assertion = cfg.installBootLoader -> config.system.switch.enable;
1011
-
`system.switch.enable` must be enabled for `virtualisation.installBootLoader` to work.
1012
-
Please enable it in your configuration.
1066
+
If you have a more advanced usecase, please open an issue or a pull request.
1070
+
assertion = cfg.installBootLoader -> config.system.switch.enable;
1072
+
`system.switch.enable` must be enabled for `virtualisation.installBootLoader` to work.
1073
+
Please enable it in your configuration.
1018
-
optional (cfg.directBoot.enable && cfg.useBootLoader)
1020
-
You enabled direct boot and a bootloader, QEMU will not boot your bootloader, rendering
1021
-
`useBootLoader` useless. You might want to disable one of those options.
1078
+
warnings = optional (cfg.directBoot.enable && cfg.useBootLoader) ''
1079
+
You enabled direct boot and a bootloader, QEMU will not boot your bootloader, rendering
1080
+
`useBootLoader` useless. You might want to disable one of those options.
# In UEFI boot, we use a EFI-only partition table layout, thus GRUB will fail when trying to install
# legacy and UEFI. In order to avoid this, we have to put "nodev" to force UEFI-only installs.
···
# allow `system.build.toplevel' to be included. (If we had a direct
# reference to ${regInfo} here, then we would get a cyclic
1040
-
boot.postBootCommands = lib.mkIf config.nix.enable
1042
-
if [[ "$(cat /proc/cmdline)" =~ regInfo=([^ ]*) ]]; then
1043
-
${config.nix.package.out}/bin/nix-store --load-db < ''${BASH_REMATCH[1]}
1099
+
boot.postBootCommands = lib.mkIf config.nix.enable ''
1100
+
if [[ "$(cat /proc/cmdline)" =~ regInfo=([^ ]*) ]]; then
1101
+
${config.nix.package.out}/bin/nix-store --load-db < ''${BASH_REMATCH[1]}
boot.initrd.availableKernelModules =
optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx"
···
virtualisation.qemu.networkingOptions =
1082
-
forwardingOptions = flip concatMapStrings cfg.forwardPorts
1083
-
({ proto, from, host, guest }:
1085
-
then "hostfwd=${proto}:${host.address}:${toString host.port}-" +
1086
-
"${guest.address}:${toString guest.port},"
1087
-
else "'guestfwd=${proto}:${guest.address}:${toString guest.port}-" +
1088
-
"cmd:${pkgs.netcat}/bin/nc ${host.address} ${toString host.port}',"
1140
+
forwardingOptions = flip concatMapStrings cfg.forwardPorts (
1147
+
if from == "host" then
1148
+
"hostfwd=${proto}:${host.address}:${toString host.port}-"
1149
+
+ "${guest.address}:${toString guest.port},"
1151
+
"'guestfwd=${proto}:${guest.address}:${toString guest.port}-"
1152
+
+ "cmd:${pkgs.netcat}/bin/nc ${host.address} ${toString host.port}',"
restrictNetworkOption = lib.optionalString cfg.restrictNetwork "restrict=on,";
···
"-device virtio-keyboard"
(mkIf pkgs.stdenv.hostPlatform.isx86 [
1102
-
"-usb" "-device usb-tablet,bus=usb-bus.0"
1167
+
"-device usb-tablet,bus=usb-bus.0"
(mkIf pkgs.stdenv.hostPlatform.isAarch [
1105
-
"-device virtio-gpu-pci" "-device usb-ehci,id=usb0" "-device usb-kbd" "-device usb-tablet"
1170
+
"-device virtio-gpu-pci"
1171
+
"-device usb-ehci,id=usb0"
1173
+
"-device usb-tablet"
1108
-
alphaNumericChars = lowerChars ++ upperChars ++ (map toString (range 0 9));
1109
-
# Replace all non-alphanumeric characters with underscores
1110
-
sanitizeShellIdent = s: concatMapStrings (c: if builtins.elem c alphaNumericChars then c else "_") (stringToCharacters s);
1111
-
in mkIf cfg.directBoot.enable [
1112
-
"-kernel \${NIXPKGS_QEMU_KERNEL_${sanitizeShellIdent config.system.name}:-${config.system.build.toplevel}/kernel}"
1113
-
"-initrd ${cfg.directBoot.initrd}"
1114
-
''-append "$(cat ${config.system.build.toplevel}/kernel-params) init=${config.system.build.toplevel}/init regInfo=${regInfo}/registration ${consoles} $QEMU_KERNEL_PARAMS"''
1177
+
alphaNumericChars = lowerChars ++ upperChars ++ (map toString (range 0 9));
1178
+
# Replace all non-alphanumeric characters with underscores
1179
+
sanitizeShellIdent =
1181
+
concatMapStrings (c: if builtins.elem c alphaNumericChars then c else "_") (stringToCharacters s);
1183
+
mkIf cfg.directBoot.enable [
1184
+
"-kernel \${NIXPKGS_QEMU_KERNEL_${sanitizeShellIdent config.system.name}:-${config.system.build.toplevel}/kernel}"
1185
+
"-initrd ${cfg.directBoot.initrd}"
1186
+
''-append "$(cat ${config.system.build.toplevel}/kernel-params) init=${config.system.build.toplevel}/init regInfo=${regInfo}/registration ${consoles} $QEMU_KERNEL_PARAMS"''
"-drive if=pflash,format=raw,unit=0,readonly=on,file=${cfg.efi.firmware}"
"-drive if=pflash,format=raw,unit=1,readonly=off,file=$NIX_EFI_VARS"
···
"-device ${cfg.tpm.deviceModel},tpmdev=tpm_dev_0"
(mkIf (pkgs.stdenv.hostPlatform.isx86 && cfg.efi.OVMF.systemManagementModeRequired) [
1132
-
"-machine" "q35,smm=on"
1133
-
"-global" "driver=cfi.pflash01,property=secure,value=on"
1208
+
"driver=cfi.pflash01,property=secure,value=on"
virtualisation.qemu.drives = mkMerge [
1138
-
(mkIf (cfg.diskImage != null) [{
1140
-
file = ''"$NIX_DISK_IMAGE"'';
1141
-
driveExtraOpts.cache = "writeback";
1142
-
driveExtraOpts.werror = "report";
1143
-
deviceExtraOpts.bootindex = "1";
1144
-
deviceExtraOpts.serial = rootDriveSerialAttr;
1146
-
(mkIf cfg.useNixStoreImage [{
1147
-
name = "nix-store";
1148
-
file = ''"$TMPDIR"/store.img'';
1149
-
deviceExtraOpts.bootindex = "2";
1150
-
driveExtraOpts.format = "raw";
1213
+
(mkIf (cfg.diskImage != null) [
1216
+
file = ''"$NIX_DISK_IMAGE"'';
1217
+
driveExtraOpts.cache = "writeback";
1218
+
driveExtraOpts.werror = "report";
1219
+
deviceExtraOpts.bootindex = "1";
1220
+
deviceExtraOpts.serial = rootDriveSerialAttr;
1223
+
(mkIf cfg.useNixStoreImage [
1225
+
name = "nix-store";
1226
+
file = ''"$TMPDIR"/store.img'';
1227
+
deviceExtraOpts.bootindex = "2";
1228
+
driveExtraOpts.format = "raw";
file = "$(pwd)/empty${toString idx}.qcow2";
driveExtraOpts.werror = "report";
···
# override by setting `virtualisation.fileSystems = lib.mkForce { };`.
fileSystems = lib.mkIf (cfg.fileSystems != { }) (mkVMOverride cfg.fileSystems);
1165
-
virtualisation.fileSystems = let
1166
-
mkSharedDir = tag: share:
1244
+
virtualisation.diskSizeAutoSupported = false;
1246
+
virtualisation.fileSystems =
1248
+
mkSharedDir = tag: share: {
value.neededForBoot = true;
1173
-
[ "trans=virtio" "version=9p2000.L" "msize=${toString cfg.msize}" "x-systemd.requires=modprobe@9pnet_virtio.service" ]
1174
-
++ lib.optional (tag == "nix-store") "cache=loose";
1177
-
(lib.mapAttrs' mkSharedDir cfg.sharedDirectories)
1179
-
"/" = lib.mkIf cfg.useDefaultFilesystems (if cfg.diskImage == null then {
1183
-
device = cfg.rootDevice;
1186
-
"/tmp" = lib.mkIf config.boot.tmp.useTmpfs {
1189
-
neededForBoot = true;
1190
-
# Sync with systemd's tmp.mount;
1191
-
options = [ "mode=1777" "strictatime" "nosuid" "nodev" "size=${toString config.boot.tmp.tmpfsSize}" ];
1255
+
"version=9p2000.L"
1256
+
"msize=${toString cfg.msize}"
1257
+
"x-systemd.requires=modprobe@9pnet_virtio.service"
1258
+
] ++ lib.optional (tag == "nix-store") "cache=loose";
1193
-
"/nix/store" = lib.mkIf (cfg.useNixStoreImage || cfg.mountHostNixStore) (if cfg.writableStore then {
1195
-
lowerdir = [ "/nix/.ro-store" ];
1196
-
upperdir = "/nix/.rw-store/upper";
1197
-
workdir = "/nix/.rw-store/work";
1262
+
(lib.mapAttrs' mkSharedDir cfg.sharedDirectories)
1264
+
"/" = lib.mkIf cfg.useDefaultFilesystems (
1265
+
if cfg.diskImage == null then
1272
+
device = cfg.rootDevice;
1276
+
"/tmp" = lib.mkIf config.boot.tmp.useTmpfs {
1279
+
neededForBoot = true;
1280
+
# Sync with systemd's tmp.mount;
1286
+
"size=${toString config.boot.tmp.tmpfsSize}"
1200
-
device = "/nix/.ro-store";
1201
-
options = [ "bind" ];
1203
-
"/nix/.ro-store" = lib.mkIf cfg.useNixStoreImage {
1204
-
device = "/dev/disk/by-label/${nixStoreFilesystemLabel}";
1206
-
neededForBoot = true;
1207
-
options = [ "ro" ];
1209
-
"/nix/.rw-store" = lib.mkIf (cfg.writableStore && cfg.writableStoreUseTmpfs) {
1211
-
options = [ "mode=0755" ];
1212
-
neededForBoot = true;
1214
-
"${config.boot.loader.efi.efiSysMountPoint}" = lib.mkIf (cfg.useBootLoader && cfg.bootPartition != null) {
1215
-
device = cfg.bootPartition;
1289
+
"/nix/store" = lib.mkIf (cfg.useNixStoreImage || cfg.mountHostNixStore) (
1290
+
if cfg.writableStore then
1293
+
lowerdir = [ "/nix/.ro-store" ];
1294
+
upperdir = "/nix/.rw-store/upper";
1295
+
workdir = "/nix/.rw-store/work";
1300
+
device = "/nix/.ro-store";
1301
+
options = [ "bind" ];
1304
+
"/nix/.ro-store" = lib.mkIf cfg.useNixStoreImage {
1305
+
device = "/dev/disk/by-label/${nixStoreFilesystemLabel}";
1307
+
neededForBoot = true;
1308
+
options = [ "ro" ];
1310
+
"/nix/.rw-store" = lib.mkIf (cfg.writableStore && cfg.writableStoreUseTmpfs) {
1312
+
options = [ "mode=0755" ];
1313
+
neededForBoot = true;
1315
+
"${config.boot.loader.efi.efiSysMountPoint}" =
1316
+
lib.mkIf (cfg.useBootLoader && cfg.bootPartition != null)
1318
+
device = cfg.bootPartition;
swapDevices = (if cfg.useDefaultFilesystems then mkVMOverride else mkDefault) [ ];
1222
-
boot.initrd.luks.devices = (if cfg.useDefaultFilesystems then mkVMOverride else mkDefault) {};
1325
+
boot.initrd.luks.devices = (if cfg.useDefaultFilesystems then mkVMOverride else mkDefault) { };
# Don't run ntpd in the guest. It should get the correct time from KVM.
services.timesyncd.enable = false;
services.qemuGuest.enable = cfg.qemu.guestAgent.enable;
1229
-
system.build.vm = hostPkgs.runCommand "nixos-vm" {
1230
-
preferLocalBuild = true;
1231
-
meta.mainProgram = "run-${config.system.name}-vm";
1235
-
ln -s ${config.system.build.toplevel} $out/system
1236
-
ln -s ${hostPkgs.writeScript "run-nixos-vm" startVM} $out/bin/run-${config.system.name}-vm
1333
+
hostPkgs.runCommand "nixos-vm"
1335
+
preferLocalBuild = true;
1336
+
meta.mainProgram = "run-${config.system.name}-vm";
1340
+
ln -s ${config.system.build.toplevel} $out/system
1341
+
ln -s ${hostPkgs.writeScript "run-nixos-vm" startVM} $out/bin/run-${config.system.name}-vm
# When building a regular system configuration, override whatever
# video driver the host uses.
services.xserver.videoDrivers = mkVMOverride [ "modesetting" ];
services.xserver.defaultDepth = mkVMOverride 0;
services.xserver.resolutions = mkVMOverride [ cfg.resolution ];
1244
-
services.xserver.monitorSection =
1246
-
# Set a higher refresh rate so that resolutions > 800x600 work.
1248
-
VertRefresh 50-160
1349
+
services.xserver.monitorSection = ''
1350
+
# Set a higher refresh rate so that resolutions > 800x600 work.
1352
+
VertRefresh 50-160
# Wireless won't work in the VM.
networking.wireless.enable = mkVMOverride false;
···
networking.usePredictableInterfaceNames = false;
1260
-
system.requiredKernelConfig = with config.lib.kernelConfig;
1261
-
[ (isEnabled "VIRTIO_BLK")
1364
+
system.requiredKernelConfig =
1365
+
with config.lib.kernelConfig;
1367
+
(isEnabled "VIRTIO_BLK")
···
(isYes "NETWORK_FILESYSTEMS")
1273
-
] ++ optionals (!cfg.graphics) [
1380
+
++ optionals (!cfg.graphics) [
(isYes "SERIAL_8250_CONSOLE")
1276
-
] ++ optionals (cfg.writableStore) [
1384
+
++ optionals (cfg.writableStore) [