Remove the host network setting, ensuring we use private networks (slirp4netns). This will allow nested container port aliasing, helping CI stability (can use ephemeral ports and container introspection). This also makes the nested podman setup non-conditional, since we only run podman containers inside dbuild, and need the setup regardless if host container is docker or not.
321 lines
8.0 KiB
Bash
Executable File
321 lines
8.0 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
if [[ -f ~/.config/scylladb/dbuild ]]; then
|
|
. ~/.config/scylladb/dbuild
|
|
fi
|
|
|
|
function die () {
|
|
msg="$1"
|
|
if [[ -n "$msg" ]]; then
|
|
echo "$(basename $0): $msg." 1>&2
|
|
fi
|
|
cat <<EOF 1>&2
|
|
|
|
Run \`$0 --help' to print the full help message.
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
command_exists() {
|
|
type -p "$1" > /dev/null
|
|
}
|
|
|
|
if command_exists podman ; then
|
|
tool=${DBUILD_TOOL-podman}
|
|
elif command_exists docker ; then
|
|
tool=${DBUILD_TOOL-docker}
|
|
else
|
|
die "Please make sure you install either podman or docker on this machine to run dbuild"
|
|
fi
|
|
|
|
here="$(realpath $(dirname "$0"))"
|
|
toplevel="$(realpath "$here/../..")"
|
|
group_args=()
|
|
docker_args=()
|
|
tmpfiles=()
|
|
image="$(<"$here/image")"
|
|
|
|
for gid in $(id -G); do
|
|
group_args+=(--group-add "$gid")
|
|
done
|
|
|
|
interactive=
|
|
|
|
function help () {
|
|
cat <<EOF 1>&2
|
|
NAME
|
|
$(basename $0) - Run a command in scylla's frozen toolchain docker build image.
|
|
|
|
SYNOPSIS
|
|
$0 [OPTIONS --] [command [arg ...]]
|
|
|
|
DESCRIPTION
|
|
$(basename $0) is used mainly to build scylla in a docker image containing
|
|
a frozen version of the toolchain.
|
|
|
|
When no command is provided, $(basename $0) runs an interactive shell in
|
|
the docker instance. The image to use is taken by default from "$(dirname $0)/image".
|
|
It may be overriden using the --image option.
|
|
|
|
When providing docker options, the options list must be terminated with \`--'.
|
|
|
|
OPTIONS
|
|
-h | --help
|
|
Print this help message.
|
|
|
|
--image [IMAGE]
|
|
Use the specified docker IMAGE.
|
|
If omitted, list the available images using \`docker image ls'
|
|
|
|
-i | --interactive
|
|
Run an interactive session.
|
|
|
|
See \`docker help run' for available options.
|
|
|
|
ENVIRONMENT
|
|
|
|
SCYLLADB_DBUILD this variable, which can be a string or a bash
|
|
array, is prepended to the parmeters passed to
|
|
docker. This can be used to mount old-style ccache
|
|
directory (~/.ccache) and set up environment
|
|
variables (e.g. CCACHE_PREFIX)
|
|
|
|
If the file ~/.config/scylladb/dbuild exists, it is sourced. This can
|
|
be used to set up the SCYLLADB_DBUILD environment variable.
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
if [[ $# -eq 0 ]]; then
|
|
interactive=y
|
|
docker_args=(-it)
|
|
elif [[ "$1" = -* ]]; then
|
|
while [[ "$1" != "--" && $# != 0 ]]; do
|
|
case "$1" in
|
|
-h|--help)
|
|
help
|
|
;;
|
|
--image)
|
|
image="$2"
|
|
shift 2
|
|
if [[ -z "$image" ]]; then
|
|
die "Expected docker image identifier to follow the --image option"
|
|
fi
|
|
if ! $tool image inspect "$image" >/dev/null && ! $tool image pull "$image"; then
|
|
die
|
|
fi
|
|
continue
|
|
;;
|
|
--*)
|
|
if [[ "$1" = --interactive || "$1" = --interactive=true ]]; then
|
|
interactive=y
|
|
fi
|
|
;;
|
|
-*)
|
|
if [[ "$1" = -*i* ]]; then
|
|
interactive=y
|
|
fi
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
docker_args+=("$1")
|
|
shift
|
|
done
|
|
if [[ "$1" != "--" ]]; then
|
|
die "Expected '--' to terminate docker flag list"
|
|
fi
|
|
shift
|
|
fi
|
|
|
|
if [[ $# != 0 ]]; then
|
|
args=("$@")
|
|
else
|
|
args=(/bin/bash -i)
|
|
fi
|
|
|
|
MAVEN_LOCAL_REPO="$HOME/.m2"
|
|
|
|
mkdir -p "$MAVEN_LOCAL_REPO"
|
|
|
|
if [[ -z "$CARGO_HOME" ]]; then
|
|
export CARGO_HOME="$HOME/.cargo"
|
|
mkdir -p "$CARGO_HOME"
|
|
fi
|
|
|
|
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
|
|
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
|
mkdir -p "$XDG_CACHE_HOME"
|
|
mkdir -p "$XDG_CONFIG_HOME"
|
|
|
|
is_podman="$($tool --help | grep -o podman)"
|
|
|
|
docker_common_args=()
|
|
|
|
docker_common_args+=("${SCYLLADB_DBUILD[@]}")
|
|
|
|
if [ -z "$is_podman" ]; then
|
|
unset TMP_PASSWD
|
|
docker_common_args+=(
|
|
-u "$(id -u):$(id -g)"
|
|
"${group_args[@]}"
|
|
-v /etc/passwd:/etc/passwd:ro
|
|
-v /etc/group:/etc/group:ro
|
|
-v /var/run/docker.sock:/var/run/docker.sock
|
|
--pids-limit -1
|
|
)
|
|
fi
|
|
|
|
# --pids-limit is not supported on podman with cgroupsv1
|
|
# detection code from
|
|
# https://unix.stackexchange.com/questions/617764/how-do-i-check-if-system-is-using-cgroupv1
|
|
containers_conf="$(mktemp)"
|
|
tmpfiles+=("$containers_conf")
|
|
cat > "$containers_conf" <<EOF
|
|
[engine]
|
|
static_dir = "$HOME/.local/share/containers/storage/libpod"
|
|
volume_path = "$HOME/.local/share/containers/storage/libpod"
|
|
|
|
[containers]
|
|
# netns = private, the default, doesn't work in nested containers,
|
|
# but we need to use port forwarded networking for our mocks etc.
|
|
netns = "slirp4netns"
|
|
|
|
EOF
|
|
|
|
storage_conf="$(mktemp)"
|
|
tmpfiles+=("$storage_conf")
|
|
cat > "$storage_conf" <<EOF
|
|
|
|
[storage]
|
|
driver = "overlay"
|
|
runroot = "/run/containers/storage"
|
|
graphroot = "$HOME/.local/share/containers/storage"
|
|
|
|
EOF
|
|
|
|
if grep -q 'cgroup2.*/sys/fs/cgroup ' /proc/mounts; then
|
|
docker_common_args+=(
|
|
-v "$HOME/.local/share/containers:$HOME/.local/share/containers"
|
|
-v "$containers_conf:/etc/containers/containers.conf.d/nested.conf"
|
|
-v "$storage_conf:/etc/containers/storage.conf"
|
|
--pids-limit -1
|
|
--annotation run.oci.keep_original_groups=1
|
|
)
|
|
fi
|
|
|
|
# if --pids-limit is not supported, add
|
|
# [containers]
|
|
# pids_limit = 0
|
|
#
|
|
# to /etc/containers/containers.conf
|
|
|
|
|
|
# Forward authentication, to avoid docker hub unauthenticated rate limits.
|
|
for auth_json in "${XDG_RUNTIME_DIR}/containers/auth.json" "${HOME}/.config/containers/auth.json"; do
|
|
if [[ -f "$auth_json" ]]; then
|
|
docker_common_args+=(-v "${auth_json}:${HOME}/.config/containers/auth.json")
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ "$PWD" != "$toplevel" ]; then
|
|
docker_common_args+=(-v "$toplevel:$toplevel")
|
|
fi
|
|
|
|
# podman cannot relabel system directories like /tmp, but it can
|
|
# relable directories we own, so we map a temporary directory to /tmp
|
|
|
|
tmpdir=$(mktemp -d)
|
|
|
|
if [ -e ~/.gdbinit ]; then
|
|
docker_common_args+=(-v "$HOME/.gdbinit:$HOME/.gdbinit:ro")
|
|
fi
|
|
|
|
# By default use "unlimited" as the hard limit
|
|
hard_limit=$(ulimit -Hn)
|
|
if [[ "${OSTYPE}" == "darwin"* ]]; then
|
|
# Docker-on-osx cannot parse "unlimited" as hard limit value, hence set to a high value
|
|
hard_limit=1024000
|
|
fi
|
|
|
|
if [[ -n "$interactive" || -t 0 ]]; then
|
|
docker_common_args+=("--tty")
|
|
fi
|
|
|
|
docker_common_args+=(
|
|
--security-opt seccomp=unconfined \
|
|
--security-opt label=disable \
|
|
--privileged \
|
|
--network host \
|
|
--ulimit nofile=$(ulimit -Sn):$hard_limit \
|
|
-v "$PWD:$PWD" \
|
|
-v "$tmpdir:/tmp" \
|
|
-v "$MAVEN_LOCAL_REPO:$MAVEN_LOCAL_REPO" \
|
|
-v /etc/localtime:/etc/localtime:ro \
|
|
--env CARGO_HOME \
|
|
-v "${CARGO_HOME}:${CARGO_HOME}" \
|
|
--env XDG_CACHE_HOME \
|
|
-v "${XDG_CACHE_HOME}:${XDG_CACHE_HOME}" \
|
|
--env XDG_CONFIG_HOME \
|
|
-v "${XDG_CONFIG_HOME}:${XDG_CONFIG_HOME}" \
|
|
-w "$PWD" \
|
|
-e HOME="$HOME" \
|
|
"${docker_args[@]}" \
|
|
"$image" \
|
|
"${args[@]}"
|
|
)
|
|
cleanup() {
|
|
rm -rf "$tmpdir"
|
|
# don't use `test -v` for MacOS compatibility
|
|
if [ "${TMP_PASSWD+var_is_set}" = "var_is_set" ]; then
|
|
rm -f "$TMP_PASSWD"
|
|
fi
|
|
rm -f "${tmpfiles[@]}"
|
|
}
|
|
|
|
if [[ -n "$interactive" || -n "$is_podman" ]]; then
|
|
# If --interactive was given on the command line, we can't run in detached mode
|
|
# as it will be impossible to interact with the container.
|
|
|
|
# We also avoid detached mode with podman, which doesn't need it
|
|
# (it does not proxy SIGTERM) and doesn't work well with it.
|
|
$tool run --rm "${docker_common_args[@]}"
|
|
ret=$?
|
|
cleanup
|
|
exit $ret
|
|
fi
|
|
|
|
container=$(
|
|
$tool run \
|
|
"--detach=true" \
|
|
"${docker_common_args[@]}"
|
|
)
|
|
|
|
kill_it() {
|
|
if [[ -n "$container" ]]; then
|
|
$tool rm -f "$container" > /dev/null
|
|
container=
|
|
fi
|
|
cleanup
|
|
}
|
|
|
|
trap kill_it SIGTERM SIGINT SIGHUP EXIT
|
|
|
|
$tool logs --follow "$container"
|
|
|
|
if [[ -n "$container" ]]; then
|
|
exitcode="$($tool wait "$container")"
|
|
else
|
|
exitcode=99
|
|
fi
|
|
|
|
kill_it
|
|
|
|
trap - SIGTERM SIGINT SIGHUP EXIT
|
|
|
|
# after "docker kill", docker wait will not print anything
|
|
[[ -z "$exitcode" ]] && exitcode=1
|
|
|
|
exit "$exitcode"
|