1
- { pkgs , nixos-anywhere , kexec-installer , nix-vm-test , ... } :
2
-
3
- let
4
- # Create dummy store paths for testing
5
- testPaths = pkgs . runCommand "test-store-paths" { } ''
6
- mkdir -p $out
7
- echo "echo 'Dummy disko script'" > $out/disko
8
- echo "echo 'Dummy system closure'" > $out/system
9
- chmod +x $out/disko $out/system
10
- '' ;
11
- in
12
- nix-vm-test . ubuntu . "22_04" {
13
- memorySize = 2048 ;
14
-
15
- # Forward SSH port to allow connection from the host
16
- virtualisation . forwardPorts = [
17
- { from = "host" ; host . port = 2222 ; guest . port = 22 ; }
18
- ] ;
19
-
20
- # Make the SSH keys available in the VM
21
- sharedDirs = {
22
- sshKeys = {
23
- source = "${ nixos-anywhere } /tests/modules/ssh-keys" ;
24
- target = "/tmp/ssh-keys" ;
25
- } ;
1
+ { pkgs , nixos-anywhere , kexec-installer , nix-vm-test , system-to-install , ... } :
2
+
3
+ ( nix-vm-test . lib . ${ pkgs . system } . ubuntu . "24_04" {
4
+ sharedDirs = { } ;
5
+
6
+ # Configure VM with 2GB memory
7
+ machineConfigModule = { ... } : {
8
+ nodes . vm . virtualisation . memorySize = 2048 ;
26
9
} ;
27
10
28
11
# The test script
29
12
testScript = ''
13
+ # Python imports
14
+ import subprocess
15
+ import tempfile
16
+ import shutil
17
+ import os
18
+
30
19
# Wait for the system to be fully booted
31
20
vm.wait_for_unit("multi-user.target")
32
21
33
22
# Unmask SSH service (which is masked by default in the test VM)
34
- vm.succeed("systemctl unmask ssh.service")
35
- vm.succeed("systemctl unmask ssh.socket")
36
- vm.succeed("systemctl start ssh")
23
+ vm.succeed("systemctl unmask ssh.service ssh.socket")
24
+
25
+ # Generate SSH host keys (required for SSH to start)
26
+ vm.succeed("ssh-keygen -A")
37
27
38
28
# Setup SSH with the existing keys
39
29
vm.succeed("mkdir -p /root/.ssh")
40
- vm.succeed("cp /tmp/ssh-keys/ssh.pub /root/.ssh/authorized_keys")
30
+ vm.succeed(
31
+ "echo '${ builtins . replaceStrings [ "\n " ] [ "" ] ( builtins . readFile ./modules/ssh-keys/ssh.pub ) } ' > /root/.ssh/authorized_keys"
32
+ )
41
33
vm.succeed("chmod 644 /root/.ssh/authorized_keys")
42
34
43
35
# Setup SSH for connection from host
44
- vm.succeed("sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config")
45
- vm.succeed("systemctl restart ssh")
46
-
36
+ vm.succeed(
37
+ "sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config"
38
+ )
39
+
40
+ # Start SSH service
41
+ vm.succeed("systemctl start ssh")
42
+
47
43
# Wait for SSH to be available
48
44
vm.wait_for_open_port(22)
49
- print("SSH server is ready")
50
45
51
- # Run nixos-anywhere from the host against the VM
52
- print("Starting kexec test phase...")
53
-
54
- # Use Python's subprocess to run nixos-anywhere from the host
55
- import subprocess
56
-
57
- cmd = f"""${ nixos-anywhere } /bin/nixos-anywhere \\
58
- -i ${ nixos-anywhere } /tests/modules/ssh-keys/ssh \\
59
- --ssh-port 2222 \\
60
- --phases kexec \\
61
- --kexec ${ kexec-installer } \\
62
- --store-paths ${ testPaths } /disko ${ testPaths } /system \\
63
- --debug \\
64
- root@localhost
65
- """
66
-
67
- print(f"Running command: {cmd}")
68
- result = subprocess.run(cmd, shell=True, check=False)
69
-
70
- if result.returncode == 0:
71
- print("kexec phase completed successfully")
72
- else:
73
- print(f"nixos-anywhere failed with exit code {result.returncode}")
74
- raise Exception("nixos-anywhere command failed")
46
+ # Forward SSH port using vm.forward_port method
47
+ ssh_port = 2222
48
+ vm.forward_port(host_port=ssh_port, guest_port=22)
49
+
50
+ # Use temporary file for SSH key with automatic cleanup
51
+ with tempfile.NamedTemporaryFile(mode='w', delete=True, suffix='_ssh_key') as temp_key:
52
+ temp_key_path = temp_key.name
53
+
54
+ # Copy SSH private key to temp file with correct permissions
55
+ shutil.copy2("${ ./modules/ssh-keys/ssh } ", temp_key_path)
56
+ os.chmod(temp_key_path, 0o600)
57
+
58
+ nixos_anywhere_cmd = [
59
+ "${ nixos-anywhere } /bin/nixos-anywhere",
60
+ "-i", temp_key_path,
61
+ "--ssh-port", str(ssh_port),
62
+ "--post-kexec-ssh-port", "2222",
63
+ "--phases", "kexec",
64
+ "--kexec", "${ kexec-installer } ",
65
+ "--store-paths", "${ system-to-install . config . system . build . diskoScriptNoDeps } ",
66
+ "${ system-to-install . config . system . build . toplevel } ",
67
+ "--debug",
68
+ "root@localhost"
69
+ ]
70
+
71
+ result = subprocess.run(nixos_anywhere_cmd, check=False)
72
+
73
+ if result.returncode != 0:
74
+ print(f"nixos-anywhere failed with exit code {result.returncode}")
75
+ vm.succeed("dmesg | tail -n 50")
76
+ vm.succeed("journalctl -n 50")
77
+ raise Exception(f"nixos-anywhere command failed with exit code {result.returncode}")
78
+
79
+ # Test SSH connection to verify we're in NixOS kexec environment
80
+ check_cmd = [
81
+ "${ pkgs . openssh } /bin/ssh", "-v",
82
+ "-i", temp_key_path,
83
+ "-p", "2222",
84
+ "-o", "StrictHostKeyChecking=no",
85
+ "-o", "UserKnownHostsFile=/dev/null",
86
+ "root@localhost",
87
+ "cat /etc/os-release"
88
+ ]
89
+
90
+ test_result = subprocess.run(check_cmd, check=True, stdout=subprocess.PIPE, text=True)
91
+ assert "nixos" in test_result.stdout.lower(), f"Expected NixOS environment but got: {test_result.stdout}"
92
+
93
+ # After kexec we no longer have the machine driver,
94
+ # so we need to let the VM crash because the test driver backdoor gets confused by the terminal output.
95
+ vm.crash()
75
96
'' ;
76
- }
97
+ } ) . sandboxed
0 commit comments