Detect "build-vm" in flake

Hello, I’m converting my NixOS configuration to a flake and refactoring it, and I discovered how useful nixos-rebuild build-vm can be to test out my config in a VM before committing it to my machine.

However, I need some settings to be different when I’m in a VM. What’s the best way to detect that the system is being built by build-vm?

I’ve come accross this question, sadly without answer: Is there a way to determine if the config is used to build a vm?

I found out that running build-vm includes https://github.com/NixOS/nixpkgs/blob/2a93ea177c3d7700b934bf95adfe00c435f696b8/nixos/modules/virtualisation/qemu-vm.nix which sets services.qemuGuest.enable to true. So I can use this value to detect that a VM is being built, but it feels dirty. Is there a better way?

PS: I discovered that you can build and run the VM in one step with nix run '.#nixosConfigurations.HOSTNAME.config.system.build.vm'. Might be obvious but maybe this can be useful for someone.

4 Likes

I define a second nixosConfiguration, call it vm, and import all the modules the normal config does, plus an extra module for my vm settings (defined inline in flake.nix because it’s so small). I also make liberal use of lib.mkOverride.

Then build my vm with nixos-rebuild build-vm .#vm.

Thanks, that’s an option I considered. In the end, I checked for the existence of options.virtualisation.qemu with options.virtualisation ? qemu.

1 Like

I personally prefer the separate entrypoints because it makes very explicit where my test environment differs from the final deployed one, while having if conditions littered across modules makes it a bit harder to trace. On the other hand, the latter is very good at keeping bits of related configuration close together.

It’s a trade-off, but I think these are the two most reasonable options.

1 Like

I’m not super knowledgeable in this domain but I think you could add VM specific options to under one of these options NixOS Search

I wanted to have a simple user password for testing purposes and stumbeled over this thread

Its as simple as

{
  virtualisation.vmVariant = {
    # following configuration is added only when building VM with build-vm
    users.users.root.initialPassword = "root";
  };
}

Everything in virtualisation.vmVariant is only applied in the VM.

2 Likes