1testModuleArgs@{
2 config,
3 lib,
4 hostPkgs,
5 nodes,
6 ...
7}:
8
9let
10 inherit (lib)
11 literalExpression
12 literalMD
13 mapAttrs
14 mkDefault
15 mkIf
16 mkMerge
17 mkOption
18 mkForce
19 optional
20 optionalAttrs
21 types
22 ;
23
24 inherit (hostPkgs.stdenv) hostPlatform;
25
26 guestSystem =
27 if hostPlatform.isLinux then
28 hostPlatform.system
29 else
30 let
31 hostToGuest = {
32 "x86_64-darwin" = "x86_64-linux";
33 "aarch64-darwin" = "aarch64-linux";
34 };
35
36 supportedHosts = lib.concatStringsSep ", " (lib.attrNames hostToGuest);
37
38 message = "NixOS Test: don't know which VM guest system to pair with VM host system: ${hostPlatform.system}. Perhaps you intended to run the tests on a Linux host, or one of the following systems that may run NixOS tests: ${supportedHosts}";
39 in
40 hostToGuest.${hostPlatform.system} or (throw message);
41
42 baseOS = import ../eval-config.nix {
43 inherit lib;
44 system = null; # use modularly defined system
45 inherit (config.node) specialArgs;
46 modules = [ config.defaults ];
47 baseModules = (import ../../modules/module-list.nix) ++ [
48 ./nixos-test-base.nix
49 {
50 key = "nodes";
51 _module.args.nodes = config.nodesCompat;
52 }
53 (
54 { config, ... }:
55 {
56 virtualisation.qemu.package = testModuleArgs.config.qemu.package;
57 virtualisation.host.pkgs = hostPkgs;
58 }
59 )
60 (
61 { options, ... }:
62 {
63 key = "nodes.nix-pkgs";
64 config = optionalAttrs (!config.node.pkgsReadOnly) (
65 mkIf (!options.nixpkgs.pkgs.isDefined) {
66 # TODO: switch to nixpkgs.hostPlatform and make sure containers-imperative test still evaluates.
67 nixpkgs.system = guestSystem;
68 }
69 );
70 }
71 )
72 testModuleArgs.config.extraBaseModules
73 ];
74 };
75
76in
77
78{
79
80 options = {
81 sshBackdoor = {
82 enable = mkOption {
83 default = false;
84 type = types.bool;
85 description = "Whether to turn on the VSOCK-based access to all VMs. This provides an unauthenticated access intended for debugging.";
86 };
87 vsockOffset = mkOption {
88 default = 2;
89 type = types.ints.between 2 4294967296;
90 description = ''
91 This field is only relevant when multiple users run the (interactive)
92 driver outside the sandbox and with the SSH backdoor activated.
93 The typical symptom for this being a problem are error messages like this:
94 `vhost-vsock: unable to set guest cid: Address already in use`
95
96 This option allows to assign an offset to each vsock number to
97 resolve this.
98
99 This is a 32bit number. The lowest possible vsock number is `3`
100 (i.e. with the lowest node number being `1`, this is 2+1).
101 '';
102 };
103 };
104
105 node.type = mkOption {
106 type = types.raw;
107 default = baseOS.type;
108 internal = true;
109 };
110
111 nodes = mkOption {
112 type = types.lazyAttrsOf config.node.type;
113 visible = "shallow";
114 description = ''
115 An attribute set of NixOS configuration modules.
116
117 The configurations are augmented by the [`defaults`](#test-opt-defaults) option.
118
119 They are assigned network addresses according to the `nixos/lib/testing/network.nix` module.
120
121 A few special options are available, that aren't in a plain NixOS configuration. See [Configuring the nodes](#sec-nixos-test-nodes)
122 '';
123 };
124
125 defaults = mkOption {
126 description = ''
127 NixOS configuration that is applied to all [{option}`nodes`](#test-opt-nodes).
128 '';
129 type = types.deferredModule;
130 default = { };
131 };
132
133 extraBaseModules = mkOption {
134 description = ''
135 NixOS configuration that, like [{option}`defaults`](#test-opt-defaults), is applied to all [{option}`nodes`](#test-opt-nodes) and can not be undone with [`specialisation.<name>.inheritParentConfig`](https://search.nixos.org/options?show=specialisation.%3Cname%3E.inheritParentConfig&from=0&size=50&sort=relevance&type=packages&query=specialisation).
136 '';
137 type = types.deferredModule;
138 default = { };
139 };
140
141 node.pkgs = mkOption {
142 description = ''
143 The Nixpkgs to use for the nodes.
144
145 Setting this will make the `nixpkgs.*` options read-only, to avoid mistakenly testing with a Nixpkgs configuration that diverges from regular use.
146 '';
147 type = types.nullOr types.pkgs;
148 default = null;
149 defaultText = literalMD ''
150 `null`, so construct `pkgs` according to the `nixpkgs.*` options as usual.
151 '';
152 };
153
154 node.pkgsReadOnly = mkOption {
155 description = ''
156 Whether to make the `nixpkgs.*` options read-only. This is only relevant when [`node.pkgs`](#test-opt-node.pkgs) is set.
157
158 Set this to `false` when any of the [`nodes`](#test-opt-nodes) needs to configure any of the `nixpkgs.*` options. This will slow down evaluation of your test a bit.
159 '';
160 type = types.bool;
161 default = config.node.pkgs != null;
162 defaultText = literalExpression ''node.pkgs != null'';
163 };
164
165 node.specialArgs = mkOption {
166 type = types.lazyAttrsOf types.raw;
167 default = { };
168 description = ''
169 An attribute set of arbitrary values that will be made available as module arguments during the resolution of module `imports`.
170
171 Note that it is not possible to override these from within the NixOS configurations. If you argument is not relevant to `imports`, consider setting {option}`defaults._module.args.<name>` instead.
172 '';
173 };
174
175 nodesCompat = mkOption {
176 internal = true;
177 description = ''
178 Basically `_module.args.nodes`, but with backcompat and warnings added.
179
180 This will go away.
181 '';
182 };
183 };
184
185 config = {
186 _module.args.nodes = config.nodesCompat;
187 nodesCompat = mapAttrs (
188 name: config:
189 config
190 // {
191 config =
192 lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2211)
193 "Module argument `nodes.${name}.config` is deprecated. Use `nodes.${name}` instead."
194 config;
195 }
196 ) config.nodes;
197
198 passthru.nodes = config.nodesCompat;
199
200 extraDriverArgs = mkIf config.sshBackdoor.enable [
201 "--dump-vsocks=${toString config.sshBackdoor.vsockOffset}"
202 ];
203
204 defaults = mkMerge [
205 (mkIf config.node.pkgsReadOnly {
206 nixpkgs.pkgs = config.node.pkgs;
207 imports = [ ../../modules/misc/nixpkgs/read-only.nix ];
208 })
209 (mkIf config.sshBackdoor.enable (
210 let
211 inherit (config.sshBackdoor) vsockOffset;
212 in
213 { config, ... }:
214 {
215 services.openssh = {
216 enable = true;
217 settings = {
218 PermitRootLogin = "yes";
219 PermitEmptyPasswords = "yes";
220 };
221 };
222
223 security.pam.services.sshd = {
224 allowNullPassword = true;
225 };
226
227 virtualisation.qemu.options = [
228 "-device vhost-vsock-pci,guest-cid=${
229 toString (config.virtualisation.test.nodeNumber + vsockOffset)
230 }"
231 ];
232 }
233 ))
234 ];
235
236 };
237}