Don't use a toolbox container until after it has been configured

It was possible to have 'podman exec' invoked against a toolbox
container before the entry point had finished initializing it. This
could lead to situations where '$USER' didn't yet exist inside the
container when 'podman exec' attempted running a binary as that user,
which would end up failing 'toolbox enter'.

There are a number of corner cases that need to be kept in mind while
implementing any kind of synchronization.

First, older containers don't use 'toolbox init-container' as their
entry point. This might mean that their start-up can't be synchronized
but they should still be kept working in their current state.

Second, once a container has been started, subsequent 'podman start'
invocations are NOPs. They won't lead to newer instances of the entry
point process being launched.

Third, the entry point process can crash or get killed due to an
out-of-band 'podman stop'. In such cases, 'toolbox enter' should not
get confused or deadlocked. It should give a meaningful error message
to the user.

Fourth, it would be nice to not have to touch the 'create' command so
that toolbox containers created with Toolbox 0.0.10 onwards can have
their start-up synchronized. This means that the host can't add any
new environment variable or bind mount to the container to agree upon
a path that's keyed by the container's identity and shared with the
host.

Given all these considerations, a timed busy loop that looks for the
presence of a stamp file, keyed by the entry point's PID, is the most
robust solution that can be verified as correct. Anything involving
file locks becomes increasingly complicated and hard to verify.

Under normal circumstances, the loop isn't expected to last more than
a few iterations. In case the entry point dies, the loop will time out
after approximately 25 seconds, the same interval as the default for
D-Bus method calls.

Some changes by Debarshi Ray based on an idea from Jan Hlaváč.

https://github.com/containers/toolbox/pull/305
This commit is contained in:
Harry Míchal 2019-10-23 01:26:06 +02:00 committed by Debarshi Ray
parent 08fa8f5440
commit d3e0f3df06

60
toolbox
View file

@ -1043,6 +1043,17 @@ init_container()
init_container_uid="$5"
init_container_user="$6"
if [ "$XDG_RUNTIME_DIR" = "" ] 2>&3; then
echo "$base_toolbox_command: XDG_RUNTIME_DIR is unset" >&3
XDG_RUNTIME_DIR=/run/user/"$init_container_uid"
echo "$base_toolbox_command: XDG_RUNTIME_DIR set to $XDG_RUNTIME_DIR" >&3
toolbox_runtime_directory="$XDG_RUNTIME_DIR"/toolbox
fi
init_container_initialized_stamp="$toolbox_runtime_directory"/container-initialized-"$$"
echo "$base_toolbox_command: creating /run/.toolboxenv" >&3
if ! touch /run/.toolboxenv 2>&3; then
@ -1187,6 +1198,13 @@ EOF
fi
fi
echo "$base_toolbox_command: finished initializing container" >&3
if ! touch "$init_container_initialized_stamp" 2>&3; then
echo "$base_toolbox_command: failed to create initialization stamp" >&2
return 1
fi
echo "$base_toolbox_command: going to sleep" >&3
exec sleep +Inf
@ -1320,6 +1338,48 @@ run()
fi
fi
echo "$base_toolbox_command: inspecting entry point of container $toolbox_container" >&3
if ! entry_point=$(podman inspect --format "{{index .Config.Cmd 0}}" --type container "$toolbox_container" 2>&3); then
echo "$base_toolbox_command: failed to inspect entry point of container $toolbox_container" >&2
exit 1
fi
echo "$base_toolbox_command: entry point of container $toolbox_container is $entry_point" >&3
if [ "$entry_point" = "toolbox" ] 2>&3; then
echo "$base_toolbox_command: waiting for container $toolbox_container to finish initializing" >&3
if ! entry_point_pid=$(podman inspect --format "{{.State.Pid}}" --type container "$toolbox_container" 2>&3); then
echo "$base_toolbox_command: failed to inspect entry point PID of container $toolbox_container" >&2
exit 1
fi
if ! is_integer "$entry_point_pid"; then
echo "$base_toolbox_command: failed to parse entry point PID of container $toolbox_container" >&2
exit 1
fi
if [ "$entry_point_pid" -le 0 ] 2>&3; then
echo "$base_toolbox_command: invalid entry point PID of container $toolbox_container" >&2
exit 1
fi
container_initialized_stamp="$toolbox_runtime_directory/container-initialized-$entry_point_pid"
container_initialized_timeout=25 #s
i=0
while ! [ -f "$container_initialized_stamp" ] 2>&3; do
sleep 1 2>&3
i=$((i + 1))
if [ "$i" -eq "$container_initialized_timeout" ] 2>&3; then
echo "$base_toolbox_command: failed to initialize container $toolbox_container" >&2
exit 1
fi
done
fi
if ! podman exec --user root:root "$toolbox_container" touch /run/.toolboxenv 2>&3; then
echo "$base_toolbox_command: failed to create /run/.toolboxenv in container $toolbox_container" >&2
exit 1