#!/usr/bin/env bats load helpers function setup() { setup_busybox } function teardown() { teardown_bundle } # This needs to be placed at the top of the bats file to work around # a shellcheck bug. See . test_host_pidns_kill() { requires cgroups_freezer update_config ' .linux.namespaces -= [{"type": "pid"}]' set_cgroups_path if [ $EUID -ne 0 ]; then requires rootless_cgroup # Can't mount real /proc when rootless + no pidns, # so change it to a bind-mounted one from the host. update_config ' .mounts |= map((select(.type == "proc") | .type = "none" | .source = "/proc" | .options = ["rbind", "nosuid", "nodev", "noexec"] ) // .)' fi runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox [ "$status" -eq 0 ] cgpath=$(get_cgroup_path "pids") init_pid=$(cat "$cgpath"/cgroup.procs) # Start a few more processes. for _ in 1 2 3 4 5; do __runc exec -d test_busybox sleep 1h done if [ -v KILL_INIT ]; then # Now kill the container's init process. Since the container do # not have own PID ns, its init is no special and the container # will still be up and running (except for rootless container # AND systemd cgroup driver AND systemd > v245, when systemd # kills the container; see "kill KILL [host pidns + init gone]" # below). kill -9 "$init_pid" wait_pids_gone 10 0.2 "$init_pid" fi # Get the list of all container processes. mapfile -t pids < <(cat "$cgpath"/cgroup.procs) echo "pids:" "${pids[@]}" # Sanity check -- make sure all processes exist. for p in "${pids[@]}"; do kill -0 "$p" done runc kill test_busybox KILL [ "$status" -eq 0 ] # Wait and check that all processes are gone. wait_pids_gone 10 0.2 "${pids[@]}" # Make sure the container is in stopped state. Note if KILL_INIT # is set, container was already stopped by killing its $init_pid # and so this check is NOP/redundant. testcontainer test_busybox stopped # Make sure cgroup.procs is empty. mapfile -t pids < <(cat "$cgpath"/cgroup.procs || true) if [ ${#pids[@]} -gt 0 ]; then echo "expected empty cgroup.procs, got:" "${pids[@]}" 1>&2 return 1 fi } @test "kill detached busybox" { runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox [ "$status" -eq 0 ] testcontainer test_busybox running runc kill test_busybox KILL [ "$status" -eq 0 ] wait_for_container 10 1 test_busybox stopped # Check that kill errors on a stopped container. runc kill test_busybox 0 [ "$status" -ne 0 ] [[ "$output" == *"container not running"* ]] # Check that -a (now obsoleted) makes kill return no error for a stopped container. runc kill -a test_busybox 0 [ "$status" -eq 0 ] runc delete test_busybox [ "$status" -eq 0 ] } # This is roughly the same as TestPIDHostInitProcessWait in libcontainer/integration. # The differences are: # # 1. Here we use separate processes to create and to kill a container, so the # processes inside a container are not children of "runc kill". # # 2. We hit different codepaths (nonChildProcess.signal rather than initProcess.signal). @test "kill KILL [host pidns]" { unset KILL_INIT test_host_pidns_kill } # Same as above plus: # # 3. Test runc kill on a container whose init process is gone. # # Issue 4047, case "runc kill". # See also: "runc delete --force [host pidns + init gone]" test in delete.bats. @test "kill KILL [host pidns + init gone]" { # Apparently, for rootless test, when using systemd cgroup manager, # newer versions of systemd clean up the container as soon as its init # process is gone. This is all fine and dandy, except it prevents us to # test this case, thus we skip the test. # # It is not entirely clear which systemd version got this feature: # v245 works fine, and v249 does not. if [ $EUID -ne 0 ] && [ -v RUNC_USE_SYSTEMD ] && [ "$(systemd_version)" -gt 245 ]; then skip "rootless+systemd conflicts with systemd > 245" fi KILL_INIT=1 test_host_pidns_kill unset KILL_INIT } # https://github.com/opencontainers/runc/issues/4394 (cgroup v1, rootless) @test "kill KILL [shared pidns]" { update_config '.process.args = ["sleep", "infinity"]' runc run -d --console-socket "$CONSOLE_SOCKET" target_ctr [ "$status" -eq 0 ] testcontainer target_ctr running target_pid="$(__runc state target_ctr | jq .pid)" update_config '.linux.namespaces |= map(if .type == "user" or .type == "pid" then (.path = "/proc/'"$target_pid"'/ns/" + .type) else . end) | del(.linux.uidMappings) | del(.linux.gidMappings)' runc run -d --console-socket "$CONSOLE_SOCKET" attached_ctr [ "$status" -eq 0 ] testcontainer attached_ctr running runc kill attached_ctr 9 [ "$status" -eq 0 ] runc delete --force attached_ctr [ "$status" -eq 0 ] runc delete --force target_ctr [ "$status" -eq 0 ] }