about summary refs log tree commit diff
path: root/nixos/tests/containers-imperative.nix
blob: 3007efaf88710928b6be9381034aac6df920f072 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import ./make-test-python.nix ({ pkgs, lib, ... }: {
  name = "containers-imperative";
  meta = {
    maintainers = with lib.maintainers; [ aristid aszlig eelco kampfschlaefer ];
  };

  nodes.machine =
    { config, pkgs, lib, ... }:
    { imports = [ ../modules/installer/cd-dvd/channel.nix ];

      # XXX: Sandbox setup fails while trying to hardlink files from the host's
      #      store file system into the prepared chroot directory.
      nix.settings.sandbox = false;
      nix.settings.substituters = []; # don't try to access cache.nixos.org

      virtualisation.writableStore = true;
      # Make sure we always have all the required dependencies for creating a
      # container available within the VM, because we don't have network access.
      virtualisation.additionalPaths = let
        emptyContainer = import ../lib/eval-config.nix {
          modules = lib.singleton {
            nixpkgs = { inherit (config.nixpkgs) localSystem; };

            containers.foo.config = {
              system.stateVersion = "18.03";
            };
          };
        };
      in with pkgs; [
        stdenv stdenvNoCC emptyContainer.config.containers.foo.path
        libxslt desktop-file-utils texinfo docbook5 libxml2
        docbook_xsl_ns xorg.lndir documentation-highlighter
      ];
    };

  testScript = let
      tmpfilesContainerConfig = pkgs.writeText "container-config-tmpfiles" ''
        {
          systemd.tmpfiles.rules = [ "d /foo - - - - -" ];
          systemd.services.foo = {
            serviceConfig.Type = "oneshot";
            script = "ls -al /foo";
            wantedBy = [ "multi-user.target" ];
          };
        }
      '';
      brokenCfg = pkgs.writeText "broken.nix" ''
        {
          assertions = [
            { assertion = false;
              message = "I never evaluate";
            }
          ];
        }
      '';
    in ''
      with subtest("Make sure we have a NixOS tree (required by ‘nixos-container create’)"):
          machine.succeed("PAGER=cat nix-env -qa -A nixos.hello >&2")

      id1, id2 = None, None

      with subtest("Create some containers imperatively"):
          id1 = machine.succeed("nixos-container create foo --ensure-unique-name").rstrip()
          machine.log(f"created container {id1}")

          id2 = machine.succeed("nixos-container create foo --ensure-unique-name").rstrip()
          machine.log(f"created container {id2}")

          assert id1 != id2

      with subtest(f"Put the root of {id2} into a bind mount"):
          machine.succeed(
              f"mv /var/lib/nixos-containers/{id2} /id2-bindmount",
              f"mount --bind /id2-bindmount /var/lib/nixos-containers/{id1}",
          )

          ip1 = machine.succeed(f"nixos-container show-ip {id1}").rstrip()
          ip2 = machine.succeed(f"nixos-container show-ip {id2}").rstrip()
          assert ip1 != ip2

      with subtest(
          "Create a directory and a file we can later check if it still exists "
          + "after destruction of the container"
      ):
          machine.succeed("mkdir /nested-bindmount")
          machine.succeed("echo important data > /nested-bindmount/dummy")

      with subtest(
          "Create a directory with a dummy file and bind-mount it into both containers."
      ):
          for id in id1, id2:
              important_path = f"/var/lib/nixos-containers/{id}/very/important/data"
              machine.succeed(
                  f"mkdir -p {important_path}",
                  f"mount --bind /nested-bindmount {important_path}",
              )

      with subtest("Start one of them"):
          machine.succeed(f"nixos-container start {id1}")

      with subtest("Execute commands via the root shell"):
          assert "Linux" in machine.succeed(f"nixos-container run {id1} -- uname")

      with subtest("Execute a nix command via the root shell. (regression test for #40355)"):
          machine.succeed(
              f"nixos-container run {id1} -- nix-instantiate -E "
              + '\'derivation { name = "empty"; builder = "false"; system = "false"; }\' '
          )

      with subtest("Stop and start (regression test for #4989)"):
          machine.succeed(f"nixos-container stop {id1}")
          machine.succeed(f"nixos-container start {id1}")

      # clear serial backlog for next tests
      machine.succeed("logger eat console backlog 3ea46eb2-7f82-4f70-b810-3f00e3dd4c4d")
      machine.wait_for_console_text(
          "eat console backlog 3ea46eb2-7f82-4f70-b810-3f00e3dd4c4d"
      )

      with subtest("Stop a container early"):
          machine.succeed(f"nixos-container stop {id1}")
          machine.succeed(f"nixos-container start {id1} >&2 &")
          machine.wait_for_console_text("Stage 2")
          machine.succeed(f"nixos-container stop {id1}")
          machine.wait_for_console_text(f"Container {id1} exited successfully")
          machine.succeed(f"nixos-container start {id1}")

      with subtest("Stop a container without machined (regression test for #109695)"):
          machine.systemctl("stop systemd-machined")
          machine.succeed(f"nixos-container stop {id1}")
          machine.wait_for_console_text(f"Container {id1} has been shut down")
          machine.succeed(f"nixos-container start {id1}")

      with subtest("tmpfiles are present"):
          machine.log("creating container tmpfiles")
          machine.succeed(
              "nixos-container create tmpfiles --config-file ${tmpfilesContainerConfig}"
          )
          machine.log("created, starting…")
          machine.succeed("nixos-container start tmpfiles")
          machine.log("done starting, investigating…")
          machine.succeed(
              "echo $(nixos-container run tmpfiles -- systemctl is-active foo.service) | grep -q active;"
          )
          machine.succeed("nixos-container destroy tmpfiles")

      with subtest("Execute commands via the root shell"):
          assert "Linux" in machine.succeed(f"nixos-container run {id1} -- uname")

      with subtest("Destroy the containers"):
          for id in id1, id2:
              machine.succeed(f"nixos-container destroy {id}")

      with subtest("Check whether destruction of any container has killed important data"):
          machine.succeed("grep -qF 'important data' /nested-bindmount/dummy")

      with subtest("Ensure that the container path is gone"):
          print(machine.succeed("ls -lsa /var/lib/nixos-containers"))
          machine.succeed(f"test ! -e /var/lib/nixos-containers/{id1}")

      with subtest("Ensure that a failed container creation doesn'leave any state"):
          machine.fail(
              "nixos-container create b0rk --config-file ${brokenCfg}"
          )
          machine.succeed("test ! -e /var/lib/nixos-containers/b0rk")
    '';
})