Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 35 additions & 8 deletions nixos/modules/installer/netboot/netboot.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This module creates netboot media containing the given NixOS
# configuration.

{ config, lib, pkgs, ... }:
{ options, config, lib, pkgs, ... }:

with lib;

Expand Down Expand Up @@ -41,6 +41,34 @@ with lib;
environment.systemPackages = [ pkgs.grub2_efi ]
++ (lib.optionals (pkgs.stdenv.hostPlatform.system != "aarch64-linux") [pkgs.grub2 pkgs.syslinux]);

# We only want to set those options in the context of
# the QEMU infrastructure.
virtualisation = lib.optionalAttrs (options ? virtualisation.directBoot) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand why we need to set this here. If this needs to be re-usable between tests it should be a fixure in tests/common IMO

# By default, using netboot images in virtualized contexts
# should not create any disk image ideally, except if
# asked explicitly.
diskImage = mkDefault null;
# We do not want to mount the host Nix store in those situations.
mountHostNixStore = mkDefault false;
# We do not need the nix store image because:
# - either we boot through network and we have the squashfs image
# - either we direct boot, we have the squashfs image
useNixStoreImage = mkDefault false;
# Though, we still want a writable store through .rw-store
writableStore = mkDefault true;
# Ideally, we might not want to test the network / firmware.
directBoot = {
enable = mkDefault true;
# We need to use our netboot initrd which contains a copy of the Nix store.
initrd = "${config.system.build.netbootRamdisk}/${config.system.boot.loader.initrdFile}";
};
# We do not want to use the default filesystems.
useDefaultFilesystems = mkDefault false;
# Bump the default memory size as we are loading the whole initrd in RAM.
memorySize = mkDefault 1536;
};


fileSystems."/" = mkImageMediaOverride
{ fsType = "tmpfs";
options = [ "mode=0755" ];
Expand Down Expand Up @@ -95,8 +123,7 @@ with lib;

# Create the initrd
system.build.netbootRamdisk = pkgs.makeInitrdNG {
inherit (config.boot.initrd) compressor;
prepend = [ "${config.system.build.initialRamdisk}/initrd" ];
prepend = [ "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}" ];

contents =
[ { object = config.system.build.squashfsStore;
Expand All @@ -109,8 +136,8 @@ with lib;
#!ipxe
# Use the cmdline variable to allow the user to specify custom kernel params
# when chainloading this script from other iPXE scripts like netboot.xyz
kernel ${pkgs.stdenv.hostPlatform.linux-kernel.target} init=${config.system.build.toplevel}/init initrd=initrd ${toString config.boot.kernelParams} ''${cmdline}
initrd initrd
kernel ${pkgs.stdenv.hostPlatform.linux-kernel.target} init=${config.system.build.toplevel}/init initrd=${config.system.boot.loader.initrdFile} ${toString config.boot.kernelParams} ''${cmdline}
initrd ${config.system.boot.loader.initrdFile}
boot
'';

Expand All @@ -124,16 +151,16 @@ with lib;
fi
SCRIPT_DIR=$( cd -- "$( dirname -- "''${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
kexec --load ''${SCRIPT_DIR}/bzImage \
--initrd=''${SCRIPT_DIR}/initrd.gz \
--initrd=''${SCRIPT_DIR}/${config.system.boot.loader.initrdFile} \
--command-line "init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}"
kexec -e
'';

# A tree containing initrd.gz, bzImage and a kexec-boot script.
system.build.kexecTree = pkgs.linkFarm "kexec-tree" [
{
name = "initrd.gz";
path = "${config.system.build.netbootRamdisk}/initrd";
name = "${config.system.boot.loader.initrdFile}";
path = "${config.system.build.netbootRamdisk}/${config.system.boot.loader.initrdFile}";
}
{
name = "bzImage";
Expand Down
2 changes: 1 addition & 1 deletion nixos/modules/virtualisation/qemu-vm.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1192,7 +1192,7 @@ in
# value for the `fileSystems' attribute should be disregarded (since those
# filesystems don't necessarily exist in the VM). You can disable this
# override by setting `virtualisation.fileSystems = lib.mkForce { };`.
fileSystems = lib.mkIf (cfg.fileSystems != { }) (mkVMOverride cfg.fileSystems);
fileSystems = lib.mkIf (cfg.fileSystems != { }) (lib.mapAttrs (n: v: mkVMOverride v) cfg.fileSystems);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we really need this. You could just set virtualisation.fileSystems to { } to use just the ones defined in netboot.nix. Is there actually a good reason to mix the ones defined by qemu-vm.nix and netboot.nix?


virtualisation.fileSystems = let
mkSharedDir = tag: share:
Expand Down
9 changes: 9 additions & 0 deletions nixos/tests/boot.nix
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ in {
bios = uefiBinary;
};

directNetboot = makeTest {
name = "directboot-netboot";
nodes.machine = {
imports = [ ../modules/installer/netboot/netboot-minimal.nix ];
virtualisation.memorySize = 4096;
};
testScript = "machine.fail('stat /dev/vda')";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably do better than this. What about checking whether the nix store is mounted via a loop device? That's more of a key characteristic of netboot for me.

};

uefiNetboot = makeNetbootTest "uefi" {
bios = uefiBinary;
# Custom ROM is needed for EFI PXE boot. I failed to understand exactly why, because QEMU should still use iPXE for EFI.
Expand Down