blob: f7b968deb60fa38d99d913cf5a178978268406fb [file] [log] [blame]
#!/usr/bin/env bash
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
DOCKERMODE=false
DOCKERCMD=$(command -v docker 2>/dev/null)
DOCKER_ID=${RANDOM}
DOCKER_DESTRUCTIVE=true
DOCKERFILE_DEFAULT="${BINDIR}/test-patch-docker/Dockerfile"
DOCKERSUPPORT=false
DOCKER_ENABLE_PRIVILEGED=false
DOCKER_CLEANUP_CMD=false
DOCKER_MEMORY="4g"
DOCKER_PLATFORM=""
DOCKER_TAG=""
DOCKER_IN_DOCKER=false
DOCKER_SOCKET="/var/run/docker.sock"
DOCKER_SOCKET_GID=-1
DOCKER_WORK_DIR="/precommit"
declare -a DOCKER_EXTRAARGS
declare -a DOCKER_VERSION
DOCKER_EXTRAENVS+=("JAVA_HOME")
DOCKER_EXTRAENVS+=("PATCH_SYSTEM")
DOCKER_EXTRAENVS+=("PROJECT_NAME")
YETUS_DOCKER_BASH_DEBUG=false
####
#### IMPORTANT
####
#### If these times are updated, the documentation needs to
#### be changed too!
# created, stopped, exited, running, for 24 hours
DOCKER_CONTAINER_PURGE=("86400" "86400" "86400" "86400" )
# keep images for 1 week
DOCKER_IMAGE_PURGE=604800
## @description Docker-specific usage
## @stability stable
## @audience private
## @replaceable no
function docker_usage
{
if [[ "${DOCKER_CLEANUP_CMD}" == false ]]; then
yetus_add_option "--docker" "Spawn a docker container"
fi
yetus_add_option "--dockercmd=<file>" "Command to use as docker executable (default: '${DOCKERCMD}')"
if [[ "${DOCKER_CLEANUP_CMD}" == false ]]; then
yetus_add_option "--docker-bash-debug=<bool>" "Enable bash -x mode running in a container (default: ${YETUS_DOCKER_BASH_DEBUG})"
yetus_add_option "--docker-cache-from=<image>" "Comma delimited images to use as a cache when building"
yetus_add_option "--dockerfile=<file>" "Dockerfile fragment to use as the base (default: '${DOCKERFILE_DEFAULT}')"
yetus_add_option "--dockerind=<bool>" "Enable Docker-in-Docker by mounting the Docker socket in the container (default: '${DOCKER_IN_DOCKER}')"
yetus_add_option "--docker-platform=<plat>" "Use a platform string for building and pulling (default: ${DOCKER_PLATFORM})"
yetus_add_option "--dockerprivd=<bool>" "Run docker in privileged mode (default: '${DOCKER_ENABLE_PRIVILEGED}')"
yetus_add_option "--docker-socket=<socket>" "Mount given socket as /var/run/docker.sock into the container when Docker-in-Docker mode is enabled (default: '${DOCKER_SOCKET}')"
yetus_add_option "--docker-tag=<tag>" "Use the given Docker tag as the base"
yetus_add_option "--docker-work-dir=<directory>" "Disposable, safe dir for precommit work (default: ${DOCKER_WORK_DIR}"
fi
yetus_add_option "--dockerdelrep" "In Docker mode, only report image/container deletions, not act on them"
if [[ "${DOCKER_CLEANUP_CMD}" == false ]]; then
yetus_add_option "--dockermemlimit=<num>" "Limit a Docker container's memory usage (default: ${DOCKER_MEMORY})"
fi
}
## @description Docker-specific argument parsing
## @stability stable
## @audience private
## @replaceable no
## @params arguments
function docker_parse_args
{
declare i
for i in "$@"; do
case ${i} in
--docker)
DOCKERSUPPORT=true
;;
--docker-bash-debug=*)
YETUS_DOCKER_BASH_DEBUG=${i#*=}
add_docker_env YETUS_DOCKER_BASH_DEBUG
;;
--docker-cache-from=*)
DOCKER_CACHE_FROM=${i#*=}
;;
--dockercmd=*)
#shellcheck disable=SC2034
DOCKERCMD=${i#*=}
;;
--dockerdelrep)
DOCKER_DESTRUCTIVE=false
;;
--dockerfile=*)
DOCKERFILE=${i#*=}
;;
--dockerind=*)
DOCKER_IN_DOCKER=${i#*=}
;;
--dockermemlimit=*)
DOCKER_MEMORY=${i#*=}
;;
--dockermode)
DOCKERMODE=true
;;
--docker-platform=*)
DOCKER_PLATFORM=${i#*=}
;;
--dockerprivd=*)
DOCKER_ENABLE_PRIVILEGED=${i#*=}
;;
--docker-socket=*)
DOCKER_SOCKET=${i#*=}
;;
--docker-tag=*)
DOCKER_TAG=${i#*=}
;;
--docker-work-dir=*)
DOCKER_TAG=${i#*=}
;;
esac
done
}
## @description Docker initialization pre- and post- re-exec
## @stability stable
## @audience private
## @replaceable no
function docker_initialize
{
declare dockvers
declare -a footer
# --docker and --dockermode are mutually
# exclusive. --docker is used by the user to
# re-exec test-patch in Docker mode.
# --dockermode is used by launch-test-patch (which is
# run as the Docker EXEC in the Dockerfile,
# see elsewhere for more info) to tell test-patch that
# it has been restarted already. launch-test-patch
# also strips --docker from the command line so that we
# don't end up in a loop if the docker image
# also has the docker command in it
# we are already in docker mode
if [[ "${DOCKERMODE}" == true ]]; then
# DOCKER_VERSION_STR is set by our creator.
footer=("${DOCKER_VERSION_STR}")
if [[ -n "${DOCKERFROM}" ]]; then
footer+=("base:" "${DOCKERFROM}")
elif [[ -f "${PATCH_DIR}/Dockerfile" ]]; then
footer+=("base:" "@@BASE@@/Dockerfile")
fi
if [[ -n "${DOCKER_PLATFORM}" ]]; then
footer+=("platform:" "${DOCKER_PLATFORM}")
fi
add_footer_table "Docker" "${footer[*]}"
return
fi
# docker mode hasn't been requested
if [[ "${DOCKERSUPPORT}" != true ]]; then
return
fi
dockvers=$(docker_version Client)
IFS='.' read -r -a DOCKER_VERSION <<< "${dockvers}"
if [[ "${DOCKER_VERSION[0]}" -lt 17 ]]; then
add_vote_table -1 docker "Docker command '${DOCKERCMD}' is too old (${dockvers} < 17.0)."
bugsystem_finalreport 1
cleanup_and_exit 1
fi
# stat is non-POSIX but one of two forms is generally
# present on a machine. See also precommit-docker.md docs.
if [[ "${OSTYPE}" == "Darwin" ]]; then
# At the user level, OS X lies about the permissions on the
# socket due to the VM-layer that is present.
DOCKER_SOCKET_GID=0
elif "${STAT}" -c '%g' "${DOCKER_SOCKET}" >/dev/null 2>&1; then
DOCKER_SOCKET_GID=$("${STAT}" -c '%g' "${DOCKER_SOCKET}")
elif "${STAT}" -f '%g' "${DOCKER_SOCKET}" >/dev/null 2>&1; then
DOCKER_SOCKET_GID=$("${STAT}" -f '%g' "${DOCKER_SOCKET}")
elif [[ ${DOCKER_IN_DOCKER} == true ]]; then
add_vote_table -1 docker "Docker-in-Docker mode (--dockerind) requires a working stat command."
bugsystem_finalreport 1
cleanup_and_exit 1
fi
}
## @description Verify dockerfile exists
## @audience private
## @stability evolving
## @replaceable no
## @return exits on failure if configured
function docker_fileverify
{
if [[ ${DOCKERMODE} = false &&
${DOCKERSUPPORT} = true ]]; then
if [[ -n "${DOCKERFILE}" ]]; then
pushd "${STARTINGDIR}" >/dev/null || return 1
if [[ -f ${DOCKERFILE} ]]; then
DOCKERFILE=$(yetus_abs "${DOCKERFILE}")
else
yetus_error "ERROR: Dockerfile '${DOCKERFILE}' not found."
add_vote_table -1 docker "Dockerfile '${DOCKERFILE}' not found."
bugsystem_finalreport 1
cleanup_and_exit 1
fi
popd >/dev/null || return 1
elif [[ -n "${DOCKER_TAG}" ]]; then
# do this later as part of the docker handler
:
else
if [[ -n "${DOCKER_PLATFORM}" ]]; then
dockplat=('--platform' "${DOCKER_PLATFORM}")
fi
echo "No --dockerfile or --dockertag provided. Attempting to pull apache/yetus:${VERSION}."
if dockercmd pull "${dockplat[@]}" "apache/yetus:${VERSION}"; then
echo "Pull succeeded; will build with pulled image."
DOCKER_TAG="apache/yetus:${VERSION}"
else
echo "Pull failed; will build with built-in Dockerfile."
DOCKERFILE=${DOCKERFILE_DEFAULT}
fi
fi
fi
}
## @description Verify docker exists
## @audience private
## @stability evolving
## @replaceable no
## @return 1 if docker is broken
## @return 0 if docker is working
function docker_exeverify
{
if ! verify_command "Docker" "${DOCKERCMD}"; then
return 1
fi
if ! ${DOCKERCMD} info >/dev/null 2>&1; then
yetus_error "Docker is not functioning properly. Daemon down/unreachable?"
return 1
fi
return 0
}
## @description Run docker with some arguments, and
## @description optionally send to debug.
## @description some destructive commands require
## @description DOCKER_DESTRUCTIVE to be set to true
## @audience private
## @stability evolving
## @replaceable no
## @param args
function dockercmd
{
declare subcmd=$1
shift
yetus_debug "dockercmd: ${DOCKERCMD} ${subcmd} $*"
if [[ ${subcmd} == rm
|| ${subcmd} == rmi
|| ${subcmd} == stop
|| ${subcmd} == kill ]]; then
if [[ "${DOCKER_DESTRUCTIVE}" == false ]]; then
yetus_error "Safemode: not running ${DOCKERCMD} ${subcmd} $*"
return
fi
fi
"${DOCKERCMD}" "${subcmd}" "$@"
}
## @description Convet docker's time format to ctime
## @audience private
## @stability evolving
## @replaceable no
## @param time
function dockerdate_to_ctime
{
declare mytime=$1
if [[ "${mytime}" = "0001-01-01T00:00:00Z" ]]; then
mytime="1970-01-01T00:00:00"
fi
# believe it or not, date is not even close to standardized...
if [[ $(uname -s) == Linux ]]; then
# GNU date
date -d "${mytime}" "+%s"
else
# BSD date; go/docker gives us two different format because fun
if ! date -j -f "%FT%T%z" "${mytime}" "+%s" 2>/dev/null; then
date -j -f "%FT%T" "${mytime}" "+%s"
fi
fi
}
## @description Stop and delete all defunct containers
## @audience private
## @stability evolving
## @replaceable no
function docker_container_maintenance
{
declare line
declare id
declare name
declare status
declare tmptime
declare createtime
declare starttime
declare stoptime
declare remove
declare difftime
declare data
if [[ "${ROBOT}" = false ]]; then
return
fi
big_console_header "Docker Container Maintenance"
dockercmd ps -a
data=$(dockercmd ps -qa)
if [[ -z "${data}" ]]; then
return
fi
while read -r line; do
id=$(echo "${line}" | cut -f1 -d, )
status=$(echo "${line}" | cut -f2 -d, )
tmptime=$(echo "${line}" | cut -f3 -d, | cut -f1 -d. )
createtime=$(dockerdate_to_ctime "${tmptime}")
tmptime=$(echo "${line}" | cut -f4 -d, | cut -f1 -d. )
starttime=$(dockerdate_to_ctime "${tmptime}")
tmptime=$(echo "${line}" | cut -f5 -d, | cut -f1 -d. )
stoptime=$(dockerdate_to_ctime "${tmptime}")
name=$(echo "${line}" | cut -f6 -d, )
curtime=$("${AWK}" 'BEGIN {srand(); print srand()}')
remove=false
case ${status} in
created)
((difftime = curtime - createtime))
if [[ ${difftime} -gt ${DOCKER_CONTAINER_PURGE[0]} ]]; then
remove=true
fi
;;
stopped)
((difftime = curtime - stoptime))
if [[ ${difftime} -gt ${DOCKER_CONTAINER_PURGE[1]} ]]; then
remove=true
fi
;;
exited | dead)
((difftime = curtime - stoptime))
if [[ ${difftime} -gt ${DOCKER_CONTAINER_PURGE[2]} ]]; then
remove=true
fi
;;
running)
((difftime = curtime - starttime))
if [[ ${difftime} -gt ${DOCKER_CONTAINER_PURGE[3]}
&& "${SENTINEL}" = true ]]; then
remove=true
echo "Attempting to kill docker container ${name} [${id}]"
dockercmd kill "${id}"
fi
;;
*)
;;
esac
if [[ "${remove}" == true ]]; then
echo "Attempting to remove docker container ${name} [${id}]"
dockercmd rm "${id}"
fi
done < <(
# shellcheck disable=SC2086
dockercmd container inspect \
--format '{{.Id}},{{.State.Status}},{{.Created}},{{.State.StartedAt}},{{.State.FinishedAt}},{{.Name}}' \
${data})
}
## @description Untag docker images for a given id
## @audience private
## @stability evolving
## @replaceable no
## @param imageid
function docker_untag_images
{
declare id=$1
declare i
declare imagestr
declare -a images
# ["image1","image2","image3"]
imagestr=$(dockercmd inspect -f '{{json .RepoTags}}' "${id}")
imagestr=${imagestr#"["}
imagestr=${imagestr%"]"}
imagestr=${imagestr//\"}
yetus_comma_to_array images "${imagestr}"
for i in "${images[@]}"; do
if dockercmd inspect -f '{{json .Size}}' "${i}" >/dev/null 2>&1;then
dockercmd rmi "${i}"
fi
done
}
## @description Delete images after ${DOCKER_IMAGE_PURGE}
## @audience private
## @stability evolving
## @replaceable no
function docker_image_maintenance_helper
{
declare id
declare tmptime
declare createtime
declare difftime
declare name
if [[ "${ROBOT}" = false ]]; then
return
fi
if [[ -z "$*" ]]; then
return
fi
for id in "$@"; do
tmptime=$(dockercmd image inspect --format '{{.Created}}' "${id}" | cut -f1 -d. )
createtime=$(dockerdate_to_ctime "${tmptime}")
curtime=$(date "+%s")
((difftime = curtime - createtime))
if [[ ${difftime} -gt ${DOCKER_IMAGE_PURGE} ]]; then
echo "Attempting to remove docker image ${id}"
docker_untag_images "${id}"
if dockercmd inspect -f '{{json .Size}}' "${id}" >/dev/null 2>&1;then
dockercmd rmi "${id}"
fi
fi
done
}
## @description get sentinel-level docker images
## @audience private
## @stability evolving
## @replaceable no
## @param args
function docker_get_sentinel_images
{
#shellcheck disable=SC2016
dockercmd images \
| tail -n +2 \
| "${GREP}" -v hours \
| "${AWK}" '{print $3}'
}
## @description Remove untagged/unused images
## @audience private
## @stability evolving
## @replaceable no
## @param args
function docker_image_maintenance
{
declare id
if [[ "${ROBOT}" = false ]]; then
return
fi
big_console_header "Removing old images"
dockercmd images
echo "Untagged images:"
#shellcheck disable=SC2046
docker_image_maintenance_helper $(dockercmd images --filter "dangling=true" -q --no-trunc)
echo "Apache Yetus images:"
#shellcheck disable=SC2046
docker_image_maintenance_helper $(dockercmd images --filter "label=org.apache.yetus" -q --no-trunc)
if [[ "${SENTINEL}" = false ]]; then
return
fi
echo "Other images:"
#shellcheck disable=SC2046
docker_image_maintenance_helper $(docker_get_sentinel_images)
}
## @description Perform pre-run maintenance to free up
## @description resources. With --jenkins, it is a lot
## @description more destructive.
## @audience private
## @stability evolving
## @replaceable no
## @param args
function docker_cleanup
{
docker_image_maintenance
docker_container_maintenance
}
## @description determine the docker version
## @stability stable
## @audience private
## @replaceable no
function docker_version
{
declare vertype=$1
declare val
declare ret
# new version command
val=$(dockercmd version --format "{{.${vertype}.Version}}" 2>/dev/null)
ret=$?
if [[ ${ret} != 0 ]];then
# old version command
val=$(dockercmd version | ${GREP} "${vertype} version" | cut -f2 -d: | tr -d ' ')
fi
echo "${val}"
}
## @description Queue env vars to add to the docker env
## @audience public
## @stability stable
## @replaceable yes
## @param envname
## @param ...
function add_docker_env
{
for k in "$@"; do
DOCKER_EXTRAENVS+=("${k}")
done
}
## @description Do the work to add the env vars onto the Docker cmd
## @audience private
## @stability stable
## @replaceable yes
function docker_do_env_adds
{
declare k
for k in "${DOCKER_EXTRAENVS[@]}"; do
DOCKER_EXTRAARGS+=("--env=${k}=${!k}")
done
}
## @description Start a test patch docker container
## @audience private
## @stability evolving
## @replaceable no
## @param args
function docker_run_image
{
declare gitfilerev
declare baseimagename
declare patchimagename="yetus/${PROJECT_NAME}:tp-${DOCKER_ID}"
declare containername="yetus_tp-${DOCKER_ID}"
declare client
declare server
declare retval
declare elapsed
declare dockerdir
declare lines
declare dockerversion
declare -a dockplat
declare -a cachefrom
declare -a images
big_console_header "Docker Image Creation"
start_clock
if [[ -n "${DOCKER_PLATFORM}" ]]; then
dockplat=('--platform' "${DOCKER_PLATFORM}")
fi
if [[ -n "${DOCKER_TAG}" ]]; then
# pull the base image from the provided docker tag
if ! dockercmd pull "${dockplat[@]}" "${DOCKER_TAG}"; then
yetus_error "ERROR: Docker failed to pull ${DOCKER_TAG}."
add_vote_table -1 docker "Docker failed to pull ${DOCKER_TAG}."
bugsystem_finalreport 1
cleanup_and_exit 1
fi
baseimagename=${DOCKER_TAG}
elif [[ -n ${DOCKERFILE} && -f ${DOCKERFILE} ]]; then
# make a base image. if it is available/cached, this will go quick
dockerdir=$(dirname "${DOCKERFILE}")
pushd "${dockerdir}" >/dev/null || return 1
# grab the git commit sha if this is part of a git repo, even if
# it is part of another git repo other than the one being tested!
gitfilerev=$("${GIT}" log -n 1 --pretty=format:%h -- "${DOCKERFILE}" 2>/dev/null)
if [[ -z ${gitfilerev} ]]; then
gitfilerev=$(date "+%F")
gitfilerev="date${gitfilerev}"
fi
# we will need this for reporting later
baseimagename="yetus/${PROJECT_NAME}:${gitfilerev}"
# create a new Dockerfile in the patchdir to actually use to
# build with, stripping everything after the cut here line
# (if it exists)
lines=$("${AWK}" '/YETUS CUT HERE/ {print FNR; exit}' "${DOCKERFILE}")
buildfile="${PATCH_DIR}/Dockerfile"
if [[ "${DOCKER_VERSION[0]}" -lt 18 ]] && [[ ${lines} -gt 0 ]]; then
# versions less than 18 don't support having the
# Dockerfile outside of the build context. Let's fall back to
# pre-YETUS-723 behavior and put the re-written Dockerfile
# outside of the source tree rather than go through a lot of
# machinations. This means COPY, ADD, etc do not work, but
# whatever
popd >/dev/null || return 1
buildfile="${PATCH_DIR}/test-patch-docker/Dockerfile"
dockerdir="${PATCH_DIR}/test-patch-docker"
mkdir -p "${dockerdir}"
pushd "${PATCH_DIR}/test-patch-docker" >/dev/null || return 1
fi
(
if [[ -z "${lines}" ]]; then
cat "${DOCKERFILE}"
else
head -n "${lines}" "${DOCKERFILE}"
fi
) > "${buildfile}"
if [[ "${DOCKER_VERSION[0]}" -lt 18 ]] && [[ ${lines} -gt 0 ]]; then
# Need to put our re-constructed Dockerfile in a place
# where it can be referenced in the output post-run
cp -p "${buildfile}" "${PATCH_DIR}/Dockerfile"
fi
if [[ -n "${DOCKER_CACHE_FROM}" ]]; then
yetus_comma_to_array images "${DOCKER_CACHE_FROM}"
for i in "${images[@]}"; do
docker pull "${i}" || true
done
cachefrom=("--cache-from=yetus/${PROJECT_NAME}:${gitfilerev},${DOCKER_CACHE_FROM}")
fi
if ! dockercmd build \
"${dockplat[@]}" \
"${cachefrom[@]}" \
--label org.apache.yetus=\"\" \
--label org.apache.yetus.testpatch.project="${PROJECT_NAME}" \
--tag "${baseimagename}" \
-f "${buildfile}" \
"${dockerdir}"; then
popd >/dev/null || return 1
yetus_error "ERROR: Docker failed to build ${baseimagename}."
add_vote_table -1 docker "Docker failed to build ${baseimagename}."
bugsystem_finalreport 1
cleanup_and_exit 1
fi
popd >/dev/null || return 1
fi
echo "Building run-specific image ${patchimagename}"
# create a directory from scratch so that our
# build context is tightly controlled
randir=${PATCH_DIR}/${RANDOM}
mkdir -p "${randir}"
pushd "${randir}" >/dev/null || return 1
cp -p "${BINDIR}"/test-patch-docker/Dockerfile.patchspecific \
"${randir}"/Dockerfile
cp -p "${BINDIR}"/test-patch-docker/launch-test-patch.sh \
"${randir}"
for lines in "${USER_PARAMS[@]}"; do
if [[ ${lines} != '--docker' ]]; then
echo "${lines}" >> "${randir}/user_params.txt"
fi
done
add_docker_env DOCKER_WORK_DIR
# using the base image, make one that is patch specific
dockercmd build \
"${dockplat[@]}" \
--no-cache \
--build-arg baseimagename="${baseimagename}" \
--build-arg GROUP_ID="${GROUP_ID}" \
--build-arg USER_ID="${USER_ID}" \
--build-arg USER_NAME="${USER_NAME}" \
--build-arg DOCKER_SOCKET_GID="${DOCKER_SOCKET_GID}" \
--build-arg DOCKER_WORK_DIR="${DOCKER_WORK_DIR}" \
--label org.apache.yetus=\"\" \
--label org.apache.yetus.testpatch.patch="tp-${DOCKER_ID}" \
--label org.apache.yetus.testpatch.project="${PROJECT_NAME}" \
--tag "${patchimagename}" \
"${randir}" >/dev/null
retval=$?
popd >/dev/null || retun 1
rm -rf "${randir}"
if [[ ${retval} != 0 ]]; then
yetus_error "ERROR: Docker failed to build run-specific ${patchimagename}."
add_vote_table -1 docker "Docker failed to build run-specific ${patchimagename}}."
bugsystem_finalreport 1
cleanup_and_exit 1
fi
#shellcheck disable=SC2046
elapsed=$(clock_display $(stop_clock))
echo ""
echo "Total elapsed build time: ${elapsed}"
echo ""
if [[ "${DOCKER_ENABLE_PRIVILEGED}" = true ]]; then
DOCKER_EXTRAARGS+=("--privileged")
fi
if [[ -n "${DOCKER_MEMORY}" ]]; then
DOCKER_EXTRAARGS+=("-m" "${DOCKER_MEMORY}")
fi
client=$(docker_version Client)
server=$(docker_version Server)
dockerversion="Client=${client} Server=${server}"
# make the kernel prefer to kill us if we run out of RAM
DOCKER_EXTRAARGS+=("--oom-score-adj" "500")
DOCKER_EXTRAARGS+=("--cidfile=${PATCH_DIR}/cidfile.txt")
if [[ "${DOCKER_IN_DOCKER}" == true ]]; then
if [[ -e "${DOCKER_SOCKET}" ]]; then
DOCKER_EXTRAARGS+=(-v "${DOCKER_SOCKET}:/var/run/docker.sock")
fi
fi
DOCKER_EXTRAARGS+=(-v "${BASEDIR}:${BASEDIR}")
DOCKER_EXTRAARGS+=(-u "${USER_NAME}")
DOCKER_EXTRAARGS+=(-w "${BASEDIR}")
DOCKER_EXTRAARGS+=("--env=BASEDIR=${BASEDIR}")
DOCKER_EXTRAARGS+=("--env=DOCKER_VERSION_STR=${dockerversion}")
docker_do_env_adds
DOCKER_EXTRAARGS+=(--name "${containername}")
trap 'docker_signal_handler' SIGTERM SIGINT SIGHUP
if [[ ${PATCH_DIR} =~ ^/ ]]; then
dockercmd run --rm=true -i \
"${dockplat[@]}" \
"${DOCKER_EXTRAARGS[@]}" \
-v "${PATCH_DIR}:${PATCH_DIR}" \
--env=PATCH_DIR="${PATCH_DIR}" \
"${patchimagename}" &
else
dockercmd run --rm=true -i \
"${dockplat[@]}" \
"${DOCKER_EXTRAARGS[@]}" \
--env=PATCH_DIR="${PATCH_DIR}" \
"${patchimagename}" &
fi
wait ${!}
retval=$?
printf '\n\n'
echo "Cleaning up docker image used for testing."
dockercmd rmi "${patchimagename}" > /dev/null
rm "${PATCH_DIR}/cidfile.txt"
cleanup_and_exit ${retval}
}
## @description docker kill the container on SIGTERM
## @audience private
## @stability evolving
## @replaceable no
function docker_signal_handler
{
declare cid
cid=$(cat "${PATCH_DIR}/cidfile.txt")
yetus_error "ERROR: Caught signal. Killing docker container:"
echo "ERROR: Caught signal. Killing docker container: ${cid}" > "${PATCH_DIR}/signal.log"
dockercmd kill "${cid}" | tee -a "${PATCH_DIR}/signal.log"
rm "${PATCH_DIR}/cidfile.txt"
yetus_error "ERROR: Exiting."
cleanup_and_exit 143 # 128 + 15 -- SIGTERM
}
## @description Switch over to a Docker container
## @audience private
## @stability evolving
## @replaceable no
## @param args
function docker_handler
{
declare plugin
declare person
## @description strip paths for display
## @audience private
## @stability evolving
function strippaths {
declare p=$1
declare d
for d in "${BASEDIR}" "${PATCH_DIR}" "${BINDIR}"; do
p=$(yetus_relative_dir "${d}" "${p}")
done
echo "${p}"
}
determine_user
# need to call this explicitly
console_docker_support
for plugin in ${PROJECT_NAME} ${BUILDTOOL} "${BUGSYSTEMS[@]}" "${TESTTYPES[@]}" "${TESTFORMATS[@]}"; do
if declare -f "${plugin}_docker_support" >/dev/null; then
"${plugin}_docker_support"
fi
done
if [[ -n "${BUILD_URL}" ]]; then
USER_PARAMS+=("--build-url=${BUILD_URL}")
fi
if [[ -f "${PERSONALITY}" ]]; then
person=$(strippaths "${PERSONALITY}")
USER_PARAMS+=("--tpperson=${person}")
fi
USER_PARAMS+=("--tpglobaltimer=${GLOBALTIMER}")
USER_PARAMS+=("--tpreexectimer=${TIMER}")
USER_PARAMS+=("--tpinstance=${INSTANCE}")
USER_PARAMS+=("--plugins=${ENABLED_PLUGINS// /,}")
#shellcheck disable=SC2164
cd "${BASEDIR}"
PATCH_DIR=$(yetus_relative_dir "${BASEDIR}" "${PATCH_DIR}")
docker_cleanup
docker_run_image
}