Skip to content

Commit

Permalink
Avoid parsing global or image-specific args
Browse files Browse the repository at this point in the history
Among other things.
  • Loading branch information
felipecrs committed Jun 15, 2023
1 parent 4e40b99 commit 6ec3fc4
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 23 deletions.
19 changes: 16 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
ARG DOCKER_VERSION="latest"
FROM docker:${DOCKER_VERSION} AS test

# Install APK deps
RUN apk add --no-cache bash

# Install dond-shim
ARG DOCKER_PATH="/usr/local/bin/docker"
RUN mv -f "${DOCKER_PATH}" "${DOCKER_PATH}.orig"
COPY docker "${DOCKER_PATH}"

# Create fixtures
RUN mkdir -p /test && \
echo test | tee /test/only-inside-container

# Set default stage
FROM felipecrs/fixdockergid:latest

USER root
Expand All @@ -7,6 +23,3 @@ RUN mv -f "${DOCKER_PATH}" "${DOCKER_PATH}.orig"
COPY docker "${DOCKER_PATH}"

USER rootless

# Create fixtures
RUN echo test | tee /home/rootless/only-inside-container
111 changes: 107 additions & 4 deletions docker
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

set -euo pipefail

if [[ "${DOND_SHIM_DEBUG:-false}" == true ]]; then
set -x
fi

function get_container_id() {
local cpuset_output
cpuset_output=$(head -1 /proc/self/cpuset)
Expand Down Expand Up @@ -74,14 +78,107 @@ function fix_volume_arg() {
volume_arg="${source}:${destination}"
}

function get_docker_options_with_value() {
local -n target_array="${1}"
shift 1
local command=("${@}")

local help_output
help_output="$(docker.orig "${command[@]}" --help)"

readarray -t help_lines <<<"${help_output}"
target_array=()
for line in "${help_lines[@]}"; do
# second group is the short option (optional)
# third group is the long option
if [[ "${line}" =~ ^[[:space:]]+((-[a-zA-Z]),[[:space:]])?(--[a-z0-9-]+)[[:space:]][a-z]+[[:space:]]+.*$ ]]; then
if [[ -n "${BASH_REMATCH[2]}" ]]; then
target_array+=("${BASH_REMATCH[2]}")
fi
target_array+=("${BASH_REMATCH[3]}")
fi
done
}

options_with_value=()
get_docker_options_with_value options_with_value

original_args=("$@")
fixed_args=()

# TODO: only piggyback on docker run, container run, create and container create
skip_next=false
parsing="global"
global_args=()
found_first_global_positional=false
command_args=()
image_args=()
for i in "${!original_args[@]}"; do
arg="${original_args[${i}]}"

if [[ "${parsing}" == "global" ]]; then
global_args+=("${arg}")

if [[ "${skip_next}" == true ]]; then
skip_next=false
continue
fi

if [[ "${arg}" == "-"* ]]; then
if [[ "${found_first_global_positional}" == false ]]; then
for option_with_value in "${options_with_value[@]}"; do
if [[ "${arg}" == "${option_with_value}" ]]; then
skip_next=true
continue
fi
done
fi
continue
fi

if [[ "${arg}" == "run" || "${arg}" == "create" ]]; then
options_with_value=()
get_docker_options_with_value options_with_value "${arg}"
parsing="command"
elif [[ "${arg}" == "container" ]]; then
found_first_global_positional=true
true
else
# Skip if command is not run, create, container run, or container create
if [[ "${DOND_SHIM_PRINT_COMMAND:-false}" == true ]]; then
echo docker.orig "${original_args[@]}"
exit 0
else
exec docker.orig "${original_args[@]}"
fi
fi
elif [[ "${parsing}" == "command" ]]; then
command_args+=("${arg}")

if [[ "${skip_next}" == true ]]; then
skip_next=false
continue
fi

if [[ "${arg}" == "-"* ]]; then
for option_with_value in "${options_with_value[@]}"; do
if [[ "${arg}" == "${option_with_value}" ]]; then
skip_next=true
continue
fi
done
continue
fi

# If this is reached, then the first positional argument has been found
parsing="image"
elif [[ "${parsing}" == "image" ]]; then
image_args+=("${arg}")
fi
done

fixed_args=()
extra_args=()
fix_next_arg=false
for arg in "${original_args[@]}"; do
for arg in "${command_args[@]}"; do
if [[ "${fix_next_arg}" == true ]]; then
fix_next_arg=false
volume_arg="${arg}"
Expand All @@ -100,4 +197,10 @@ for arg in "${original_args[@]}"; do
extra_args=()
done

exec docker.orig "${fixed_args[@]}"
final_command=(docker.orig "${global_args[@]}" "${fixed_args[@]}" "${image_args[@]}")

if [[ "${DOND_SHIM_PRINT_COMMAND:-false}" == true ]]; then
echo "${final_command[@]}"
else
exec "${final_command[@]}"
fi
85 changes: 69 additions & 16 deletions test.sh
Original file line number Diff line number Diff line change
@@ -1,25 +1,78 @@
#!/bin/bash

set -euxo pipefail
set -euo pipefail

image_id="$(docker build --quiet .)"
if [[ "${DEBUG:-false}" == true ]]; then
set -x
export DOND_SHIM_DEBUG=true
fi

# shellcheck disable=SC2312
docker_args=(docker run --rm --user "$(id -u):$(id -g)" --volume /var/run/docker.sock:/var/run/docker.sock)
# Set docker versions from args or use defaults
if [[ $# -eq 0 ]]; then
docker_versions=("18.09" "19.03" "20.10" "23" "24" latest)
else
docker_versions=("$@")
fi

# Check if docker on docker is working
"${docker_args[@]}" "${image_id}" docker version >/dev/null
for docker_version in "${docker_versions[@]}"; do
echo "Testing with docker version: ${docker_version}"

# Check if mounting an volume from the container gets fixed
"${docker_args[@]}" "${image_id}" docker run --rm --volume /home/rootless/only-inside-container:/only-inside-container ubuntu:latest grep "^test$" /only-inside-container >/dev/null
"${docker_args[@]}" "${image_id}" docker run --rm --volume=/home/rootless/only-inside-container:/only-inside-container ubuntu:latest grep "^test$" /only-inside-container >/dev/null
image_id="$(docker build --target test --build-arg "DOCKER_VERSION=${docker_version}" --quiet .)"

# Check if mounting a volume which is already a volume gets fixed
"${docker_args[@]}" --volume "${PWD}:/wd" "${image_id}" docker run --rm --volume /wd:/wd ubuntu:latest grep "^test$" /wd/testfile >/dev/null
# shellcheck disable=SC2312
docker_args=(docker run --rm --env DOND_SHIM_DEBUG --entrypoint= --volume /var/run/docker.sock:/var/run/docker.sock)

# Same as above but for a file within the volume
"${docker_args[@]}" --volume "${PWD}:/wd" "${image_id}" docker run --rm --volume /wd/testfile:/wd/testfile ubuntu:latest grep "^test$" /wd/testfile >/dev/null
echo "Do not change global options or after the image"
"${docker_args[@]}" --env DOND_SHIM_PRINT_COMMAND=true --volume "${PWD}:/wd" "${image_id}" \
docker --host test run --volume /wd:/wd alpine --volume /wd:/wd |
grep --quiet "^docker.orig --host test run --volume ${PWD}:/wd alpine --volume /wd:/wd$"

# Volumes inside volumes
"${docker_args[@]}" --volume "${PWD}/testfile:/home/rootless/testfile" "${image_id}" docker run --rm --volume /home/rootless:/wd ubuntu:latest grep "^test$" /wd/testfile >/dev/null
"${docker_args[@]}" --volume "${PWD}/testfile:/home/rootless/testfile" --volume "${PWD}/testfile:/home/rootless/testfile2" "${image_id}" docker run --rm --volume /home/rootless:/wd ubuntu:latest bash -c 'grep "^test$" /wd/testfile && grep "^test$" /wd/testfile2 && grep "^test$" /wd/only-inside-container' >/dev/null
echo "Same but for container run"
"${docker_args[@]}" --env DOND_SHIM_PRINT_COMMAND=true --volume "${PWD}:/wd" "${image_id}" \
docker --host test container run --volume /wd:/wd alpine --volume /wd:/wd |
grep --quiet "^docker.orig --host test container run --volume ${PWD}:/wd alpine --volume /wd:/wd$"

echo "Same but for create"
"${docker_args[@]}" --env DOND_SHIM_PRINT_COMMAND=true --volume "${PWD}:/wd" "${image_id}" \
docker --host test create --volume /wd:/wd alpine --volume /wd:/wd |
grep --quiet "^docker.orig --host test create --volume ${PWD}:/wd alpine --volume /wd:/wd$"

echo "Same but container create"
"${docker_args[@]}" --env DOND_SHIM_PRINT_COMMAND=true --volume "${PWD}:/wd" "${image_id}" \
docker --host test container create --volume /wd:/wd alpine --volume /wd:/wd |
grep --quiet "^docker.orig --host test container create --volume ${PWD}:/wd alpine --volume /wd:/wd$"

echo "Do not do anything for other commands"
"${docker_args[@]}" --env DOND_SHIM_PRINT_COMMAND=true --volume "${PWD}:/wd" "${image_id}" \
docker --host test whatever --volume /wd:/wd alpine --volume /wd:/wd |
grep --quiet "^docker.orig --host test whatever --volume /wd:/wd alpine --volume /wd:/wd$"

echo "Check if docker on docker is working"
"${docker_args[@]}" "${image_id}" \
docker version >/dev/null

echo "Check if mounting an volume from the container gets fixed"
"${docker_args[@]}" "${image_id}" \
docker run --rm --volume /test/only-inside-container:/only-inside-container ubuntu:latest grep "^test$" /only-inside-container >/dev/null

echo "Same but with equals sign"
"${docker_args[@]}" "${image_id}" \
docker run --rm --volume=/test/only-inside-container:/only-inside-container ubuntu:latest grep "^test$" /only-inside-container >/dev/null

echo "Check if mounting a volume which is already a volume gets fixed"
"${docker_args[@]}" --volume "${PWD}:/wd" "${image_id}" \
docker run --rm --volume /wd:/wd ubuntu:latest grep "^test$" /wd/testfile >/dev/null

echo "Same as above but for a file within the volume"
"${docker_args[@]}" --volume "${PWD}:/wd" "${image_id}" \
docker run --rm --volume /wd/testfile:/wd/testfile ubuntu:latest grep "^test$" /wd/testfile >/dev/null

echo "Check if mounting a volume which contains another volume adds all proper volumes"
"${docker_args[@]}" --volume "${PWD}/testfile:/test/testfile" "${image_id}" \
docker run --rm --volume /test:/wd ubuntu:latest grep "^test$" /wd/testfile >/dev/null

echo "Same as above but for multiple files under different volumes"
"${docker_args[@]}" --volume "${PWD}/testfile:/test/testfile" --volume "${PWD}/testfile:/test/testfile2" "${image_id}" \
docker run --rm --volume /test:/wd ubuntu:latest bash -c 'grep "^test$" /wd/testfile && grep "^test$" /wd/testfile2 && grep "^test$" /wd/only-inside-container' >/dev/null

done

0 comments on commit 6ec3fc4

Please sign in to comment.