Did you know that it is rather easy to setup a VM to test your NixOs configuration?
# flake.nix
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
outputs = { self, nixpkgs, ... }:
let
system = "x86_64-linux";
in
{
# test is a hostname for our machine
nixosConfigurations.test = nixpkgs.lib.nixosSystem {
inherit system;
modules = [
./configuration.nix
];
};
};
}
# configuration.nix
{ config, lib, pkgs, ... }: {
# customize kernel version
boot.kernelPackages = pkgs.linuxPackages_5_15;
users.groups.admin = {};
users.users = {
admin = {
isNormalUser = true;
extraGroups = [ "wheel" ];
password = "admin";
group = "admin";
};
};
virtualisation.vmVariant = {
# following configuration is added only when building VM with build-vm
virtualisation = {
memorySize = 2048; # Use 2048MiB memory.
cores = 3;
graphics = false;
};
};
services.openssh = {
enable = true;
settings.PasswordAuthentication = true;
};
networking.firewall.allowedTCPPorts = [ 22 ];
environment.systemPackages = with pkgs; [
htop
];
system.stateVersion = "23.05";
}
git init # skip this step if you are inside already tracked repository
git add . # flakes requires at least tracking the files
nixos-rebuild build-vm --flake .#test
# expose port 22 from guest
export QEMU_NET_OPTS="hostfwd=tcp::2221-:22"
result/bin/run-nixos-vm
# ssh onto the machine
ssh -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no admin@localhost -p 2221
@sanzoghenzo Yup, but this can easily be simplified with a function if you'd like to avoid repetition. For example:
Which can also be done for the system config:
Note: The
rec
keyword allows us to refer tovm-test
from within the same attrset (see Nix language basics — nix.dev).Also, you can include the
QEMU_NET_OPTS
env var into your dev shell:Just like with apps, you can write more devShells according to your needs and activate them with
nix develop .#devShells.<name>
.Alternatively, you can forward the port in the system config with:
Notes:
nix run .#<name>
andnix develop .#<name>
instead ofnix run .#apps.<name>
andnix develop .#devShells.<name>
Now, we can refactor things a bit and import
mkAppVM
andmkSystem
from a separate file, which might make things cleaner:utils.nix
Which leaves us with this final configuration:
flake.nix
Thanks for suggesting this as it looks like an interesting and flexible tool, but for this usecase it makes more sense to me to use apps because it integrates directly with Nix, thus leveraging its full capabilites. Also, after removing the boilerplate, the Nix code looks cleaner and more readable to me.
That said, I'm curious if
task
and similar tools would be more suitable for more complex cases.