1{
2 system ? builtins.currentSystem,
3 config ? { },
4 pkgs ? import ../.. { inherit system config; },
5 lib ? pkgs.lib,
6}:
7
8let
9
10 inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest;
11
12 mkOCITest =
13 backend:
14 makeTest {
15 name = "oci-containers-${backend}";
16
17 meta.maintainers = lib.teams.serokell.members ++ (with lib.maintainers; [ benley ]);
18
19 nodes = {
20 ${backend} =
21 { pkgs, ... }:
22 {
23 virtualisation.oci-containers = {
24 inherit backend;
25 containers.nginx = {
26 image = "nginx-container";
27 imageStream = pkgs.dockerTools.examples.nginxStream;
28 ports = [ "8181:80" ];
29 capabilities = {
30 CAP_AUDIT_READ = true;
31 CAP_AUDIT_WRITE = false;
32 };
33 privileged = false;
34 devices = [
35 "/dev/random:/dev/random"
36 ];
37 };
38 };
39
40 # Stop systemd from killing remaining processes if ExecStop script
41 # doesn't work, so that proper stopping can be tested.
42 systemd.services."${backend}-nginx".serviceConfig.KillSignal = "SIGCONT";
43 };
44 };
45
46 testScript = ''
47 import json
48
49 start_all()
50 ${backend}.wait_for_unit("${backend}-nginx.service")
51 ${backend}.wait_for_open_port(8181)
52 ${backend}.wait_until_succeeds("curl -f http://localhost:8181 | grep Hello")
53 output = json.loads(${backend}.succeed("${backend} inspect nginx --format json").strip())[0]
54 ${backend}.succeed("systemctl stop ${backend}-nginx.service", timeout=10)
55 assert output['HostConfig']['CapAdd'] == ["CAP_AUDIT_READ"]
56 assert output['HostConfig']['CapDrop'] == ${
57 if backend == "docker" then "[\"CAP_AUDIT_WRITE\"]" else "[]"
58 } # Rootless podman runs with no capabilities so it cannot drop them
59 assert output['HostConfig']['Privileged'] == False
60 assert output['HostConfig']['Devices'] == [{'PathOnHost': '/dev/random', 'PathInContainer': '/dev/random', 'CgroupPermissions': '${
61 if backend == "docker" then "rwm" else ""
62 }'}]
63 '';
64 };
65
66 podmanRootlessTests = lib.genAttrs [ "conmon" "healthy" ] (
67 type:
68 makeTest {
69 name = "oci-containers-podman-rootless-${type}";
70 meta.maintainers = lib.teams.flyingcircus.members;
71 nodes = {
72 podman =
73 { pkgs, ... }:
74 {
75 environment.systemPackages = [ pkgs.redis ];
76 users.groups.redis = { };
77 users.users.redis = {
78 isSystemUser = true;
79 group = "redis";
80 home = "/var/lib/redis";
81 linger = type == "healthy";
82 createHome = true;
83 uid = 2342;
84 subUidRanges = [
85 {
86 count = 65536;
87 startUid = 2147483646;
88 }
89 ];
90 subGidRanges = [
91 {
92 count = 65536;
93 startGid = 2147483647;
94 }
95 ];
96 };
97 virtualisation.oci-containers = {
98 backend = "podman";
99 containers.redis = {
100 image = "redis:latest";
101 imageFile = pkgs.dockerTools.examples.redis;
102 ports = [ "6379:6379" ];
103 podman = {
104 user = "redis";
105 sdnotify = type;
106 };
107 };
108 };
109 };
110 };
111
112 testScript = ''
113 start_all()
114 podman.wait_for_unit("podman-redis.service")
115 ${lib.optionalString (type != "healthy") ''
116 podman.wait_for_open_port(6379)
117 ''}
118 podman.wait_until_succeeds("set -eo pipefail; echo 'keys *' | redis-cli")
119 '';
120 }
121 );
122in
123{
124 docker = mkOCITest "docker";
125 podman = mkOCITest "podman";
126 podman-rootless-conmon = podmanRootlessTests.conmon;
127 podman-rootless-healthy = podmanRootlessTests.healthy;
128}