mirror of
https://github.com/opencontainers/runc.git
synced 2025-09-26 19:41:35 +08:00

The main benefit here is when we are using a systemd cgroup driver, we actually ask systemd to add a PID, rather than doing it ourselves. This way, we can add rootless exec PID to a cgroup. This requires newer opencontainers/cgroups and coreos/go-systemd. Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
369 lines
10 KiB
Bash
369 lines
10 KiB
Bash
#!/usr/bin/env bats
|
|
|
|
load helpers
|
|
|
|
function setup() {
|
|
setup_busybox
|
|
}
|
|
|
|
function teardown() {
|
|
teardown_bundle
|
|
}
|
|
|
|
@test "runc exec" {
|
|
# run busybox detached
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
[ "$status" -eq 0 ]
|
|
|
|
runc exec test_busybox echo Hello from exec
|
|
[ "$status" -eq 0 ]
|
|
echo text echoed = "'""${output}""'"
|
|
[[ "${output}" == *"Hello from exec"* ]]
|
|
}
|
|
|
|
@test "runc exec [exit codes]" {
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
[ "$status" -eq 0 ]
|
|
|
|
runc exec test_busybox false
|
|
[ "$status" -eq 1 ]
|
|
|
|
runc exec test_busybox sh -c "exit 42"
|
|
[ "$status" -eq 42 ]
|
|
|
|
runc exec --pid-file /non-existent/directory test_busybox true
|
|
[ "$status" -eq 255 ]
|
|
|
|
runc exec test_busybox no-such-binary
|
|
[ "$status" -eq 255 ]
|
|
|
|
runc exec no_such_container true
|
|
[ "$status" -eq 255 ]
|
|
}
|
|
|
|
@test "runc exec --pid-file" {
|
|
# run busybox detached
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
[ "$status" -eq 0 ]
|
|
|
|
runc exec --pid-file pid.txt test_busybox echo Hello from exec
|
|
[ "$status" -eq 0 ]
|
|
echo text echoed = "'""${output}""'"
|
|
[[ "${output}" == *"Hello from exec"* ]]
|
|
|
|
# check pid.txt was generated
|
|
[ -e pid.txt ]
|
|
|
|
output=$(cat pid.txt)
|
|
[[ "$output" =~ [0-9]+ ]]
|
|
[[ "$output" != $(__runc state test_busybox | jq '.pid') ]]
|
|
}
|
|
|
|
@test "runc exec --pid-file with new CWD" {
|
|
bundle="$(pwd)"
|
|
# create pid_file directory as the CWD
|
|
mkdir pid_file
|
|
cd pid_file
|
|
|
|
# run busybox detached
|
|
runc run -d -b "$bundle" --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
[ "$status" -eq 0 ]
|
|
|
|
runc exec --pid-file pid.txt test_busybox echo Hello from exec
|
|
[ "$status" -eq 0 ]
|
|
echo text echoed = "'""${output}""'"
|
|
[[ "${output}" == *"Hello from exec"* ]]
|
|
|
|
# check pid.txt was generated
|
|
[ -e pid.txt ]
|
|
|
|
output=$(cat pid.txt)
|
|
[[ "$output" =~ [0-9]+ ]]
|
|
[[ "$output" != $(__runc state test_busybox | jq '.pid') ]]
|
|
}
|
|
|
|
@test "runc exec ls -la" {
|
|
# run busybox detached
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
[ "$status" -eq 0 ]
|
|
|
|
runc exec test_busybox ls -la
|
|
[ "$status" -eq 0 ]
|
|
[[ ${lines[0]} == *"total"* ]]
|
|
[[ ${lines[1]} == *"."* ]]
|
|
[[ ${lines[2]} == *".."* ]]
|
|
}
|
|
|
|
@test "runc exec ls -la with --cwd" {
|
|
# run busybox detached
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
[ "$status" -eq 0 ]
|
|
|
|
runc exec --cwd /bin test_busybox pwd
|
|
[ "$status" -eq 0 ]
|
|
[[ ${output} == "/bin"* ]]
|
|
}
|
|
|
|
@test "runc exec --env" {
|
|
# run busybox detached
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
[ "$status" -eq 0 ]
|
|
|
|
runc exec --env RUNC_EXEC_TEST=true test_busybox env
|
|
[ "$status" -eq 0 ]
|
|
|
|
[[ ${output} == *"RUNC_EXEC_TEST=true"* ]]
|
|
}
|
|
|
|
@test "runc exec --user" {
|
|
# --user can't work in rootless containers that don't have idmap.
|
|
[ $EUID -ne 0 ] && requires rootless_idmap
|
|
|
|
# run busybox detached
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
[ "$status" -eq 0 ]
|
|
|
|
runc exec --user 1000:1000 test_busybox id
|
|
[ "$status" -eq 0 ]
|
|
[[ "${output}" == "uid=1000 gid=1000"* ]]
|
|
|
|
# Check the default value of HOME ("/") is set even in case when
|
|
# - HOME is not set in process.Env, and
|
|
# - there is no entry in container's /etc/passwd for a given UID.
|
|
#
|
|
# NOTE this is not a standard runtime feature, but rather
|
|
# a historical de facto behavior we're afraid to change.
|
|
|
|
# shellcheck disable=SC2016
|
|
runc exec --user 1000 test_busybox sh -u -c 'echo $HOME'
|
|
[ "$status" -eq 0 ]
|
|
[[ "$output" = "/" ]]
|
|
}
|
|
|
|
# https://github.com/opencontainers/runc/issues/3674.
|
|
@test "runc exec --user vs /dev/null ownership" {
|
|
requires root
|
|
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
[ "$status" -eq 0 ]
|
|
|
|
ls -l /dev/null
|
|
__runc exec -d --user 1000:1000 test_busybox id </dev/null
|
|
ls -l /dev/null
|
|
UG=$(stat -c %u:%g /dev/null)
|
|
|
|
# Host's /dev/null must be owned by root.
|
|
[ "$UG" = "0:0" ]
|
|
}
|
|
|
|
@test "runc exec --additional-gids" {
|
|
requires root
|
|
|
|
# run busybox detached
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
[ "$status" -eq 0 ]
|
|
|
|
wait_for_container 15 1 test_busybox
|
|
|
|
runc exec --user 1000:1000 --additional-gids 100 --additional-gids 65534 test_busybox id -G
|
|
[ "$status" -eq 0 ]
|
|
[ "$output" = "1000 100 65534" ]
|
|
}
|
|
|
|
@test "runc exec --preserve-fds" {
|
|
# run busybox detached
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
[ "$status" -eq 0 ]
|
|
|
|
echo hello >preserve-fds.test
|
|
# fd 3 is used by bats, so we use 4
|
|
exec 4<preserve-fds.test
|
|
runc exec --preserve-fds=2 test_busybox cat /proc/self/fd/4
|
|
[ "$status" -eq 0 ]
|
|
[ "${output}" = "hello" ]
|
|
}
|
|
|
|
function check_exec_debug() {
|
|
[[ "$*" == *"nsexec container setup"* ]]
|
|
[[ "$*" == *"child process in init()"* ]]
|
|
[[ "$*" == *"setns_init: about to exec"* ]]
|
|
}
|
|
|
|
@test "runc --debug exec" {
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test
|
|
[ "$status" -eq 0 ]
|
|
|
|
runc --debug exec test true
|
|
[ "$status" -eq 0 ]
|
|
[[ "${output}" == *"level=debug"* ]]
|
|
check_exec_debug "$output"
|
|
}
|
|
|
|
@test "runc --debug --log exec" {
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test
|
|
[ "$status" -eq 0 ]
|
|
|
|
runc --debug --log log.out exec test true
|
|
# check output does not include debug info
|
|
[[ "${output}" != *"level=debug"* ]]
|
|
|
|
cat log.out >&2
|
|
# check expected debug output was sent to log.out
|
|
output=$(cat log.out)
|
|
[[ "${output}" == *"level=debug"* ]]
|
|
check_exec_debug "$output"
|
|
}
|
|
|
|
@test "runc exec --cgroup sub-cgroups [v1]" {
|
|
requires root cgroups_v1
|
|
|
|
set_cgroups_path
|
|
set_cgroup_mount_writable
|
|
|
|
__runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
testcontainer test_busybox running
|
|
|
|
# Check we can't join parent cgroup.
|
|
runc exec --cgroup ".." test_busybox cat /proc/self/cgroup
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *"bad sub cgroup path"* ]]
|
|
|
|
# Check we can't join non-existing subcgroup.
|
|
runc exec --cgroup nonexistent test_busybox cat /proc/self/cgroup
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *" adding pid "*"o such file or directory"* ]]
|
|
|
|
# Check we can't join non-existing subcgroup (for a particular controller).
|
|
runc exec --cgroup cpu:nonexistent test_busybox cat /proc/self/cgroup
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *" adding pid "*"o such file or directory"* ]]
|
|
|
|
# Check we can't specify non-existent controller.
|
|
runc exec --cgroup whaaat:/ test_busybox true
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *"unknown controller "* ]]
|
|
|
|
# Check we can join top-level cgroup (implicit).
|
|
runc exec test_busybox cat /proc/self/cgroup
|
|
[ "$status" -eq 0 ]
|
|
run ! grep -v ":$REL_CGROUPS_PATH\$" <<<"$output"
|
|
|
|
# Check we can join top-level cgroup (explicit).
|
|
runc exec --cgroup / test_busybox cat /proc/self/cgroup
|
|
[ "$status" -eq 0 ]
|
|
run ! grep -v ":$REL_CGROUPS_PATH\$" <<<"$output"
|
|
|
|
# Create a few subcgroups.
|
|
# Note that cpu,cpuacct may be mounted together or separate.
|
|
runc exec test_busybox sh -euc "mkdir -p /sys/fs/cgroup/memory/submem /sys/fs/cgroup/cpu/subcpu /sys/fs/cgroup/cpuacct/subcpu"
|
|
[ "$status" -eq 0 ]
|
|
|
|
# Check that explicit --cgroup works.
|
|
runc exec --cgroup memory:submem --cgroup cpu,cpuacct:subcpu test_busybox cat /proc/self/cgroup
|
|
[ "$status" -eq 0 ]
|
|
[[ "$output" == *":memory:$REL_CGROUPS_PATH/submem"* ]]
|
|
[[ "$output" == *":cpu"*":$REL_CGROUPS_PATH/subcpu"* ]]
|
|
}
|
|
|
|
@test "runc exec --cgroup subcgroup [v2]" {
|
|
requires root cgroups_v2
|
|
|
|
set_cgroups_path
|
|
set_cgroup_mount_writable
|
|
|
|
__runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
testcontainer test_busybox running
|
|
|
|
# Check we can't join parent cgroup.
|
|
runc exec --cgroup ".." test_busybox cat /proc/self/cgroup
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *"bad sub cgroup path"* ]]
|
|
|
|
# Check we can't join non-existing subcgroup.
|
|
runc exec --cgroup nonexistent test_busybox cat /proc/self/cgroup
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *" adding pid "*"o such file or directory"* ]]
|
|
|
|
# Check we can join top-level cgroup (implicit).
|
|
runc exec test_busybox grep '^0::/$' /proc/self/cgroup
|
|
[ "$status" -eq 0 ]
|
|
|
|
# Check we can join top-level cgroup (explicit).
|
|
runc exec --cgroup / test_busybox grep '^0::/$' /proc/self/cgroup
|
|
[ "$status" -eq 0 ]
|
|
|
|
# Now move "init" to a subcgroup, and check it was moved.
|
|
runc exec test_busybox sh -euc "mkdir /sys/fs/cgroup/foobar \
|
|
&& echo 1 > /sys/fs/cgroup/foobar/cgroup.procs \
|
|
&& grep -w foobar /proc/1/cgroup"
|
|
[ "$status" -eq 0 ]
|
|
|
|
# The following part is taken from
|
|
# @test "runc exec (cgroup v2 + init process in non-root cgroup) succeeds"
|
|
|
|
# The init process is now in "/foo", but an exec process can still
|
|
# join "/" because we haven't enabled any domain controller yet.
|
|
runc exec test_busybox grep '^0::/$' /proc/self/cgroup
|
|
[ "$status" -eq 0 ]
|
|
|
|
# Turn on a domain controller (memory).
|
|
runc exec test_busybox sh -euc 'echo $$ > /sys/fs/cgroup/foobar/cgroup.procs; echo +memory > /sys/fs/cgroup/cgroup.subtree_control'
|
|
[ "$status" -eq 0 ]
|
|
|
|
# An exec process can no longer join "/" after turning on a domain
|
|
# controller. Check that cgroup v2 fallback to init cgroup works.
|
|
runc exec test_busybox sh -euc "cat /proc/self/cgroup && grep '^0::/foobar$' /proc/self/cgroup"
|
|
[ "$status" -eq 0 ]
|
|
|
|
# Check that --cgroup / disables the init cgroup fallback.
|
|
runc exec --cgroup / test_busybox true
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *" adding pid "*" to cgroups"*"evice or resource busy"* ]]
|
|
|
|
# Check that explicit --cgroup foobar works.
|
|
runc exec --cgroup foobar test_busybox grep '^0::/foobar$' /proc/self/cgroup
|
|
[ "$status" -eq 0 ]
|
|
|
|
# Check all processes is in foobar (this check is redundant).
|
|
runc exec --cgroup foobar test_busybox sh -euc '! grep -vwH foobar /proc/*/cgroup'
|
|
[ "$status" -eq 0 ]
|
|
|
|
# Add a second subcgroup, check we're in it.
|
|
runc exec --cgroup foobar test_busybox mkdir /sys/fs/cgroup/second
|
|
[ "$status" -eq 0 ]
|
|
runc exec --cgroup second test_busybox grep -w second /proc/self/cgroup
|
|
[ "$status" -eq 0 ]
|
|
}
|
|
|
|
@test "runc exec [execve error]" {
|
|
cat <<EOF >rootfs/run.sh
|
|
#!/mmnnttbb foo bar
|
|
sh
|
|
EOF
|
|
chmod +x rootfs/run.sh
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
|
runc exec -t test_busybox /run.sh
|
|
[ "$status" -ne 0 ]
|
|
|
|
# After the sync socket closed, we should not send error to parent
|
|
# process, or else we will get a unnecessary error log(#4171).
|
|
# Although we never close the sync socket when doing exec,
|
|
# but we need to keep this test to ensure this behavior is always right.
|
|
[ ${#lines[@]} -eq 1 ]
|
|
[[ ${lines[0]} = *"exec /run.sh: no such file or directory"* ]]
|
|
}
|
|
|
|
# https://github.com/opencontainers/runc/issues/4688
|
|
@test "runc exec check default home" {
|
|
# --user can't work in rootless containers that don't have idmap.
|
|
[ $EUID -ne 0 ] && requires rootless_idmap
|
|
echo 'tempuser:x:2000:2000:tempuser:/home/tempuser:/bin/sh' >>rootfs/etc/passwd
|
|
|
|
runc run -d --console-socket "$CONSOLE_SOCKET" test
|
|
[ "$status" -eq 0 ]
|
|
|
|
runc exec -u 2000 test sh -c "echo \$HOME"
|
|
[ "$status" -eq 0 ]
|
|
[ "${lines[0]}" = "/home/tempuser" ]
|
|
}
|