How to use vmTools.diskImageFuns? [soved]

edit: See first comment for updated question,

below is the original post which describes my general problem while I found it might be
solvable by vmTools.diskImageFuns


Hi,

I’m trying to build a qcow2 image of a Debian VM using debootstrap as a derivation but I keep hitting various snags.

First - I don’t care much about reproducibility at this point, nor do I care about the sandbox (I know…)

My current (non-working) iteration:

      images.debian = let
        version = builtins.readFile "${debian-snapshot}/debian-snapshot/version";
        base_url = builtins.readFile "${debian-snapshot}/debian-snapshot/base_url";
      in
        pkgs.runCommandWith {
          name = "debian-vm";
          derivationArgs = {
            inherit version;
            __useChroot = false;
            nativeBuildInputs = with pkgs; [ debootstrap qemu lkl parted util-linux ];
          };
        } ''           
          _img=disk.raw
          _mount=mnt

          truncate -s 15G $_img
          mkdir $_mount

          parted --script $_img -- \
            mklabel gpt \
            mkpart ESP fat32 8MiB 512MiB \
            set 1 boot on \
            mkpart ROOT ext4 512MiB -1 \
            print

          ls /dev -l
          lsmod

          _loop=$(losetup -f --show -P $_img)
          _efiPart="${_loop}p1"
          _rootPart="${_loop}p2"
          
          mount -o loop $_rootPart $_mount
          mkdir -p $_mount/boot/efi
          mount -o loop $_efiPart= $_mount/boot/efi
        
          debootstrap --arch amd64 --variant=minbase stable $_mount ${base_url}/${version}

          umount -R $_mount
          rmdir $_mount

          losetup -d $_loop

          qemu-img convert -f raw -O qcow2 $_img $out

          rm $_img
        '';
    };

No matter what I try, I always hit a problem with not having enough “power” in the build sandbox (even with __useChroot = false).

I tried various approaches:

  • create raw disk image and mount it as loopback → no root, no /dev/loop in the sandbox
  • use lkl approach similar to what image-builder does but with lklfuse instead of cptofs → no fuse module in the sandbox
  • qemu and libguestfs mounts → no supermin appliance even with pkgs.libguestfs-with-appliance

One thing I haven’t tried (yet) is buildInLinuxVM but I would like to avoid that - the build worker may not have KVM capabilities, in fact, it will not even be NixOS, the build will be run a in a nix docker container.

What approach did I forget to try? Or is there some kind of tooling around this I’m not aware of? Is it even feasible?

Thanks,

-j.

edit: never mind, I used diskImages assuming it was a shorthand for diskImageFuns but I must have used it wrong. Replacing the function with diskImageFuns works as expected

still don’t understand the error tho…


ok, so I found vmTools.diskImageFuns which looks almost exactly like the thing I want but I have no idea how to use it (in a flake output).

I got this basic PoC flake:

{
  description = "Debian nix-builder";

  inputs = {
    nixpkgs = {
      type = "github";
      owner = "NixOS";
      repo = "nixpkgs";
      ref = "nixos-24.11";
     };
   };

  outputs = { self, nixpkgs }: 
    let
      system = "x86_64-linux";
      pkgs = import nixpkgs { inherit system; };
    in
  {
    packages.images.debian = pkgs.vmTools.diskImages.debian12x86_64 {};
  };
}

But that gives me an error which I don’t understand:

error: attempt to call something which is not a function but a set: { type = "derivation"; QEMU_OPTS = «thunk»; __ignoreNulls = true; __structuredAttrs = «thunk»; all = «thunk»; args = «thunk»; buildCommand = «thunk»; buildInputs = «thunk»; builder = «thunk»; cmakeFlags = «thunk»; «44 attributes elided» }
       at /nix/store/3yz8chs4n6kc4k2lk10g39nmj887imv0-source/flake.nix:22:30:
           21|   {
           22|     packages.images.debian = pkgs.vmTools.diskImages.debian12x86_64 {};
             |                              ^
           23|   };

packages.images.debian = pkgs.vmTools.diskImages.debian12x86_64; without the attribute set should work.