diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index 06210529eb8c..c98916f60fa3 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -108,9 +108,9 @@ let set -e - NIX_DISK_IMAGE=$(readlink -f "''${NIX_DISK_IMAGE:-${config.virtualisation.diskImage}}") + NIX_DISK_IMAGE=$(readlink -f "''${NIX_DISK_IMAGE:-${toString config.virtualisation.diskImage}}") || test -z "$NIX_DISK_IMAGE" - if ! test -e "$NIX_DISK_IMAGE"; then + if test -n "$NIX_DISK_IMAGE" && ! test -e "$NIX_DISK_IMAGE"; then ${qemu}/bin/qemu-img create -f qcow2 "$NIX_DISK_IMAGE" \ ${toString config.virtualisation.diskSize}M fi @@ -346,7 +346,7 @@ in virtualisation.diskImage = mkOption { - type = types.str; + type = types.nullOr types.str; default = "./${config.system.name}.qcow2"; defaultText = literalExpression ''"./''${config.system.name}.qcow2"''; description = @@ -354,6 +354,9 @@ in Path to the disk image containing the root filesystem. The image will be created on startup if it does not exist. + + If null, a tmpfs will be used as the root filesystem and + the VM's state will not be persistent. ''; }; @@ -990,12 +993,12 @@ in ]; virtualisation.qemu.drives = mkMerge [ - [{ + (mkIf (cfg.diskImage != null) [{ name = "root"; file = ''"$NIX_DISK_IMAGE"''; driveExtraOpts.cache = "writeback"; driveExtraOpts.werror = "report"; - }] + }]) (mkIf cfg.useNixStoreImage [{ name = "nix-store"; file = ''"$TMPDIR"/store.img''; @@ -1018,20 +1021,21 @@ in }) cfg.emptyDiskImages) ]; + fileSystems = mkVMOverride cfg.fileSystems; + # Mount the host filesystem via 9P, and bind-mount the Nix store # of the host into our own filesystem. We use mkVMOverride to # allow this module to be applied to "normal" NixOS system # configuration, where the regular value for the `fileSystems' # attribute should be disregarded for the purpose of building a VM # test image (since those filesystems don't exist in the VM). - fileSystems = - let + virtualisation.fileSystems = let mkSharedDir = tag: share: { name = if tag == "nix-store" && cfg.writableStore - then "/nix/.ro-store" - else share.target; + then "/nix/.ro-store" + else share.target; value.device = tag; value.fsType = "9p"; value.neededForBoot = true; @@ -1039,44 +1043,42 @@ in [ "trans=virtio" "version=9p2000.L" "msize=${toString cfg.msize}" ] ++ lib.optional (tag == "nix-store") "cache=loose"; }; - in - mkVMOverride (cfg.fileSystems // - optionalAttrs cfg.useDefaultFilesystems { - "/".device = cfg.bootDevice; - "/".fsType = "ext4"; - "/".autoFormat = true; - } // - optionalAttrs config.boot.tmpOnTmpfs { - "/tmp" = { + in lib.mkMerge [ + (lib.mapAttrs' mkSharedDir cfg.sharedDirectories) + { + "/" = lib.mkIf cfg.useDefaultFilesystems (if cfg.diskImage == null then { + device = "tmpfs"; + fsType = "tmpfs"; + } else { + device = cfg.bootDevice; + fsType = "ext4"; + autoFormat = true; + }); + "/tmp" = lib.mkIf config.boot.tmpOnTmpfs { device = "tmpfs"; fsType = "tmpfs"; neededForBoot = true; # Sync with systemd's tmp.mount; options = [ "mode=1777" "strictatime" "nosuid" "nodev" "size=${toString config.boot.tmpOnTmpfsSize}" ]; }; - } // - optionalAttrs cfg.useNixStoreImage { - "/nix/${if cfg.writableStore then ".ro-store" else "store"}" = { + "/nix/${if cfg.writableStore then ".ro-store" else "store"}" = lib.mkIf cfg.useNixStoreImage { device = "${lookupDriveDeviceName "nix-store" cfg.qemu.drives}"; neededForBoot = true; options = [ "ro" ]; }; - } // - optionalAttrs (cfg.writableStore && cfg.writableStoreUseTmpfs) { - "/nix/.rw-store" = { + "/nix/.rw-store" = lib.mkIf (cfg.writableStore && cfg.writableStoreUseTmpfs) { fsType = "tmpfs"; options = [ "mode=0755" ]; neededForBoot = true; }; - } // - optionalAttrs cfg.useBootLoader { # see note [Disk layout with `useBootLoader`] - "/boot" = { + "/boot" = lib.mkIf cfg.useBootLoader { device = "${lookupDriveDeviceName "boot" cfg.qemu.drives}2"; # 2 for e.g. `vdb2`, as created in `bootDisk` fsType = "vfat"; noCheck = true; # fsck fails on a r/o filesystem }; - } // lib.mapAttrs' mkSharedDir cfg.sharedDirectories); + } + ]; boot.initrd.systemd = lib.mkIf (config.boot.initrd.systemd.enable && cfg.writableStore) { mounts = [{