From 3576d8e155962c2045fab5d3adfc7672605f6964 Mon Sep 17 00:00:00 2001 From: Maksim Davydov Date: Tue, 23 Dec 2025 16:55:29 +0300 Subject: [PATCH] IGNITE-27445 [ducktests] Docker setup fails with bind-mounted repositories due to user permission mismatch --- modules/ducktests/tests/docker/Dockerfile | 17 +++++++++--- modules/ducktests/tests/docker/ducker-ignite | 28 +++++++++++++++----- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/modules/ducktests/tests/docker/Dockerfile b/modules/ducktests/tests/docker/Dockerfile index 2c6289f9ea318..68a5d4f6d131a 100644 --- a/modules/ducktests/tests/docker/Dockerfile +++ b/modules/ducktests/tests/docker/Dockerfile @@ -94,18 +94,27 @@ ARG JMXTERM_ARTIFACT="$JMXTERM_NAME-$JMXTERM_VERSION-uber.jar" RUN cd /opt && curl -OL https://github.com/jiaqi/jmxterm/releases/download/v$JMXTERM_VERSION/$JMXTERM_ARTIFACT \ && mv $JMXTERM_ARTIFACT $JMXTERM_NAME.jar -# Set up the ducker user. -RUN userdel -r ubuntu \ - && useradd -ms /bin/bash ducker \ +# Build-time arguments for host UID/GID +ARG HOST_UID=1000 +ARG HOST_GID=1000 + +# Delete default ubuntu user if it exists +RUN userdel -r ubuntu || true + +# Create ducker group and user matching host UID/GID +RUN groupadd -g ${HOST_GID} ducker \ + && useradd -ms /bin/bash -u ${HOST_UID} -g ${HOST_GID} -K UID_MIN=0 ducker \ && mkdir -p /home/ducker/ \ && rsync -aiq /root/.ssh/ /home/ducker/.ssh \ - && chown -R ducker /home/ducker/ /mnt/ /var/log/ /opt \ + && chown -R ${HOST_UID}:${HOST_GID} /home/ducker/ /mnt/ /var/log/ /opt \ && cp /dev/null /etc/environment \ && echo "LANG=C.UTF-8" >> /home/ducker/.ssh/environment \ && echo "PATH=$(runuser -l ducker -c 'echo $PATH'):$JAVA_HOME/bin:/opt/venv/bin" >> /home/ducker/.ssh/environment \ && echo "JAVA_HOME=$JAVA_HOME" >> /home/ducker/.ssh/environment \ && echo 'PATH=$PATH:'"$JAVA_HOME/bin" >> /home/ducker/.profile \ && echo 'ducker ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers + +# Switch to ducker user USER ducker CMD sudo service ssh start && tail -f /dev/null diff --git a/modules/ducktests/tests/docker/ducker-ignite b/modules/ducktests/tests/docker/ducker-ignite index 10d2b8f7a6d95..39d59f303a7bf 100755 --- a/modules/ducktests/tests/docker/ducker-ignite +++ b/modules/ducktests/tests/docker/ducker-ignite @@ -31,6 +31,18 @@ ducker_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # The absolute path to the root Ignite directory ignite_dir="$( cd "${ducker_dir}/../../../.." && pwd )" +# Container-side base directory for the ducker user +container_ducker_dir="/home/ducker" + +# Container-side path where tests of ducktests module are mounted for ducktape tests visibility +container_ducker_test_dir="${container_ducker_dir}/ducktests" + +# Container-side path where Ignite source/code is mounted for Ignite start-up +container_ignite_dir="/opt/ignite-dev" + +# Container-side path where Ignite source/code is mounted for Ignite start-up +container_ignite_ext_dir="/opt/ignite-extensions" + # The memory consumption to allow during the docker build. # This does not include swap. docker_build_memory_limit="8000m" @@ -256,6 +268,7 @@ ducker_build_image() { # Tip: if you are scratching your head for some dependency problems that are referring to an old code version # (for example java.lang.NoClassDefFoundError), add --no-cache flag to the build shall give you a clean start. must_do -v -o docker build --memory="${docker_build_memory_limit}" \ + --build-arg "HOST_UID=$(id -u)" --build-arg "HOST_GID=$(id -g)" \ --build-arg "ducker_creator=${user_name}" --build-arg "jdk_version=${jdk_version}" -t "${image_name}" \ -f "${docker_context}/Dockerfile" -- "${docker_context}" docker_status=$? @@ -308,7 +321,7 @@ docker_run() { local mount_ignite_ext="" if [[ -d "${ignite_dir}/../ignite-extensions" ]]; then local ignite_ext_dir="$( cd "${ignite_dir}/../ignite-extensions" && pwd )" - mount_ignite_ext="--mount type=bind,source="${ignite_ext_dir}",target=/opt/ignite-extensions,consistency=delegated" + mount_ignite_ext="--mount type=bind,source="${ignite_ext_dir}",target=${container_ignite_ext_dir},consistency=delegated" fi # Invoke docker-run. We need privileged mode to be able to run iptables @@ -321,7 +334,8 @@ docker_run() { --network ducknet ${expose_ports} \ --memory=${docker_run_memory_limit} \ --memory-swappiness=1 \ - --mount type=bind,source="${ignite_dir}",target=/opt/ignite-dev,consistency=delegated \ + --mount type=bind,source="${ignite_dir}",target=${container_ignite_dir},consistency=delegated \ + --mount type=bind,source="${ducker_dir}/../",target=${container_ducker_test_dir},consistency=delegated \ "${mount_ignite_ext}" \ $DOCKER_OPTIONS \ --name "${node}" \ @@ -338,7 +352,7 @@ setup_custom_ducktape() { local running_container running_container=$(docker ps -f=network=ducknet -q) must_do -v -o docker cp "${custom_ducktape}" "${running_container}:/opt/ducktape" - docker exec --user=root ducker01 bash -c 'set -x && cd /opt/ignite-dev/modules/ducktests/tests && sudo python ./setup.py develop install && cd /opt/ducktape && sudo python ./setup.py develop install' + docker exec --user=root ducker01 bash -c "set -x && cd ${container_ducker_test_dir} && sudo python ./setup.py develop install && cd /opt/ducktape && sudo python ./setup.py develop install" [[ $? -ne 0 ]] && die "failed to install the new ducktape." must_do -v -o docker commit ducker01 "${image_name}" must_do -v docker kill "${running_container}" @@ -408,7 +422,7 @@ attempting to start new ones." for n in $(seq -f %02g 1 ${num_nodes}); do local node="ducker${n}" docker exec --user=root "${node}" \ - bash -c "grep -v ${node} /opt/ignite-dev/modules/ducktests/tests/docker/build/node_hosts >> /etc/hosts" + bash -c "grep -v ${node} ${container_ducker_test_dir}/docker/build/node_hosts >> /etc/hosts" [[ $? -ne 0 ]] && die "failed to append to the /etc/hosts file on ${node}" done @@ -466,7 +480,7 @@ cat<&3 "ssh_config": { "host": "${node}", "hostname": "${node}", - "identityfile": "/home/ducker/.ssh/id_rsa", + "identityfile": "${container_ducker_dir}/.ssh/id_rsa", "password": "", "port": 22, "user": "ducker" @@ -493,7 +507,7 @@ ducker_test() { local regex=".*\/ignitetest\/(.*)" if [[ $arg =~ $regex ]]; then local ignpath=${BASH_REMATCH[1]} - args="${args} ./modules/ducktests/tests/ignitetest/${ignpath}" + args="${args} ${container_ducker_test_dir}/ignitetest/${ignpath}" else args="${args} ${arg}" fi @@ -510,7 +524,7 @@ ducker_test() { wait_jobs [[ $? -ne 0 ]] && die "failed to execute extra ducktape setup." fi - cmd="cd /opt/ignite-dev && ducktape --cluster-file /opt/ignite-dev/modules/ducktests/tests/docker/build/cluster.json $args" + cmd="cd ${container_ducker_dir} && ducktape --results-root ${container_ducker_dir} --cluster-file ${container_ducker_test_dir}/docker/build/cluster.json $args" echo "docker exec ducker01 bash -c \"${cmd}\"" exec docker exec --user=ducker ducker01 bash -c "${cmd}" }