1{ pkgs, lib, ... }:
2{
3 name = "containers-imperative";
4 meta = {
5 maintainers = with lib.maintainers; [
6 aristid
7 aszlig
8 kampfschlaefer
9 ];
10 };
11
12 nodes.machine =
13 {
14 config,
15 pkgs,
16 lib,
17 ...
18 }:
19 {
20 imports = [ ../modules/installer/cd-dvd/channel.nix ];
21
22 boot.enableContainers = true;
23
24 # XXX: Sandbox setup fails while trying to hardlink files from the host's
25 # store file system into the prepared chroot directory.
26 nix.settings.sandbox = false;
27 nix.settings.substituters = [ ]; # don't try to access cache.nixos.org
28
29 virtualisation.memorySize = 2048;
30 virtualisation.writableStore = true;
31 # Make sure we always have all the required dependencies for creating a
32 # container available within the VM, because we don't have network access.
33 virtualisation.additionalPaths =
34 let
35 emptyContainer = import ../lib/eval-config.nix {
36 modules = lib.singleton {
37 nixpkgs.hostPlatform = { inherit (pkgs.stdenv.hostPlatform) system; };
38
39 containers.foo.config = { };
40 };
41
42 # The system is inherited from the host above.
43 # Set it to null, to remove the "legacy" entrypoint's non-hermetic default.
44 system = null;
45 };
46 in
47 with pkgs;
48 [
49 stdenv
50 stdenvNoCC
51 emptyContainer.config.containers.foo.path
52 libxslt
53 desktop-file-utils
54 texinfo
55 docbook5
56 libxml2
57 docbook_xsl_ns
58 xorg.lndir
59 documentation-highlighter
60 perlPackages.ConfigIniFiles
61 ];
62 };
63
64 testScript =
65 let
66 tmpfilesContainerConfig = pkgs.writeText "container-config-tmpfiles" ''
67 {
68 systemd.tmpfiles.rules = [ "d /foo - - - - -" ];
69 systemd.services.foo = {
70 serviceConfig.Type = "oneshot";
71 script = "ls -al /foo";
72 wantedBy = [ "multi-user.target" ];
73 };
74 }
75 '';
76 brokenCfg = pkgs.writeText "broken.nix" ''
77 {
78 assertions = [
79 { assertion = false;
80 message = "I never evaluate";
81 }
82 ];
83 }
84 '';
85 in
86 ''
87 with subtest("Make sure we have a NixOS tree (required by ‘nixos-container create’)"):
88 machine.succeed("PAGER=cat nix-env -qa -A nixos.hello >&2")
89
90 id1, id2 = None, None
91
92 with subtest("Create some containers imperatively"):
93 id1 = machine.succeed("nixos-container create foo --ensure-unique-name").rstrip()
94 machine.log(f"created container {id1}")
95
96 id2 = machine.succeed("nixos-container create foo --ensure-unique-name").rstrip()
97 machine.log(f"created container {id2}")
98
99 assert id1 != id2
100
101 with subtest(f"Put the root of {id2} into a bind mount"):
102 machine.succeed(
103 f"mv /var/lib/nixos-containers/{id2} /id2-bindmount",
104 f"mount --bind /id2-bindmount /var/lib/nixos-containers/{id1}",
105 )
106
107 ip1 = machine.succeed(f"nixos-container show-ip {id1}").rstrip()
108 ip2 = machine.succeed(f"nixos-container show-ip {id2}").rstrip()
109 assert ip1 != ip2
110
111 with subtest(
112 "Create a directory and a file we can later check if it still exists "
113 + "after destruction of the container"
114 ):
115 machine.succeed("mkdir /nested-bindmount")
116 machine.succeed("echo important data > /nested-bindmount/dummy")
117
118 with subtest(
119 "Create a directory with a dummy file and bind-mount it into both containers."
120 ):
121 for id in id1, id2:
122 important_path = f"/var/lib/nixos-containers/{id}/very/important/data"
123 machine.succeed(
124 f"mkdir -p {important_path}",
125 f"mount --bind /nested-bindmount {important_path}",
126 )
127
128 with subtest("Start one of them"):
129 machine.succeed(f"nixos-container start {id1}")
130
131 with subtest("Execute commands via the root shell"):
132 assert "Linux" in machine.succeed(f"nixos-container run {id1} -- uname")
133
134 with subtest("Execute a nix command via the root shell. (regression test for #40355)"):
135 machine.succeed(
136 f"nixos-container run {id1} -- nix-instantiate -E "
137 + '\'derivation { name = "empty"; builder = "false"; system = "false"; }\' '
138 )
139
140 with subtest("Stop and start (regression test for #4989)"):
141 machine.succeed(f"nixos-container stop {id1}")
142 machine.succeed(f"nixos-container start {id1}")
143
144 # clear serial backlog for next tests
145 machine.succeed("logger eat console backlog 3ea46eb2-7f82-4f70-b810-3f00e3dd4c4d")
146 machine.wait_for_console_text(
147 "eat console backlog 3ea46eb2-7f82-4f70-b810-3f00e3dd4c4d"
148 )
149
150 with subtest("Stop a container early"):
151 machine.succeed(f"nixos-container stop {id1}")
152 machine.succeed(f"nixos-container start {id1} >&2 &")
153 machine.wait_for_console_text("Stage 2")
154 machine.succeed(f"nixos-container stop {id1}")
155 machine.wait_for_console_text(f"Container {id1} exited successfully")
156 machine.succeed(f"nixos-container start {id1}")
157
158 with subtest("Stop a container without machined (regression test for #109695)"):
159 machine.systemctl("stop systemd-machined")
160 machine.succeed(f"nixos-container stop {id1}")
161 machine.wait_for_console_text(f"Container {id1} has been shut down")
162 machine.succeed(f"nixos-container start {id1}")
163
164 with subtest("tmpfiles are present"):
165 machine.log("creating container tmpfiles")
166 machine.succeed(
167 "nixos-container create tmpfiles --config-file ${tmpfilesContainerConfig}"
168 )
169 machine.log("created, starting…")
170 machine.succeed("nixos-container start tmpfiles")
171 machine.log("done starting, investigating…")
172 machine.succeed(
173 "echo $(nixos-container run tmpfiles -- systemctl is-active foo.service) | grep -q active;"
174 )
175 machine.succeed("nixos-container destroy tmpfiles")
176
177 with subtest("Execute commands via the root shell"):
178 assert "Linux" in machine.succeed(f"nixos-container run {id1} -- uname")
179
180 with subtest("Destroy the containers"):
181 for id in id1, id2:
182 machine.succeed(f"nixos-container destroy {id}")
183
184 with subtest("Check whether destruction of any container has killed important data"):
185 machine.succeed("grep -qF 'important data' /nested-bindmount/dummy")
186
187 with subtest("Ensure that the container path is gone"):
188 print(machine.succeed("ls -lsa /var/lib/nixos-containers"))
189 machine.succeed(f"test ! -e /var/lib/nixos-containers/{id1}")
190
191 with subtest("Ensure that a failed container creation doesn'leave any state"):
192 machine.fail(
193 "nixos-container create b0rk --config-file ${brokenCfg}"
194 )
195 machine.succeed("test ! -e /var/lib/nixos-containers/b0rk")
196 '';
197}