Fix "docker-build.sh" wrapper to handle images with ONBUILD instructions more automatically

The way we handle this semi-gracefully is to create a fake "docker save" tarball that contains just a single layer whose parent is the image we're wanting to test, and whose "config" is the same as the parent image, but with "OnBuild" nulled out, and adjust the build to use that new layer as the base for the build instead.
This commit is contained in:
Tianon Gravi 2015-11-12 16:13:31 -08:00
parent 32c3a0b1b8
commit c16b7e1cc2
7 changed files with 76 additions and 8 deletions

View File

@ -3,11 +3,11 @@ set -e
# wrapper around "docker build" that creates a temporary directory and copies files into it first so that arbitrary host directories can be copied into containers without bind mounts, but accepts a Dockerfile on stdin
# usage: ./docker-build.sh some-host-directory -t some-new-image:some-tag <<EOD
# usage: ./docker-build.sh some-host-directory some-new-image:some-tag <<EOD
# FROM ...
# COPY dir/... /.../
# EOD
# ie: ./docker-build.sh .../hylang-hello-world -t librarytest/hylang <<EOD
# ie: ./docker-build.sh .../hylang-hello-world librarytest/hylang <<EOD
# FROM hylang
# COPY dir/container.hy /dir/
# CMD ["hy", "/dir/container.hy"]
@ -16,9 +16,24 @@ set -e
dir="$1"; shift
[ -d "$dir" ]
imageTag="$1"; shift
tmp="$(mktemp -t -d docker-library-test-build-XXXXXXXXXX)"
trap "rm -rf '$tmp'" EXIT
cat > "$tmp/Dockerfile"
from="$(awk -F '[[:space:]]+' 'toupper($1) == "FROM" { print $2; exit }' "$tmp/Dockerfile")"
onbuilds="$(docker inspect -f '{{len .Config.OnBuild}}' "$from")"
if [ "$onbuilds" -gt 0 ]; then
# crap, the image we want to build has some ONBUILD instructions
# those are kind of going to ruin our day
# let's do some hacks to strip those bad boys out in a new fake layer
"$(dirname "$(readlink -f "$BASH_SOURCE")")/remove-onbuild.sh" "$from" "$imageTag"
awk -F '[[:space:]]+' 'toupper($1) == "FROM" { $2 = "'"$imageTag"'" } { print }' "$tmp/Dockerfile" > "$tmp/Dockerfile.new"
mv "$tmp/Dockerfile.new" "$tmp/Dockerfile"
fi
cp -a "$dir" "$tmp/dir"
docker build "$@" "$tmp" > /dev/null
docker build -t "$imageTag" "$tmp" > /dev/null

View File

@ -13,7 +13,7 @@ clientImage="$image"
# Create an instance of the container-under-test
serverImage="$("$dir/../image-name.sh" librarytest/jetty-hello-web "$image")"
"$dir/../docker-build.sh" "$dir" -t "$serverImage" <<EOD
"$dir/../docker-build.sh" "$dir" "$serverImage" <<EOD
FROM $image
COPY dir/index.jsp /var/lib/jetty/webapps/ROOT/
EOD

View File

@ -6,7 +6,7 @@ dir="$(dirname "$(readlink -f "$BASH_SOURCE")")"
image="$1"
serverImage="$("$dir/../image-name.sh" librarytest/mysql-initdb "$image")"
"$dir/../docker-build.sh" "$dir" -t "$serverImage" <<EOD
"$dir/../docker-build.sh" "$dir" "$serverImage" <<EOD
FROM $image
COPY dir/initdb.sql /docker-entrypoint-initdb.d/
EOD

View File

@ -17,7 +17,7 @@ ENTRYPOINT ["cgi-fcgi"]
EOF
serverImage="$("$dir/../image-name.sh" librarytest/php-fpm-hello-web "$image")"
"$dir/../docker-build.sh" "$dir" -t "$serverImage" <<EOD
"$dir/../docker-build.sh" "$dir" "$serverImage" <<EOD
FROM $image
COPY dir/index.php /var/www/html/
EOD

View File

@ -6,7 +6,7 @@ dir="$(dirname "$(readlink -f "$BASH_SOURCE")")"
image="$1"
serverImage="$("$dir/../image-name.sh" librarytest/postgres-initdb "$image")"
"$dir/../docker-build.sh" "$dir" -t "$serverImage" <<EOD
"$dir/../docker-build.sh" "$dir" "$serverImage" <<EOD
FROM $image
COPY dir/initdb.sql /docker-entrypoint-initdb.d/
EOD

53
test/tests/remove-onbuild.sh Executable file
View File

@ -0,0 +1,53 @@
#!/bin/bash
set -e
# do some hacks to strip out onbuilds in a new faked layer
# usage: ./remove-onbuild.sh input-image output-image
# ie: ./remove-onbuild.sh rails:onbuild librarytest/rails-onbuild-without-onbuild
in="$1"; shift
out="$1"; shift
outImage="${out%%:*}"
outTag="${out#*:}"
[ "$outImage" != "$outTag" ] || outTag='latest'
tmp="$(mktemp -t -d docker-library-test-remove-onbuild-XXXXXXXXXX)"
trap "rm -rf '$tmp'" EXIT
declare -A json=(
[Size]=0
)
declare -A mappings=(
[parent]='.Id'
[created]='.Created'
[container]='.Container'
[container_config]='.ContainerConfig'
[config]='.Config'
[docker_version]='.DockerVersion'
[architecture]='.Architecture'
[os]='.Os'
)
for key in "${!mappings[@]}"; do
val="$(docker inspect -f '{{json '"${mappings[$key]}"'}}' "$in")"
json["$key"]="$val"
done
onbuildConfig="$(docker inspect -f '{{json .Config.OnBuild}}' "$in" | sed 's/[]\/$*.^|[]/\\&/g')" # pre-escaped for use within "sed"
json[config]="$(echo "${json[config]}" | sed -r "s/$onbuildConfig/null/g")" # grab the image config, but scrub the onbuilds
jsonString='{'
first=1
for key in "${!json[@]}"; do
[ "$first" ] || jsonString+=','
first=
jsonString+='"'"$key"'":'"${json[$key]}"
done
newId="$(echo "$jsonString" | sha256sum | cut -d' ' -f1)" # lol, this is hacky
jsonString+=',"id":"'"$newId"'"}'
mkdir -p "$tmp/$newId"
echo "$jsonString" > "$tmp/$newId/json"
echo -n '1.0' > "$tmp/$newId/VERSION"
dd if=/dev/zero of="$tmp/$newId/layer.tar" bs=1k count=1 &> /dev/null # empty tar file
cat > "$tmp/repositories" <<EOF
{"$outImage":{"$outTag":"$newId"}}
EOF
tar -cC "$tmp" . | docker load

View File

@ -22,7 +22,7 @@ workdir="$containerMount/$testBase"
# TODO should we be doing something fancy with $BASH_SOURCE instead so we can be arbitrarily deep and mount the top level always?
newImage="$("$thisDir/image-name.sh" librarytest/run-in-container "$image--$testBase")"
"$thisDir/docker-build.sh" "$hostMount" -t "$newImage" <<EOD
"$thisDir/docker-build.sh" "$hostMount" "$newImage" <<EOD
FROM $image
COPY dir $containerMount
WORKDIR $workdir