Using virtualization.qemu with an iso image

I’m making a little nixos-based ISO image as a USB rescue image – something I think NixOS is particularly well suited for! I’m hoping to have something that is headless-friendly that will boot straight to a copytoram image (several of my devices have only 1 USB port) that has tools for btrfs, zfs, arch-install-scripts, and several others tools available offline.

It’s coming along pretty well! GitHub - n8henrie/nixos-rescue: NixOS-based USB rescue image

Now I’m trying to add an additional flake output to run the ISO as a virtual image as part of testing. However, I’m having trouble using the user-friendly virtualisation.* tools, in part due to it being a read-only root (which fsk doesn’t like).

I’m able to boot the image with qemu directly, and I’m sure I could just do something like I’ve done in another flake to wrap a script around qemu and get the job done:

qemu-system-x86_64 \
    -m 2048M \
    --drive media=cdrom,file=rescue.iso,format=raw,readonly=on \
    -nographic

However, I was looking at all the nifty tools under virtualisation and wondering if that might be doable as well. Currently ~it~ EDIT: master runs, but it creates a qcow2 drive, and I’m hoping to have something boot directly from the ISO, just like it will from the USB drive.

My current uncommitted attempt looks like this:

{
  description = "NixOS-based rescue drive";
  inputs.nixos.url = "nixpkgs/nixos-22.11";
  outputs = {
    self,
    nixos,
  }: let
    system = "x86_64-linux";
  in {
    packages.x86_64-linux = rec {
      default = rescue.config.system.build.isoImage;
      rescue = nixos.lib.nixosSystem {
        inherit system;
        modules = [
          ./configuration.nix
        ];
      };
      vm =
        (nixos.lib.nixosSystem {
          inherit system;
          modules = [
            ./configuration.nix
            (nixos + "/nixos/modules/virtualisation/qemu-vm.nix")
            (nixos + "/nixos/modules/profiles/qemu-guest.nix")
            ({
              config,
              pkgs,
              ...
            }: {
              virtualisation = {
                memorySize = 2048;
                useDefaultFilesystems = false;
                # useBootLoader = true;
                graphics = false;
                fileSystems."/" = {
                  device = "/dev/vda1";
                  fsType = "iso9660";
                };
                qemu = {
                  drives = [
                    {
                      file = "${self.outputs.packages.x86_64-linux.default}/iso/rescue.iso";
                      driveExtraOpts = {
                        media = "cdrom";
                        format = "raw";
                        readonly = "on";
                      };
                    }
                  ];
                };
              };
            })
          ];
        })
        .config
        .system
        .build
        .vm;
    };
    apps.x86_64-linux.default = {
      type = "app";
      program = "${self.outputs.packages.x86_64-linux.vm}/bin/run-rescue-vm";
    };
  };
}

but it fails with:

$ nix run
warning: Git tree '/home/n8henrie/git/nixos-rescue' is dirty
SeaBIOS (version rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org)


iPXE (http://ipxe.org) 00:03.0 CA00 PCI2.10 PnP PMM+7FF90E50+7FEF0E50 CA00



Booting from ROM...
Probing EDD (edd=off to disable)... o

<<< NixOS Stage 1 >>>

loading module loop...
loading module overlay...
loading module virtio_balloon...
loading module virtio_console...
loading module virtio_rng...
loading module vfat...
loading module nls_cp437...
loading module nls_iso8859-1...
loading module dm_mod...
running udev...
Starting version 251.10
kbd_mode: KDSKBMODE: Inappropriate ioctl for device
starting device mapper and LVM...
mounting /dev/vda1 on /...
mounting nix-store on /nix/.ro-store...
mkdir: can't create directory '/mnt-root/nix/': Read-only file system
mount: mounting nix-store on /mnt-root/nix/.ro-store failed: No such file or directory

An error occurred in stage 1 of the boot process, which must mount the
root filesystem on `/mnt-root' and then start stage 2.  Press one
of the following keys:

  i) to launch an interactive shell
  f) to start an interactive shell having pid 1 (needed if you want to
     start stage 2's init manually)
  r) to reboot immediately
  *) to ignore the error and continue

It looks like there were similar issues in this thread from someone trying to boot from the installation ISO.

Is there an approach with virtualization.qemu that would let me boot a read-only ISO image directly?

3 Likes

Why not use useBootLoader? You can also try tmpfs as /

Had tried it (that’s why commented out).

Gets to here and then seems to hang (unclear why):

SeaBIOS (version rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org)
iPXE (http://ipxe.org) 00:03.0 CA00 PCI2.10 PnP PMM+7FF90ED0+7FEF0ED0 CA00
Booting from Hard Disk...
fileSystems."/" = {
                  device = "tmpfs";
                  fsType = "tmpfs;
                };

That works, but then it creates the rescue.qcow2 file, which I’m trying to avoid. Hmmm.

Setting virtualisation.diskImage = ""; and nothing runs. Looks like this is getting some recent attention: nixos/qemu-vm: allow use without a disk image by lheckemann · Pull Request #206839 · NixOS/nixpkgs · GitHub

Woohoo, diskImage = "/dev/null" as in that PR seems to work! Will post a link to working config soon.

Relevant commit: Make bootable VM target for testing · n8henrie/nixos-rescue@c5940ae · GitHub

I needed to set:

  • useDefaultFilesystems = false;
  • diskImage = "/dev/null";

For the root FS:

  • fsType = "tmpfs";
  • options = ["mode=0755"];

See that commit for further details.

2 Likes