With this patch I essentially get the expected list of maintainers for changes in
nixos-tests.
The downside of this approach is that the CI facility assumes that
there's at most a single definition of `meta.maintainers`, however it
can be more in a module-system context.
For simplicity, just use the first definition location for the time
being.
Verified with
let
lib = import ./lib;
maintainers = import ./ci/eval/compare/maintainers.nix { inherit lib; };
in
maintainers {
changedFiles = [
"nixos/tests/matrix/matrix-authentication-service.nix"
];
affectedAttrPaths = map (lib.splitString ".") [
"nixosTests.matrix-authentication-service"
];
}
In 9e78baf, Aarch64 machines were added the `-device virtio-gpu-pci`
argument, to mirror `-vga std` option that was added unconditionally to
virtualised x86_64 machines. This also enabled screenshots on aarch64
machines to be taken in tests. Since then, in a7ca287, the `-vga std`
option was removed, because that is the default value of this option
embedded in QEMU since version 2.2.
Removing it from the hard-coded list of qemu options makes it possible
for the user to choose their own `-vga` value. Similarly, for Aarch
virtualised machines, choosing unconditionally the `-device virtio-gpu-pci`
option instead of e.g `-device virtio-gpu-gl-pci`, can be bothersome too - see:
https://discourse.nixos.org/t/test-an-aarch64-linux-vm-wayland-compositor-from-an-x86-64-linux-host/77416/2
This commit is similar to 44c6c2ef16 which
was reverted in #527048.
After d95261b435, the following flake.nix fails:
```nix
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { nixpkgs, ... }: {
nixosConfigurations.demo = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
({ lib, ... }: {
boot.loader.grub.enable = false;
fileSystems."/" = { device = "none"; fsType = "tmpfs"; };
nixpkgs.config.packageOverrides =
lib.mkIf false (_: { });
})
];
};
};
}
```
This is the error:
```
$ nix build /tmp/tmp.vWEVitTgK9/#nixosConfigurations.demo.config.system.build.toplevel
evaluation warning: system.stateVersion is not set, defaulting to 26.05. Read why this matters on https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion.
error:
… while calling the 'derivationStrict' builtin
at <nix/derivation-internal.nix>:37:12:
36|
37| strict = derivationStrict drvAttrs;
| ^
38|
… while evaluating derivation 'nixos-system-nixos-26.05.20260409.4c1018d'
whose name attribute is located at /nix/store/anvdcc2arw7kqrvwnidvhw6ypkkvws68-source/pkgs/stdenv/generic/make-derivation.nix:541:11
… while evaluating attribute 'buildCommand' of derivation 'nixos-system-nixos-26.05.20260409.4c1018d'
at /nix/store/anvdcc2arw7kqrvwnidvhw6ypkkvws68-source/nixos/modules/system/activation/top-level.nix:64:7:
63| passAsFile = [ "extraDependencies" ];
64| buildCommand = systemBuilder;
| ^
65|
… while evaluating the option `environment.etc.dbus-1.source':
… while evaluating the default value of option `pythonTestDriverPackage`
… while evaluating the module argument `hostPkgs' in "/nix/store/anvdcc2arw7kqrvwnidvhw6ypkkvws68-source/nixos/lib/testing/driver.nix":
… noting that argument `hostPkgs` is not externally provided, so querying `_module.args` instead, requiring `config`
… while evaluating the option `hostPkgs':
(stack trace truncated; use '--show-trace' to show the full, detailed trace)
error: The option `hostPkgs' was accessed but has no value defined. Try setting the option.
```
Setting a `defaultText` fixes the issue.
I've also added a regression test under `nixos/tests/nixos-test-driver/` and
fixed a typo in the option description ("implemetnation").
When "non-user" modules are not placed in baseModules or
extraModules (arguments of eval-config.nix), noUserModules.evalModules
breaks if the options defined in those modules are consumed. In order
to restore noUserModules functionality for NixOS VM (and now nspawn)
tests, the modules implementing test behavior are moved to baseModules.
ignore the NixOS configuration's hostname and only use the test driver
attribute for the type hints. This allows for setting a different host
name than the node name in the test without trigggering type errors in
the typecheck phase.
co-authored-by: phanirithvij <phanirithvij2000@gmail.com>
`vhost-device-vsock`[1] is a custom implementation of AF_VSOCK, but the
application on the host-side uses a UNIX domain-socket. This gives us
the following nice properties:
* We don't need to do `--arg sandbox-paths /dev/vhost-vsock` anymore for
debugging builds within the sandbox. That means, untrusted users can
also debug these kinds of tests now.
* This prevents CID conflicts on the host-side, i.e. there's no need for
using `sshBackdoor.vsockOffset` for tests anymore.
A big shout-out goes to Allison Karlitskaya, the developer of test.thing[2]
who talked about this approach to do AF_VSOCK on All Systems Go 2025.
This patch requires systemd 258[3] because this contains `vhost-mux` in
its SSH config which is needed to connect to the VMs from now on.
To not blow up the patches even more, this only uses AF_VSOCK for the
debugger. A potential follow-up for the future would be a removal of the
current `backdoor.service` and replace it entirely by this
functionality.
The internal implementation tries to be consistent with how VLANs and
machines are handled, i.e. the processes are started when the Driver's
context is entered and cleaned up in __exit__().
I decided to push the process management and creation of sockets for
vhost-device-vsock into its own class, that's an implementation detail
and not a concern for the test-driver. In fact, `vhost-device-vsock` is
something we can drop once QEMU implements native support for using
AF_UNIX on the host-side[4]. `VsockPair` is its own class since
returning e.g. a triple of `(Path, Path, Int)` would be ambiguous in
what is the guest and what the host path (and frankly, I found it hard
to distinguish the two when reading the docs of `vhost-device-vsock`
initially).
Finally, now that we can do the SSH backdoor without adding additional
devices to the sandbox, I figured, it's time to write a test-case for
it.
[1] https://github.com/rust-vmm/vhost-device/blob/main/vhost-device-vsock/README.md
[2] https://codeberg.org/lis/test.thing
[3] https://github.com/NixOS/nixpkgs/pull/427968
[4] https://gitlab.com/qemu-project/qemu/-/issues/2095
The nspawn container support (23f1e6370d) added a `containers`
argument to the testScript caller. This breaks tests whose testScript
uses strict pattern matching without ellipsis, e.g. `{ nodes }:`,
since Nix rejects unexpected arguments.
Use `builtins.intersectAttrs` to only pass arguments the function
actually expects, making the caller forward-compatible with future
argument additions.
Fixes: 23f1e6370d ("nixos/test-driver: add support for nspawn containers")
This shares a lot in common with the
<nixos/modules/virtualisation/nixos-containers.nix> infrastructure, but
is designed to behave like our `qemu-vm.nix` profile (provides a lot of
the same `virtualisation.*` options, produces a simple script you can
run).
This lays the groundwork to be able to rework the nixos test
infrastructure to allow for containers as well as qemu nodes. That work
isn't quite done yet, but if you want more context, you can see the
followup work in <https://github.com/applicative-systems/nixpkgs/compare/nspawn-container-profile...applicative-systems:nixpkgs:nixos-test-containers>.
Credit due to the [Clan.lol](https://clan.lol/) team for first
implementing this. I'm just cleaning it up and making it play nicely
with upstream.
To try it out, create a `demo.nix`:
```nix
let
pkgs = import ./. { };
mkContainer =
{
nodeNumber,
vlans,
}:
pkgs.nixos (
{
config,
modulesPath,
pkgs,
lib,
...
}:
let
interfaces = lib.attrValues config.virtualisation.allInterfaces;
# Automatically assign IP addresses to requested interfaces.
assignIPs = lib.filter (i: i.assignIP) interfaces;
ipInterfaces = lib.forEach assignIPs (
i:
lib.nameValuePair i.name {
ipv4.addresses = [
{
address = "192.168.${toString i.vlan}.${toString nodeNumber}";
prefixLength = 24;
}
];
}
);
in
{
imports = [ "${modulesPath}/virtualisation/nspawn-container" ];
users.users.root.password = "";
networking.hostName = "c${toString nodeNumber}";
virtualisation.vlans = vlans;
networking.interfaces = lib.listToAttrs ipInterfaces;
environment.systemPackages = [ pkgs.neovim ];
system.stateVersion = lib.trivial.release;
}
);
in
{
container1 = mkContainer {
nodeNumber = 1;
vlans = [ 1 ];
};
container2 = mkContainer {
nodeNumber = 2;
vlans = [ 2 ];
};
container12 = mkContainer {
nodeNumber = 12;
vlans = [
1
2
];
};
}
```
Build and run the machines in separate terminals (unfortunately,
`systemd-nspawn` requires `sudo`):
```console
$ sudo $(nix-build ./demo.nix -A container1.config.system.build.nspawn)/bin/run-c1-nspawn
$ sudo $(nix-build ./demo.nix -A container2.config.system.build.nspawn)/bin/run-c2-nspawn
$ sudo $(nix-build ./demo.nix -A container12.config.system.build.nspawn)/bin/run-c12-nspawn
```
You can log into this machines as `root`, and verify they can ping each
other:
`c1` can ping `c12`:
```
[root@c1:~]# ping 192.168.1.12 -c 1
PING 192.168.1.12 (192.168.1.12) 56(84) bytes of data.
64 bytes from 192.168.1.12: icmp_seq=1 ttl=64 time=0.164 ms
...
```
So can `c2`:
```
[root@c2:~]# ping 192.168.2.12
PING 192.168.2.12 (192.168.2.12) 56(84) bytes of data.
64 bytes from 192.168.2.12: icmp_seq=1 ttl=64 time=0.127 ms
```