]>
git.ipfire.org Git - thirdparty/systemd.git/blob - test/units/testsuite-13.nspawn-oci.sh
2 # SPDX-License-Identifier: LGPL-2.1-or-later
3 # shellcheck disable=SC2016
7 # shellcheck source=test/units/util.sh
8 .
"$(dirname "$0")"/util.sh
10 export SYSTEMD_LOG_LEVEL
=debug
11 export SYSTEMD_LOG_TARGET
=journal
13 # shellcheck disable=SC2317
17 mountpoint
-q /var
/lib
/machines
&& umount
/var
/lib
/machines
18 [[ -n "${DEV:-}" ]] && rm -f "$DEV"
19 [[ -n "${NETNS:-}" ]] && umount
"$NETNS" && rm -f "$NETNS"
20 [[ -n "${TMPDIR:-}" ]] && rm -fr "$TMPDIR"
21 rm -f /run
/systemd
/nspawn
/*.nspawn
26 # Mount tmpfs over /var/lib/machines to not pollute the image
27 mkdir
-p /var
/lib
/machines
28 mount
-t tmpfs tmpfs
/var
/lib
/machines
30 # Setup a couple of dirs/devices for the OCI containers
31 DEV
="$(mktemp -u /dev/oci-dev-XXX)"
32 mknod
-m 666 "$DEV" b
42 42
33 NETNS
="$(mktemp /var/tmp/netns.XXX)"
34 mount
--bind /proc
/self
/ns
/net
"$NETNS"
37 OCI
="$(mktemp -d /var/lib/machines/testsuite-13.oci-bundle.XXX)"
38 create_dummy_container
"$OCI/rootfs"
39 mkdir
-p "$OCI/rootfs/opt/var"
40 mkdir
-p "$OCI/rootfs/opt/readonly"
42 # Let's start with a simple config
43 cat >"$OCI/config.json" <<EOF
45 "ociVersion" : "1.0.0",
51 "destination" : "/root",
58 systemd-nspawn
--oci-bundle="$OCI" bash
-xec 'mountpoint /root'
60 # And now for something a bit more involved
62 # - the hooks are parsed & processed, but never executed
63 # - set sysctl's are parsed but never used?
64 # - same goes for arg_sysctl in nspawn.c
65 cat >"$OCI/config.json" <<EOF
67 "ociVersion" : "1.0.0",
68 "hostname" : "my-oci-container",
75 "destination" : "/root",
80 "destination" : "/var",
83 "options" : ["rbind", "rw"]
95 "additionalGids" : [5, 6]
98 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
107 "noNewPrivileges" : true,
113 "CAP_NET_BIND_SERVICE"
118 "CAP_NET_BIND_SERVICE"
123 "CAP_NET_BIND_SERVICE"
130 "CAP_NET_BIND_SERVICE"
135 "type" : "RLIMIT_NOFILE",
140 "type" : "RLIMIT_RTPRIO",
179 "path" : "/dev/zero",
210 "reservation" : 33554432,
228 "throttleReadBpsDevice" : [
235 "throttleWriteBpsDevice" : [
242 "throttleReadIOPSDevice" : [
249 "throttleWriteIOPSDevice" : [
262 "kernel.domainname" : "foo.bar",
263 "vm.swappiness" : "60"
266 "defaultAction" : "SCMP_ACT_ALLOW",
277 "action" : "SCMP_ACT_ERRNO",
288 "op" : "SCMP_CMP_MASKED_EQ"
294 "rootfsPropagation" : "shared",
310 "echo \$PRESTART_FOO >/prestart"
313 "PRESTART_FOO=prestart_bar",
319 "path" : "/bin/touch",
350 # Create a simple "entrypoint" script that validates that the container
351 # is created correctly according to the OCI config
352 cat >"$OCI/rootfs/entrypoint.sh" <<EOF
361 [[ "\$PWD" == /root ]]
365 [[ "\$(ulimit -S -n)" -eq 1024 ]]
366 [[ "\$(ulimit -H -n)" -eq 1024 ]]
367 [[ "\$(ulimit -S -r)" -eq 5 ]]
368 [[ "\$(ulimit -H -r)" -eq 10 ]]
369 [[ "\$(hostname)" == my-oci-container ]]
374 [[ "\$(stat -c '%t:%T' "$DEV")" == 4:2 ]]
376 # Linux - maskedPaths
378 cat /proc/kcore && exit 1
379 test ! -e /root/nonexistent
381 # Linux - readonlyPaths
382 touch /opt/readonly/foo && exit 1
386 timeout
30 systemd-nspawn
--oci-bundle="$OCI"
388 # Test a couple of invalid configs
392 '"process" : { "foo" : [ ] }'
394 '"mounts" : [ { "destination" : "foo", "type" : "tmpfs", "source" : "tmpfs" } ]'
396 '"process" : { "rlimits" : [ { "type" : "RLIMIT_FOO", "soft" : 0, "hard" : 0 } ] }'
397 # rlimit without RLIMIT_ prefix
398 '"process" : { "rlimits" : [ { "type" : "CORE", "soft" : 0, "hard" : 0 } ] }'
399 # Invalid env assignment
400 '"process" : { "env" : [ "foo" ] }'
401 '"process" : { "env" : [ "foo=bar", 1 ] }'
402 # Invalid process args
403 '"process" : { "args" : [ ] }'
404 '"process" : { "args" : [ "" ] }'
405 '"process" : { "args" : [ "foo", 1 ] }'
406 # Invalid capabilities
407 '"process" : { "capabilities" : { "bounding" : [ 1 ] } }'
408 '"process" : { "capabilities" : { "bounding" : [ "FOO_BAR" ] } }'
409 # Unsupported option (without JSON_PERMISSIVE)
410 '"linux" : { "resources" : { "cpu" : { "realtimeRuntime" : 1 } } }'
412 '"linux" : { "namespaces" : [ { "type" : "foo" } ] }'
413 # Namespace path for a non-network namespace
414 '"linux" : { "namespaces" : [ { "type" : "user", "path" : "/foo/bar" } ] }'
415 # Duplicate namespace
416 '"linux" : { "namespaces" : [ { "type" : "ipc" }, { "type" : "ipc" } ] }'
417 # Invalid device type
418 '"linux" : { "devices" : [ { "type" : "foo", "path" : "/dev/foo" } ] }'
419 # Invalid cgroups path
420 '"linux" : { "cgroupsPath" : "/foo/bar/baz" }'
421 '"linux" : { "cgroupsPath" : "foo/bar/baz" }'
422 # Invalid sysctl assignments
423 '"linux" : { "sysctl" : { "vm.swappiness" : 60 } }'
424 '"linux" : { "sysctl" : { "foo..bar" : "baz" } }'
425 # Invalid seccomp assignments
426 '"linux" : { "seccomp" : { } }'
427 '"linux" : { "seccomp" : { "defaultAction" : 1 } }'
428 '"linux" : { "seccomp" : { "defaultAction" : "foo" } }'
429 '"linux" : { "seccomp" : { "defaultAction" : "SCMP_ACT_ALLOW", "syscalls" : [ { "action" : "SCMP_ACT_ERRNO", "names" : [ ] } ] } }'
430 # Invalid masked paths
431 '"linux" : { "maskedPaths" : [ "/foo", 1 ] }'
432 '"linux" : { "maskedPaths" : [ "/foo", "bar" ] }'
433 # Invalid read-only paths
434 '"linux" : { "readonlyPaths" : [ "/foo", 1 ] }'
435 '"linux" : { "readonlyPaths" : [ "/foo", "bar" ] }'
437 '"hooks" : { "prestart" : [ { "path" : "/bin/sh", "timeout" : 0 } ] }'
438 # Invalid annotations
439 '"annotations" : { "" : "bar" }'
440 '"annotations" : { "foo" : 1 }'
443 for snippet
in "${INVALID_SNIPPETS[@]}"; do
444 : "Snippet: $snippet"
445 cat >"$OCI/config.json" <<EOF
447 "ociVersion" : "1.0.0",
454 (! systemd-nspawn
--oci-bundle="$OCI" sh
-c 'echo hello')
457 # Invalid OCI bundle version
458 cat >"$OCI/config.json" <<EOF
460 "ociVersion" : "6.6.6",
466 (! systemd-nspawn
--oci-bundle="$OCI" sh
-c 'echo hello')