diff options
Diffstat (limited to 'nixos/modules/virtualisation/qemu-vm.nix')
-rw-r--r-- | nixos/modules/virtualisation/qemu-vm.nix | 195 |
1 files changed, 58 insertions, 137 deletions
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index d1dc6404d4f51..153dc877352ad 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -134,32 +134,26 @@ let TMPDIR=$(mktemp -d nix-vm.XXXXXXXXXX --tmpdir) fi - ${lib.optionalString (cfg.useNixStoreImage) - (if cfg.writableStore - then '' - # Create a writable copy/snapshot of the store image. - ${qemu}/bin/qemu-img create -f qcow2 -F qcow2 -b ${storeImage}/nixos.qcow2 "$TMPDIR"/store.img - '' - else '' - ( - cd ${builtins.storeDir} - ${hostPkgs.erofs-utils}/bin/mkfs.erofs \ - --force-uid=0 \ - --force-gid=0 \ - -L ${nixStoreFilesystemLabel} \ - -U eb176051-bd15-49b7-9e6b-462e0b467019 \ - -T 0 \ - --exclude-regex="$( - <${hostPkgs.closureInfo { rootPaths = [ config.system.build.toplevel regInfo ]; }}/store-paths \ - sed -e 's^.*/^^g' \ - | cut -c -10 \ - | ${hostPkgs.python3}/bin/python ${./includes-to-excludes.py} )" \ - "$TMPDIR"/store.img \ - . \ - </dev/null >/dev/null - ) - '' - ) + ${lib.optionalString (cfg.useNixStoreImage) '' + echo "Creating Nix store image..." + + ${hostPkgs.gnutar}/bin/tar --create \ + --absolute-names \ + --verbatim-files-from \ + --transform 'flags=rSh;s|/nix/store/||' \ + --files-from ${hostPkgs.closureInfo { rootPaths = [ config.system.build.toplevel regInfo ]; }}/store-paths \ + | ${hostPkgs.erofs-utils}/bin/mkfs.erofs \ + --quiet \ + --force-uid=0 \ + --force-gid=0 \ + -L ${nixStoreFilesystemLabel} \ + -U eb176051-bd15-49b7-9e6b-462e0b467019 \ + -T 0 \ + --tar=f \ + "$TMPDIR"/store.img + + echo "Created Nix store image." + '' } # Create a directory for exchanging data with the VM. @@ -298,21 +292,6 @@ let OVMF = cfg.efi.OVMF; }; - storeImage = import ../../lib/make-disk-image.nix { - name = "nix-store-image"; - inherit pkgs config lib; - additionalPaths = [ regInfo ]; - format = "qcow2"; - onlyNixStore = true; - label = nixStoreFilesystemLabel; - partitionTableType = "none"; - installBootLoader = false; - touchEFIVars = false; - diskSize = "auto"; - additionalSpace = "0M"; - copyChannel = false; - }; - in { @@ -350,7 +329,7 @@ in virtualisation.diskSize = mkOption { - type = types.nullOr types.ints.positive; + type = types.ints.positive; default = 1024; description = '' The disk size in megabytes of the virtual machine. @@ -393,7 +372,7 @@ in The path (inside the VM) to the device containing the EFI System Partition (ESP). If you are *not* booting from a UEFI firmware, this value is, by - default, `null`. The ESP is mounted under `/boot`. + default, `null`. The ESP is mounted to `boot.loader.efi.efiSysMountpoint`. ''; }; @@ -665,6 +644,14 @@ in description = "Primary IP address used in /etc/hosts."; }; + networking.primaryIPv6Address = + mkOption { + type = types.str; + default = ""; + internal = true; + description = "Primary IPv6 address used in /etc/hosts."; + }; + virtualisation.host.pkgs = mkOption { type = options.nixpkgs.pkgs.type; default = pkgs; @@ -780,10 +767,14 @@ in this can drastically improve performance, but at the cost of disk space and image build time. - As an alternative, you can use a bootloader which will provide you - with a full NixOS system image containing a Nix store and - avoid mounting the host nix store through - {option}`virtualisation.mountHostNixStore`. + The Nix store image is built just-in-time right before the VM is + started. Because it does not produce another derivation, the image is + not cached between invocations and never lands in the store or binary + cache. + + If you want a full disk image with a partition table and a root + filesystem instead of only a store image, enable + {option}`virtualisation.useBootLoader` instead. ''; }; @@ -1011,25 +1002,7 @@ in ]; warnings = - optional ( - cfg.writableStore && - cfg.useNixStoreImage && - opt.writableStore.highestPrio > lib.modules.defaultOverridePriority) - '' - You have enabled ${opt.useNixStoreImage} = true, - without setting ${opt.writableStore} = false. - - This causes a store image to be written to the store, which is - costly, especially for the binary cache, and because of the need - for more frequent garbage collection. - - If you really need this combination, you can set ${opt.writableStore} - explicitly to true, incur the cost and make this warning go away. - Otherwise, we recommend - - ${opt.writableStore} = false; - '' - ++ optional (cfg.directBoot.enable && cfg.useBootLoader) + optional (cfg.directBoot.enable && cfg.useBootLoader) '' You enabled direct boot and a bootloader, QEMU will not boot your bootloader, rendering `useBootLoader` useless. You might want to disable one of those options. @@ -1042,42 +1015,8 @@ in boot.loader.grub.device = mkVMOverride (if cfg.useEFIBoot then "nodev" else cfg.bootLoaderDevice); boot.loader.grub.gfxmodeBios = with cfg.resolution; "${toString x}x${toString y}"; - boot.initrd.kernelModules = optionals (cfg.useNixStoreImage && !cfg.writableStore) [ "erofs" ]; - boot.loader.supportsInitrdSecrets = mkIf (!cfg.useBootLoader) (mkVMOverride false); - boot.initrd.postMountCommands = lib.mkIf (!config.boot.initrd.systemd.enable) - '' - # Mark this as a NixOS machine. - mkdir -p $targetRoot/etc - echo -n > $targetRoot/etc/NIXOS - - # Fix the permissions on /tmp. - chmod 1777 $targetRoot/tmp - - mkdir -p $targetRoot/boot - - ${optionalString cfg.writableStore '' - echo "mounting overlay filesystem on /nix/store..." - mkdir -p -m 0755 $targetRoot/nix/.rw-store/store $targetRoot/nix/.rw-store/work $targetRoot/nix/store - mount -t overlay overlay $targetRoot/nix/store \ - -o lowerdir=$targetRoot/nix/.ro-store,upperdir=$targetRoot/nix/.rw-store/store,workdir=$targetRoot/nix/.rw-store/work || fail - ''} - ''; - - systemd.tmpfiles.settings."10-qemu-vm" = lib.mkIf config.boot.initrd.systemd.enable { - "/etc/NIXOS".f = { - mode = "0644"; - user = "root"; - group = "root"; - }; - "${config.boot.loader.efi.efiSysMountPoint}".d = { - mode = "0644"; - user = "root"; - group = "root"; - }; - }; - # After booting, register the closure of the paths in # `virtualisation.additionalPaths' in the Nix database in the VM. This # allows Nix operations to work in the VM. The path to the @@ -1093,8 +1032,7 @@ in ''; boot.initrd.availableKernelModules = - optional cfg.writableStore "overlay" - ++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx" + optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx" ++ optional (cfg.tpm.enable) "tpm_tis"; virtualisation.additionalPaths = [ config.system.build.toplevel ]; @@ -1102,7 +1040,9 @@ in virtualisation.sharedDirectories = { nix-store = mkIf cfg.mountHostNixStore { source = builtins.storeDir; - target = "/nix/store"; + # Always mount this to /nix/.ro-store because we never want to actually + # write to the host Nix Store. + target = "/nix/.ro-store"; securityModel = "none"; }; xchg = { @@ -1194,7 +1134,7 @@ in name = "nix-store"; file = ''"$TMPDIR"/store.img''; deviceExtraOpts.bootindex = "2"; - driveExtraOpts.format = if cfg.writableStore then "qcow2" else "raw"; + driveExtraOpts.format = "raw"; }]) (imap0 (idx: _: { file = "$(pwd)/empty${toString idx}.qcow2"; @@ -1212,10 +1152,7 @@ in virtualisation.fileSystems = let mkSharedDir = tag: share: { - name = - if tag == "nix-store" && cfg.writableStore - then "/nix/.ro-store" - else share.target; + name = share.target; value.device = tag; value.fsType = "9p"; value.neededForBoot = true; @@ -1240,8 +1177,19 @@ in # Sync with systemd's tmp.mount; options = [ "mode=1777" "strictatime" "nosuid" "nodev" "size=${toString config.boot.tmp.tmpfsSize}" ]; }; - "/nix/${if cfg.writableStore then ".ro-store" else "store"}" = lib.mkIf cfg.useNixStoreImage { + "/nix/store" = lib.mkIf (cfg.useNixStoreImage || cfg.mountHostNixStore) (if cfg.writableStore then { + overlay = { + lowerdir = [ "/nix/.ro-store" ]; + upperdir = "/nix/.rw-store/upper"; + workdir = "/nix/.rw-store/work"; + }; + } else { + device = "/nix/.ro-store"; + options = [ "bind" ]; + }); + "/nix/.ro-store" = lib.mkIf cfg.useNixStoreImage { device = "/dev/disk/by-label/${nixStoreFilesystemLabel}"; + fsType = "erofs"; neededForBoot = true; options = [ "ro" ]; }; @@ -1250,40 +1198,13 @@ in options = [ "mode=0755" ]; neededForBoot = true; }; - "/boot" = lib.mkIf (cfg.useBootLoader && cfg.bootPartition != null) { + "${config.boot.loader.efi.efiSysMountPoint}" = lib.mkIf (cfg.useBootLoader && cfg.bootPartition != null) { device = cfg.bootPartition; fsType = "vfat"; - noCheck = true; # fsck fails on a r/o filesystem }; } ]; - boot.initrd.systemd = lib.mkIf (config.boot.initrd.systemd.enable && cfg.writableStore) { - mounts = [{ - where = "/sysroot/nix/store"; - what = "overlay"; - type = "overlay"; - options = "lowerdir=/sysroot/nix/.ro-store,upperdir=/sysroot/nix/.rw-store/store,workdir=/sysroot/nix/.rw-store/work"; - wantedBy = ["initrd-fs.target"]; - before = ["initrd-fs.target"]; - requires = ["rw-store.service"]; - after = ["rw-store.service"]; - unitConfig.RequiresMountsFor = "/sysroot/nix/.ro-store"; - }]; - services.rw-store = { - before = [ "shutdown.target" ]; - conflicts = [ "shutdown.target" ]; - unitConfig = { - DefaultDependencies = false; - RequiresMountsFor = "/sysroot/nix/.rw-store"; - }; - serviceConfig = { - Type = "oneshot"; - ExecStart = "/bin/mkdir -p -m 0755 /sysroot/nix/.rw-store/store /sysroot/nix/.rw-store/work /sysroot/nix/store"; - }; - }; - }; - swapDevices = (if cfg.useDefaultFilesystems then mkVMOverride else mkDefault) [ ]; boot.initrd.luks.devices = (if cfg.useDefaultFilesystems then mkVMOverride else mkDefault) {}; |