I’m trying to get into setting up multiple hosts with NixOS and I figured I’d start with nixos-anywhere, cause I found a straightforward tutorial, but can I somehow also get an image that I can load into something like VirtualBox?
My first target is building a flake for an rpi with kodi, so I’d like to check that it’s working as expected in an emulator before I push it to the rpi.
I don’t think nixos-anywhere supports this specifically. You could set up a virtual machine with ssh keys and use it as a target for nixos-anywhere (you might need to do some configuration in VirtualBox in order to access the guest from the host). For testing a configuration, you can also use nixos-generators or the build-vm subcommand of nixos-rebuild (both of which are a lot less effort than manually setting up a VM).
This is a working sample to give you more than just the idea, but please apply Nix language best practices in reality.
# default.nix
let
pkgs = import <nixpkgs> { };
disko = builtins.fetchTarball "https://github.com/nix-community/disko/archive/master.tar.gz";
# convenience wrapper to evaluate a configuration
nixos = config: pkgs.nixos [ "${disko}/module.nix" config ];
# a sample system configuration
machine-config = { ... }: {
boot.loader.systemd-boot.enable = true;
disko.devices.disk.main = {
device = "/dev/sda";
content = {
type = "gpt";
partitions = {
boot = {
size = "1G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
system.stateVersion = "23.11";
};
# evaluated machine configuration
machine = nixos machine-config;
in
{
tests = machine.config.system.build.installTest;
}
To run the test:
nix-build -A tests --no-out-link
(Without --no-out-link it will produce an empty result symlink in the current directory, because the derivation, which runs the test when it’s built, doesn’t write anything to the store.)
What I also played around with recently is having two helper scripts in the development shell to further ease testing:
# default.nix
let
# ...
run-vm = pkgs.writeShellApplication {
name = "run-vm";
text = ''
# make QEMU create the disk image in memory
pushd "$(mktemp -d)" > /dev/null
"$(nix-build ${toString ./.} -A machine.config.system.build.vm --no-out-link)"/bin/run-nixos-vm "$@"
# clean up
rm nixos.qcow2
popd > /dev/null
'';
};
run-tests = pkgs.writeShellApplication {
name = "run-tests";
text = ''
nix-build ${toString ./.} -A tests --no-out-link "$@"
'';
};
in
{
# ...
inherit machine;
shell = pkgs.mkShell {
packages = [ run-vm run-tests ];
};
Add a shell.nix for convenience, since now default.nix contains more than one derivation and otherwise you’d have to run nix-shell -A shell every time. Then you can run the configuration in a VM with run-vm, and run the tests with run-tests within your nix-shell.
Expanding the test suite to multiple machine configurations is left as an exercise for the reader.
[b0ef@ximian:~/nix-build/tst1]$ nix-build -A shell
these 3 derivations will be built:
/nix/store/05y9s0x8nn8dlfn8fy8dmykkznqzaaci-run-tests.drv
/nix/store/l0qg5q37kdmikyhlfxmzfvz77jyqykkh-run-vm.drv
/nix/store/hrvh08g313wbvfr8ia26izq5hd13hxbl-nix-shell.drv
this path will be fetched (0.96 MiB download, 5.96 MiB unpacked):
/nix/store/qc5c375far00lbcmhc55ph1bf0djqb3i-ShellCheck-0.9.0
copying path '/nix/store/qc5c375far00lbcmhc55ph1bf0djqb3i-ShellCheck-0.9.0' from 'https://cache.nixos.org'...
building '/nix/store/05y9s0x8nn8dlfn8fy8dmykkznqzaaci-run-tests.drv'...
building '/nix/store/l0qg5q37kdmikyhlfxmzfvz77jyqykkh-run-vm.drv'...
In /nix/store/a64cvvlf9d4qvspir5srpsb6p17dk507-run-vm/bin/run-vm line 6:
machine="$1"
^-----^ SC2034 (warning): machine appears unused. Verify use (or export if used externally).
For more information:
https://www.shellcheck.net/wiki/SC2034 -- machine appears unused. Verify us...
error: builder for '/nix/store/l0qg5q37kdmikyhlfxmzfvz77jyqykkh-run-vm.drv' failed with exit code 1;
last 7 log lines:
>
> In /nix/store/a64cvvlf9d4qvspir5srpsb6p17dk507-run-vm/bin/run-vm line 6:
> machine="$1"
> ^-----^ SC2034 (warning): machine appears unused. Verify use (or export if used externally).
>
> For more information:
> https://www.shellcheck.net/wiki/SC2034 -- machine appears unused. Verify us...
For full logs, run 'nix log /nix/store/l0qg5q37kdmikyhlfxmzfvz77jyqykkh-run-vm.drv'.
error: 1 dependencies of derivation '/nix/store/hrvh08g313wbvfr8ia26izq5hd13hxbl-nix-shell.drv' failed to build
[b0ef@ximian:~/nix-build/tst1]$ ./result/run-vm
bash: ./result/run-vm: Not a directory
[b0ef@ximian:~/nix-build/tst1]$ file result
result: symbolic link to /nix/store/35b3p7rxngjl2ny77a32n6kqng356m4k-nix-shell
If you have a default.nix only then indeed nix-shell -A shell and inside of that run-vm and if you have a separate shell.nix for the shell attribute so to say then just nix-shell and inside of that run-vm.