···2222 - made sure NixOS tests are [linked](https://nixos.org/manual/nixpkgs/unstable/#ssec-nixos-tests-linking) to the relevant packages
2323- [ ] Tested compilation of all packages that depend on this change using `nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD"`. Note: all changes have to be committed, also see [nixpkgs-review usage](https://github.com/Mic92/nixpkgs-review#usage)
2424- [ ] Tested basic functionality of all binary files (usually in `./result/bin/`)
2525-- [23.11 Release Notes (or backporting 23.05 Release notes)](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#generating-2305-release-notes)
2525+- [23.11 Release Notes](https://github.com/NixOS/nixpkgs/blob/master/nixos/doc/manual/release-notes/rl-2311.section.md) (or backporting [23.05 Release notes](https://github.com/NixOS/nixpkgs/blob/master/nixos/doc/manual/release-notes/rl-2305.section.md))
2626 - [ ] (Package updates) Added a release notes entry if the change is major or breaking
2727 - [ ] (Module updates) Added a release notes entry if the change is significant
2828 - [ ] (Module addition) Added a release notes entry if adding a new NixOS module
-13
CONTRIBUTING.md
···161161- Services which require a client to be up-to-date regardless. (E.g. `spotify`, `steam`, or `discord`)
162162- Security critical applications (E.g. `firefox`)
163163164164-## Generating 23.11 Release Notes
165165-<!--
166166-note: title unchanged even though we don't need regeneration because extant
167167-PRs will link here. definitely change the title for 23.11 though.
168168--->
169169-170170-Documentation in nixpkgs is transitioning to a markdown-centric workflow. In the past release notes required a translation step to convert from markdown to a compatible docbook document, but this is no longer necessary.
171171-172172-Steps for updating 23.11 Release notes:
173173-174174-1. Edit `nixos/doc/manual/release-notes/rl-2311.section.md` with the desired changes
175175-2. Commit changes to `rl-2311.section.md`.
176176-177164## Reviewing contributions
178165179166See the nixpkgs manual for more details on how to [Review contributions](https://nixos.org/nixpkgs/manual/#chap-reviewing-contributions).
+14
nixos/doc/manual/release-notes/rl-2311.section.md
···6161- A new option was added to the virtualisation module that enables specifying explicitly named network interfaces in QEMU VMs. The existing `virtualisation.vlans` is still supported for cases where the name of the network interface is irrelevant.
62626363- `services.nginx` gained a `defaultListen` option at server-level with support for PROXY protocol listeners, also `proxyProtocol` is now exposed in `services.nginx.virtualHosts.<name>.listen` option. It is now possible to run PROXY listeners and non-PROXY listeners at a server-level, see [#213510](https://github.com/NixOS/nixpkgs/pull/213510/) for more details.
6464+6565+## Nixpkgs internals {#sec-release-23.11-nixpkgs-internals}
6666+6767+- The `qemu-vm.nix` module by default now identifies block devices via
6868+ persistent names available in `/dev/disk/by-*`. Because the rootDevice is
6969+ identfied by its filesystem label, it needs to be formatted before the VM is
7070+ started. The functionality of automatically formatting the rootDevice in the
7171+ initrd is removed from the QEMU module. However, for tests that depend on
7272+ this functionality, a test utility for the scripted initrd is added
7373+ (`nixos/tests/common/auto-format-root-device.nix`). To use this in a NixOS
7474+ test, import the module, e.g. `imports = [
7575+ ./common/auto-format-root-device.nix ];` When you use the systemd initrd, you
7676+ can automatically format the root device by setting
7777+ `virtualisation.fileSystems."/".autoFormat = true;`.
+1
nixos/lib/make-disk-image.nix
···573573 # In this throwaway resource, we only have /dev/vda, but the actual VM may refer to another disk for bootloader, e.g. /dev/vdb
574574 # Use this option to create a symlink from vda to any arbitrary device you want.
575575 ${optionalString (config.boot.loader.grub.device != "/dev/vda") ''
576576+ mkdir -p $(dirname ${config.boot.loader.grub.device})
576577 ln -s /dev/vda ${config.boot.loader.grub.device}
577578 ''}
578579
···6060 config.networking.resolvconf.package # for configuring DNS in some configs
6161 pkgs.procps # for collecting running services (opt-in feature)
6262 pkgs.glibc # for `getent` to look up user shells
6363+ pkgs.kmod # required to pass tailscale's v6nat check
6364 ];
6465 serviceConfig.Environment = [
6566 "PORT=${toString cfg.port}"
+63-96
nixos/modules/virtualisation/qemu-vm.nix
···81818282 drivesCmdLine = drives: concatStringsSep "\\\n " (imap1 driveCmdline drives);
83838484-8585- # Creates a device name from a 1-based a numerical index, e.g.
8686- # * `driveDeviceName 1` -> `/dev/vda`
8787- # * `driveDeviceName 2` -> `/dev/vdb`
8888- driveDeviceName = idx:
8989- let letter = elemAt lowerChars (idx - 1);
9090- in if cfg.qemu.diskInterface == "scsi" then
9191- "/dev/sd${letter}"
9292- else
9393- "/dev/vd${letter}";
9494-9595- lookupDriveDeviceName = driveName: driveList:
9696- (findSingle (drive: drive.name == driveName)
9797- (throw "Drive ${driveName} not found")
9898- (throw "Multiple drives named ${driveName}") driveList).device;
9999-100100- addDeviceNames =
101101- imap1 (idx: drive: drive // { device = driveDeviceName idx; });
102102-10384 # Shell script to start the VM.
10485 startVM =
10586 ''
···1099011091 set -e
111929393+ # Create an empty ext4 filesystem image. A filesystem image does not
9494+ # contain a partition table but just a filesystem.
9595+ createEmptyFilesystemImage() {
9696+ local name=$1
9797+ local size=$2
9898+ local temp=$(mktemp)
9999+ ${qemu}/bin/qemu-img create -f raw "$temp" "$size"
100100+ ${pkgs.e2fsprogs}/bin/mkfs.ext4 -L ${rootFilesystemLabel} "$temp"
101101+ ${qemu}/bin/qemu-img convert -f raw -O qcow2 "$temp" "$name"
102102+ rm "$temp"
103103+ }
104104+112105 NIX_DISK_IMAGE=$(readlink -f "''${NIX_DISK_IMAGE:-${toString config.virtualisation.diskImage}}") || test -z "$NIX_DISK_IMAGE"
113106114107 if test -n "$NIX_DISK_IMAGE" && ! test -e "$NIX_DISK_IMAGE"; then
115108 echo "Disk image do not exist, creating the virtualisation disk image..."
116116- # If we are using a bootloader and default filesystems layout.
117117- # We have to reuse the system image layout as a backing image format (CoW)
118118- # So we can write on the top of it.
119109120120- # If we are not using the default FS layout, potentially, we are interested into
121121- # performing operations in postDeviceCommands or at early boot on the raw device.
122122- # We can still boot through QEMU direct kernel boot feature.
110110+ ${if (cfg.useBootLoader && cfg.useDefaultFilesystems) then ''
111111+ # Create a writable qcow2 image using the systemImage as a backing
112112+ # image.
123113124124- # CoW prevent size to be attributed to an image.
125125- # FIXME: raise this issue to upstream.
126126- ${qemu}/bin/qemu-img create \
127127- ${concatStringsSep " \\\n" ([ "-f qcow2" ]
128128- ++ optional (cfg.useBootLoader && cfg.useDefaultFilesystems) "-F qcow2 -b ${systemImage}/nixos.qcow2"
129129- ++ optional (!(cfg.useBootLoader && cfg.useDefaultFilesystems)) "-o size=${toString config.virtualisation.diskSize}M"
130130- ++ [ ''"$NIX_DISK_IMAGE"'' ])}
114114+ # CoW prevent size to be attributed to an image.
115115+ # FIXME: raise this issue to upstream.
116116+ ${qemu}/bin/qemu-img create \
117117+ -f qcow2 \
118118+ -b ${systemImage}/nixos.qcow2 \
119119+ -F qcow2 \
120120+ "$NIX_DISK_IMAGE"
121121+ '' else if cfg.useDefaultFilesystems then ''
122122+ createEmptyFilesystemImage "$NIX_DISK_IMAGE" "${toString cfg.diskSize}M"
123123+ '' else ''
124124+ # Create an empty disk image without a filesystem.
125125+ ${qemu}/bin/qemu-img create -f qcow2 "$NIX_DISK_IMAGE" "${toString cfg.diskSize}M"
126126+ ''
127127+ }
131128 echo "Virtualisation disk image created."
132129 fi
133130···148145 ${pkgs.erofs-utils}/bin/mkfs.erofs \
149146 --force-uid=0 \
150147 --force-gid=0 \
148148+ -L ${nixStoreFilesystemLabel} \
151149 -U eb176051-bd15-49b7-9e6b-462e0b467019 \
152150 -T 0 \
153151 --exclude-regex="$(
···218216219217 regInfo = pkgs.closureInfo { rootPaths = config.virtualisation.additionalPaths; };
220218219219+ # Use well-defined and persistent filesystem labels to identify block devices.
220220+ rootFilesystemLabel = "nixos";
221221+ espFilesystemLabel = "ESP"; # Hard-coded by make-disk-image.nix
222222+ nixStoreFilesystemLabel = "nix-store";
223223+224224+ # The root drive is a raw disk which does not necessarily contain a
225225+ # filesystem or partition table. It thus cannot be identified via the typical
226226+ # persistent naming schemes (e.g. /dev/disk/by-{label, uuid, partlabel,
227227+ # partuuid}. Instead, supply a well-defined and persistent serial attribute
228228+ # via QEMU. Inside the running system, the disk can then be identified via
229229+ # the /dev/disk/by-id scheme.
230230+ rootDriveSerialAttr = "root";
231231+221232 # System image is akin to a complete NixOS install with
222233 # a boot partition and root partition.
223234 systemImage = import ../../lib/make-disk-image.nix {
···225236 additionalPaths = [ regInfo ];
226237 format = "qcow2";
227238 onlyNixStore = false;
239239+ label = rootFilesystemLabel;
228240 partitionTableType = selectPartitionTableLayout { inherit (cfg) useDefaultFilesystems useEFIBoot; };
229241 # Bootloader should be installed on the system image only if we are booting through bootloaders.
230242 # Though, if a user is not using our default filesystems, it is possible to not have any ESP
···247259 additionalPaths = [ regInfo ];
248260 format = "qcow2";
249261 onlyNixStore = true;
262262+ label = nixStoreFilesystemLabel;
250263 partitionTableType = "none";
251264 installBootLoader = false;
252265 touchEFIVars = false;
···255268 copyChannel = false;
256269 };
257270258258- bootConfiguration =
259259- if cfg.useDefaultFilesystems
260260- then
261261- if cfg.useBootLoader
262262- then
263263- if cfg.useEFIBoot then "efi_bootloading_with_default_fs"
264264- else "legacy_bootloading_with_default_fs"
265265- else
266266- if cfg.directBoot.enable then "direct_boot_with_default_fs"
267267- else "custom"
268268- else
269269- "custom";
270270- suggestedRootDevice = {
271271- "efi_bootloading_with_default_fs" = "${cfg.bootLoaderDevice}2";
272272- "legacy_bootloading_with_default_fs" = "${cfg.bootLoaderDevice}1";
273273- "direct_boot_with_default_fs" = cfg.bootLoaderDevice;
274274- # This will enforce a NixOS module type checking error
275275- # to ask explicitly the user to set a rootDevice.
276276- # As it will look like `rootDevice = lib.mkDefault null;` after
277277- # all "computations".
278278- "custom" = null;
279279- }.${bootConfiguration};
280271in
281272282273{
···343334 virtualisation.bootLoaderDevice =
344335 mkOption {
345336 type = types.path;
346346- default = lookupDriveDeviceName "root" cfg.qemu.drives;
347347- defaultText = literalExpression ''lookupDriveDeviceName "root" cfg.qemu.drives'';
348348- example = "/dev/vda";
337337+ default = "/dev/disk/by-id/virtio-${rootDriveSerialAttr}";
338338+ defaultText = literalExpression ''/dev/disk/by-id/virtio-${rootDriveSerialAttr}'';
339339+ example = "/dev/disk/by-id/virtio-boot-loader-device";
349340 description =
350341 lib.mdDoc ''
351351- The disk to be used for the boot filesystem.
352352- By default, it is the same disk as the root filesystem.
342342+ The path (inside th VM) to the device to boot from when legacy booting.
353343 '';
354344 };
355345356346 virtualisation.bootPartition =
357347 mkOption {
358348 type = types.nullOr types.path;
359359- default = if cfg.useEFIBoot then "${cfg.bootLoaderDevice}1" else null;
360360- defaultText = literalExpression ''if cfg.useEFIBoot then "''${cfg.bootLoaderDevice}1" else null'';
361361- example = "/dev/vda1";
349349+ default = if cfg.useEFIBoot then "/dev/disk/by-label/${espFilesystemLabel}" else null;
350350+ defaultText = literalExpression ''if cfg.useEFIBoot then "/dev/disk/by-label/${espFilesystemLabel}" else null'';
351351+ example = "/dev/disk/by-label/esp";
362352 description =
363353 lib.mdDoc ''
364364- The boot partition to be used to mount /boot filesystem.
365365- In legacy boots, this should be null.
366366- By default, in EFI boot, it is the first partition of the boot device.
354354+ The path (inside the VM) to the device containing the EFI System Partition (ESP).
355355+356356+ If you are *not* booting from a UEFI firmware, this value is, by
357357+ default, `null`. The ESP is mounted under `/boot`.
367358 '';
368359 };
369360370361 virtualisation.rootDevice =
371362 mkOption {
372363 type = types.nullOr types.path;
373373- example = "/dev/vda2";
364364+ default = "/dev/disk/by-label/${rootFilesystemLabel}";
365365+ defaultText = literalExpression ''/dev/disk/by-label/${rootFilesystemLabel}'';
366366+ example = "/dev/disk/by-label/nixos";
374367 description =
375368 lib.mdDoc ''
376376- The disk or partition to be used for the root filesystem.
377377- By default (read the source code for more details):
378378-379379- - under EFI with a bootloader: 2nd partition of the boot disk
380380- - in legacy boot with a bootloader: 1st partition of the boot disk
381381- - in direct boot (i.e. without a bootloader): whole disk
382382-383383- In case you are not using a default boot device or a default filesystem, you have to set explicitly your root device.
369369+ The path (inside the VM) to the device containing the root filesystem.
384370 '';
385371 };
386372···711697 mkOption {
712698 type = types.listOf (types.submodule driveOpts);
713699 description = lib.mdDoc "Drives passed to qemu.";
714714- apply = addDeviceNames;
715700 };
716701717702 diskInterface =
···975960 # FIXME: make a sense of this mess wrt to multiple ESP present in the system, probably use boot.efiSysMountpoint?
976961 boot.loader.grub.device = mkVMOverride (if cfg.useEFIBoot then "nodev" else cfg.bootLoaderDevice);
977962 boot.loader.grub.gfxmodeBios = with cfg.resolution; "${toString x}x${toString y}";
978978- virtualisation.rootDevice = mkDefault suggestedRootDevice;
979963980964 boot.initrd.kernelModules = optionals (cfg.useNixStoreImage && !cfg.writableStore) [ "erofs" ];
981965982966 boot.loader.supportsInitrdSecrets = mkIf (!cfg.useBootLoader) (mkVMOverride false);
983967984984- boot.initrd.extraUtilsCommands = lib.mkIf (cfg.useDefaultFilesystems && !config.boot.initrd.systemd.enable)
985985- ''
986986- # We need mke2fs in the initrd.
987987- copy_bin_and_libs ${pkgs.e2fsprogs}/bin/mke2fs
988988- '';
989989-990990- boot.initrd.postDeviceCommands = lib.mkIf (cfg.useDefaultFilesystems && !config.boot.initrd.systemd.enable)
991991- ''
992992- # If the disk image appears to be empty, run mke2fs to
993993- # initialise.
994994- FSTYPE=$(blkid -o value -s TYPE ${cfg.rootDevice} || true)
995995- PARTTYPE=$(blkid -o value -s PTTYPE ${cfg.rootDevice} || true)
996996- if test -z "$FSTYPE" -a -z "$PARTTYPE"; then
997997- mke2fs -t ext4 ${cfg.rootDevice}
998998- fi
999999- '';
10001000-1001968 boot.initrd.postMountCommands = lib.mkIf (!config.boot.initrd.systemd.enable)
1002969 ''
1003970 # Mark this as a NixOS machine.
···11121079 driveExtraOpts.cache = "writeback";
11131080 driveExtraOpts.werror = "report";
11141081 deviceExtraOpts.bootindex = "1";
10821082+ deviceExtraOpts.serial = rootDriveSerialAttr;
11151083 }])
11161084 (mkIf cfg.useNixStoreImage [{
11171085 name = "nix-store";
···11541122 } else {
11551123 device = cfg.rootDevice;
11561124 fsType = "ext4";
11571157- autoFormat = true;
11581125 });
11591126 "/tmp" = lib.mkIf config.boot.tmp.useTmpfs {
11601127 device = "tmpfs";
···11641131 options = [ "mode=1777" "strictatime" "nosuid" "nodev" "size=${toString config.boot.tmp.tmpfsSize}" ];
11651132 };
11661133 "/nix/${if cfg.writableStore then ".ro-store" else "store"}" = lib.mkIf cfg.useNixStoreImage {
11671167- device = "${lookupDriveDeviceName "nix-store" cfg.qemu.drives}";
11341134+ device = "/dev/disk/by-label/${nixStoreFilesystemLabel}";
11681135 neededForBoot = true;
11691136 options = [ "ro" ];
11701137 };
···11741141 neededForBoot = true;
11751142 };
11761143 "/boot" = lib.mkIf (cfg.useBootLoader && cfg.bootPartition != null) {
11771177- device = cfg.bootPartition; # 1 for e.g. `vda1`, as created in `systemImage`
11441144+ device = cfg.bootPartition;
11781145 fsType = "vfat";
11791146 noCheck = true; # fsck fails on a r/o filesystem
11801147 };
+29
nixos/tests/common/auto-format-root-device.nix
···11+# This is a test utility that automatically formats
22+# `config.virtualisation.rootDevice` in the initrd.
33+# Note that when you are using
44+# `boot.initrd.systemd.enable = true`, you can use
55+# `virtualisation.fileSystems."/".autoFormat = true;`
66+# instead.
77+88+{ config, pkgs, ... }:
99+1010+let
1111+ rootDevice = config.virtualisation.rootDevice;
1212+in
1313+{
1414+1515+ boot.initrd.extraUtilsCommands = ''
1616+ # We need mke2fs in the initrd.
1717+ copy_bin_and_libs ${pkgs.e2fsprogs}/bin/mke2fs
1818+ '';
1919+2020+ boot.initrd.postDeviceCommands = ''
2121+ # If the disk image appears to be empty, run mke2fs to
2222+ # initialise.
2323+ FSTYPE=$(blkid -o value -s TYPE ${rootDevice} || true)
2424+ PARTTYPE=$(blkid -o value -s PTTYPE ${rootDevice} || true)
2525+ if test -z "$FSTYPE" -a -z "$PARTTYPE"; then
2626+ mke2fs -t ext4 ${rootDevice}
2727+ fi
2828+ '';
2929+}
+7-3
nixos/tests/fsck.nix
···2121 boot.initrd.systemd.enable = systemdStage1;
2222 };
23232424- testScript = ''
2424+ testScript = { nodes, ...}:
2525+ let
2626+ rootDevice = nodes.machine.virtualisation.rootDevice;
2727+ in
2828+ ''
2529 machine.wait_for_unit("default.target")
26302731 with subtest("root fs is fsckd"):
2832 machine.succeed("journalctl -b | grep '${if systemdStage1
2929- then "fsck.*vda.*clean"
3030- else "fsck.ext4.*/dev/vda"}'")
3333+ then "fsck.*${builtins.baseNameOf rootDevice}.*clean"
3434+ else "fsck.ext4.*${rootDevice}"}'")
31353236 with subtest("mnt fs is fsckd"):
3337 machine.succeed("journalctl -b | grep 'fsck.*vdb.*clean'")
···298298 ../modules/profiles/installation-device.nix
299299 ../modules/profiles/base.nix
300300 extraInstallerConfig
301301+ ./common/auto-format-root-device.nix
301302 ];
303303+304304+ # In systemdStage1, also automatically format the device backing the
305305+ # root filesystem.
306306+ virtualisation.fileSystems."/".autoFormat = systemdStage1;
302307303308 # builds stuff in the VM, needs more juice
304309 virtualisation.diskSize = 8 * 1024;