Skip to content

Commit a9adfc6

Browse files
committed
nixos/test-driver: allow assigning other vsock number ranges
I'm a little annoyed at myself that I only realized this _after_ #392030 got merged. But I realized that if something else is using AF_VSOCK or you simply have another interactive test running (e.g. by another user on a larger builder), starting up VMs in the driver fails with qemu-system-x86_64: -device vhost-vsock-pci,guest-cid=3: vhost-vsock: unable to set guest cid: Address already in use Multi-user setups are broken anyways because you usually don't have permissions to remove the VM state from another user and thus starting the driver fails with PermissionError: [Errno 13] Permission denied: PosixPath('/tmp/vm-state-machine') but this is something you can work around at least. I was considering to generate random offsets, but that's not feasible given we need to know the numbers at eval time to inject them into the QEMU args. Also, while we could do this via the test-driver, we should also probe if the vsock numbers are unused making the code even more complex for a use-case I consider rather uncommon. Hence the solution is to do sshBackdoor.vsockOffset = 23542; when encountering conflicts.
1 parent 509c009 commit a9adfc6

File tree

6 files changed

+68
-9
lines changed

6 files changed

+68
-9
lines changed

nixos/doc/manual/development/running-nixos-tests-interactively.section.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,33 @@ $ ssh vsock/3 -o User=root
8787

8888
The socket numbers correspond to the node number of the test VM, but start
8989
at three instead of one because that's the lowest possible
90-
vsock number.
90+
vsock number. The exact SSH commands are also printed out when starting
91+
`nixos-test-driver`.
9192

9293
On non-NixOS systems you'll probably need to enable
9394
the SSH config from {manpage}`systemd-ssh-proxy(1)` yourself.
9495

96+
If starting VM fails with an error like
97+
98+
```
99+
qemu-system-x86_64: -device vhost-vsock-pci,guest-cid=3: vhost-vsock: unable to set guest cid: Address already in use
100+
```
101+
102+
it means that the vsock numbers for the VMs are already in use. This can happen
103+
if another interactive test with SSH backdoor enabled is running on the machine.
104+
105+
In that case, you need to assign another range of vsock numbers. You can pick another
106+
offset with
107+
108+
```nix
109+
{
110+
sshBackdoor = {
111+
enable = true;
112+
vsockOffset = 23542;
113+
};
114+
}
115+
```
116+
95117
## Port forwarding to NixOS test VMs {#sec-nixos-test-port-forwarding}
96118

97119
If your test has only a single VM, you may use e.g.

nixos/doc/manual/redirects.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,6 +1826,9 @@
18261826
"test-opt-sshBackdoor.enable": [
18271827
"index.html#test-opt-sshBackdoor.enable"
18281828
],
1829+
"test-opt-sshBackdoor.vsockOffset": [
1830+
"index.html#test-opt-sshBackdoor.vsockOffset"
1831+
],
18291832
"test-opt-defaults": [
18301833
"index.html#test-opt-defaults"
18311834
],

nixos/lib/test-driver/src/test_driver/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def main() -> None:
112112
arg_parser.add_argument(
113113
"--dump-vsocks",
114114
help="indicates that the interactive SSH backdoor is active and dumps information about it on start",
115-
action="store_true",
115+
type=int,
116116
)
117117

118118
args = arg_parser.parse_args()
@@ -141,8 +141,8 @@ def main() -> None:
141141
if args.interactive:
142142
history_dir = os.getcwd()
143143
history_path = os.path.join(history_dir, ".nixos-test-history")
144-
if args.dump_vsocks:
145-
driver.dump_machine_ssh()
144+
if offset := args.dump_vsocks:
145+
driver.dump_machine_ssh(offset)
146146
ptpython.ipython.embed(
147147
user_ns=driver.test_symbols(),
148148
history_filename=history_path,

nixos/lib/test-driver/src/test_driver/driver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,14 @@ def subtest(name: str) -> Iterator[None]:
178178
)
179179
return {**general_symbols, **machine_symbols, **vlan_symbols}
180180

181-
def dump_machine_ssh(self) -> None:
181+
def dump_machine_ssh(self, offset: int) -> None:
182182
print("SSH backdoor enabled, the machines can be accessed like this:")
183183
print(
184184
f"{Style.BRIGHT}Note:{Style.RESET_ALL} this requires {Style.BRIGHT}systemd-ssh-proxy(1){Style.RESET_ALL} to be enabled (default on NixOS 25.05 and newer)."
185185
)
186186
names = [machine.name for machine in self.machines]
187187
longest_name = len(max(names, key=len))
188-
for num, name in enumerate(names, start=3):
188+
for num, name in enumerate(names, start=offset + 1):
189189
spaces = " " * (longest_name - len(name) + 2)
190190
print(
191191
f" {name}:{spaces}{Style.BRIGHT}ssh -o User=root vsock/{num}{Style.RESET_ALL}"

nixos/lib/testing/nodes.nix

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,21 @@ in
8484
type = types.bool;
8585
description = "Whether to turn on the VSOCK-based access to all VMs. This provides an unauthenticated access intended for debugging.";
8686
};
87+
vsockOffset = mkOption {
88+
default = 2;
89+
type = types.ints.between 2 4294967296;
90+
description = ''
91+
By default this assigns vsock numbers starting at 3 to the nodes.
92+
On e.g. large builders used by multiple people, this would cause conflicts
93+
between multiple users doing interactive debugging.
94+
95+
This option allows to assign an offset to each vsock number to
96+
resolve this.
97+
98+
This is a 32bit number. The lowest possible vsock number is `3`
99+
(i.e. with the lowest node number being `1`, this is 2+1).
100+
'';
101+
};
87102
};
88103

89104
node.type = mkOption {
@@ -182,7 +197,7 @@ in
182197
passthru.nodes = config.nodesCompat;
183198

184199
extraDriverArgs = mkIf config.sshBackdoor.enable [
185-
"--dump-vsocks"
200+
"--dump-vsocks=${toString config.sshBackdoor.vsockOffset}"
186201
];
187202

188203
defaults = mkMerge [
@@ -191,7 +206,9 @@ in
191206
imports = [ ../../modules/misc/nixpkgs/read-only.nix ];
192207
})
193208
(mkIf config.sshBackdoor.enable {
194-
testing.sshBackdoor.enable = true;
209+
testing.sshBackdoor = {
210+
inherit (config.sshBackdoor) enable vsockOffset;
211+
};
195212
})
196213
];
197214

nixos/modules/testing/test-instrumentation.nix

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,21 @@ in
8989

9090
sshBackdoor = {
9191
enable = mkEnableOption "vsock-based ssh backdoor for the VM";
92+
vsockOffset = mkOption {
93+
default = 2;
94+
type = types.ints.between 2 4294967296;
95+
description = ''
96+
By default this assigns vsock numbers starting at 3 to the nodes.
97+
On e.g. large builders used by multiple people, this would cause conflicts
98+
between multiple users doing interactive debugging.
99+
100+
This option allows to assign an offset to each vsock number to
101+
resolve this.
102+
103+
This is a 32bit number. The lowest possible vsock number is `3`
104+
(i.e. with the lowest node number being `1`, this is 2+1).
105+
'';
106+
};
92107
};
93108

94109
};
@@ -193,7 +208,9 @@ in
193208
package = lib.mkDefault pkgs.qemu_test;
194209

195210
options = mkIf config.testing.sshBackdoor.enable [
196-
"-device vhost-vsock-pci,guest-cid=${toString (config.virtualisation.test.nodeNumber + 2)}"
211+
"-device vhost-vsock-pci,guest-cid=${
212+
toString (config.virtualisation.test.nodeNumber + config.testing.sshBackdoor.vsockOffset)
213+
}"
197214
];
198215
};
199216
};

0 commit comments

Comments
 (0)