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