Dynamically modifying a machine during a NixOS test

I’ve finally got around to fixing NixOS managing ZFS data sets with spaces in the name · Issue #29273 · NixOS/nixpkgs · GitHub and am trying to write a NixOS test for my patch.

I’m having trouble figuring out how I can modify the machine my test is running in while the test is running, as there is no /etc/nixos/configuration.nix.

My test script currently looks like this:

testScript = ‘’
$machine->succeed(“modprobe zfs”);
$machine->succeed(“zpool status”);

$machine->succeed("truncate -s 100M /test.img");
$machine->succeed("zpool create tank /test.img");

$machine->succeed("zfs create -o mountpoint=legacy tank/Foo\\ Bar");
# TODO: modify configuration.nix to include:
# fileSystems."/Foo Bar" = { device = "tank/Foo Bar"; fsType = "zfs"; };
# TODO: nixos-rebuild switch
# and ensure /etc/fstab is properly escaped

‘’;

Any help? Thank you.

@fpletz has some wizardry at offer IIRC

I’m not sure what you mean by “dynamic”, but you can switch to another configuration. Here is an example test which is actually doing this:

The idea here is to have two nodes defined, one for the initial configuration and another one for the configuration you want to switch to. You only start the initial configuration (via $initial->start or anything implicitly triggering this) and afterwards you just query the toplevel attribute for the configuration you want to switch to using the nodes attribute and run switch-to-configuration test.

Here is a shorter example:

import <nixpkgs/nixos/tests/make-test.nix> {
  name = "foobar";

  nodes = {
    initial = { pkgs, ... }: {
      environment.systemPackages = [ pkgs.hello ];
    };
    new = {
      services.openssh.enable = true;
    };
  };

  testScript = { nodes, ... }: let
    inherit (nodes.new.config.system.build) toplevel;
  in ''
    $initial->waitForUnit('multi-user.target');
    $initial->succeed('hello');
    $initial->fail('nc -z 127.0.0.1 22');

    $initial->succeed('${toplevel}/bin/switch-to-configuration test');
    $initial->fail('hello');
    $initial->succeed('nc -z 127.0.0.1 22');
  '';
}

Update 2023-11: Note that nowadays there is a better way to do this using the specialisation option, here is a test that uses this option:

2 Likes

aszlig,

That appears to be exactly what I’m looking for. Appreciate the very clear answer!