kolla-ansible/tools/build-all-docker-images
Martin André 9a5fed6608 Fail image build when build script is missing
When an image did not provide a build script, due to a broken link for
instance, the build-all-docker-images script was wrongly marking the
image as "up-to-date", and the functional gate was reporting success.

This commit restores the expected behavior, and mark the images with
non-existent build scripts as failures.

Change-Id: Ifedc8d9c312925fe5aa953ed8f8fdae02b756906
Closes-Bug: #1460959
2015-06-03 10:22:57 +09:00

234 lines
5.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Depends on bash 4 and gawk
TOPDIR=$(git rev-parse --show-toplevel)
# Work in a temp dir so that developers can continue working while a build is
# in progress
WORKDIR=$(mktemp -d /tmp/kolla-workdir.XXXXXXXXXX)
# Remove $WORKDIR otherwise $TOPDIR is copied *inside* of it
rm -rf $WORKDIR
cp -aL "$TOPDIR" $WORKDIR
DOCKERDIR="$WORKDIR/docker"
declare -A dependency
declare -A img_dirs
declare -A status
function info {
[[ -n $1 ]] && printf "%s\n" "$1"
}
function success {
[[ -n $1 ]] && printf "\033[00;32m%s\033[00m\n" "$1"
}
function warn {
[[ -n $1 ]] && printf "\033[00;31m%s\033[00m\n" "$1"
}
function set_defaults {
PREFIX=centos-rdo-
NAMESPACE=kollaglue
[ -f $WORKDIR/.buildconf ] && . $WORKDIR/.buildconf
}
function has_changed {
local image=$1
# Rebuild everything unless given git revision
# We don't really care about the order of the $FROM and $TO parameters, all
# we need is the list of changed files between the revisions, or HEAD if
# only one of them is specified
[[ -z $FROM && -z $TO ]] || git diff --name-only $FROM $TO | grep -q "${img_dirs[$image]#$WORKDIR/}"
}
function requires_build {
local image=$1
local dep=${dependency[$image]}
# An image requires a built if it meets the following conditions:
# - it has instructions to build the image
# - it hasn't been processed yet
# - its dependency was rebuilt or its build instruction was modified
[[ ${img_dirs[$image]} && -z ${status[$image]} ]] && \
([[ ${status[$dep]} == "rebuilt" ]] || has_changed $image)
}
function build_image {
local dir=$1
printf "\n"
if [ -x "$dir/build" ]; then
info "Building image in $dir"
if $dir/build $ARGS --no-use-released-parent; then
success "Successfully built image in $dir"
status[$image]="rebuilt"
else
warn "Failed to build image in $dir"
status[$image]="fail"
fi
else
warn "Image $image does not provide build script"
status[$image]="fail"
fi
}
function init_image {
local img_dir=$1
set_defaults
[ -f $WORKDIR/.buildconf ] && . $WORKDIR/.buildconf
[ -f $img_dir/.buildconf ] && . $img_dir/.buildconf
[ -n "$FORCE_NAMESPACE" ] && NAMESPACE=$FORCE_NAMESPACE
[ -n "${REGISTRY}" ] && NAMESPACE="${REGISTRY}/${NAMESPACE}"
local image="${NAMESPACE:+${NAMESPACE}/}${PREFIX}${img_dir##*/}"
local base_image=$(cat $img_dir/Dockerfile | gawk 'match($0, /^\s*FROM\s+(\S+)/, matches) {print matches[1]}' )
base_image=${base_image//%%KOLLA_NAMESPACE%%/$NAMESPACE}
base_image=${base_image//%%KOLLA_PREFIX%%/$PREFIX}
base_image=${base_image//:%%KOLLA_TAG%%/}
img_dirs[$image]=$img_dir
dependency[$image]=$base_image
# Restore defaults to minimize risk of side effects
set_defaults
}
function process_image {
local image=$1
if [ -n "${dependency[$image]}" ]; then
process_image ${dependency[$image]}
fi
if requires_build $image; then
build_image ${img_dirs[$image]}
fi
if [ -z "${status[$image]}" ]; then
status[$image]="up-to-date"
fi
}
function print_summary {
printf "\nSummary\n=======\n"
for image in "${!status[@]}"; do
case "${status[$image]}" in
("fail") warn "Failed to process $image" ;;
("rebuilt") success "Rebuilt $image" ;;
(*) info "$image: ${status[$image]}" ;;
esac
done
}
function print_parseable_summary {
printf "{"
for image in "${!status[@]}"; do
printf "'$image':'${status[$image]}',"
done
printf "}"
}
function interrupted {
info "Interrupted..."
print_summary
rm -rf $WORKDIR
exit 1
}
function usage {
read -r -d '' HELP <<EOF
A wrapper to build-docker-image that build all images in order.
Options:
--from <git-revision>
--to <git-revision>
$($WORKDIR/tools/build-docker-image --help)
EOF
printf "%s\n" "${HELP/$WORKDIR\/tools\/build-docker-image/$0}"
}
trap 'interrupted' INT
ARGS=$@
PARSED_ARGS=$(getopt -q -o hr:n:t: -l help,namespace:,release,tag:,private-registry:,from:,to:,testmode -- "$@")
eval set -- "$PARSED_ARGS"
while :; do
case "$1" in
(--help|-h) usage
exit 0
;;
(--namespace|-n)
shift
FORCE_NAMESPACE="$1"
;;
(--release)
RELEASE_SPECIFIED=1
;;
(--tag|-t)
shift
TAG_SPECIFIED=1
;;
(--private-registry|-r)
shift
REGISTRY="$1"
;;
(--from)
shift
FROM="$1"
ARGS=${ARGS/\-\-from*$FROM/}
;;
(--to)
shift
TO="$1"
ARGS=${ARGS/\-\-to*$TO/}
;;
(--testmode)
TESTMODE=1
ARGS=${ARGS/\-\-testmode/}
;;
(--) break
;;
esac
shift
done
set_defaults
# BASE == centos, fedora, ubuntu, etc.
BASE=$(echo "${PREFIX}" | cut -d- -f1)
# TYPE == binary, source, rdo
TYPE=$(echo "${PREFIX}" | cut -d- -f2)
# Ensure a tag is specified otherwise build may fail when changing git branch
# The release tag is automatically appended when --release flag is used.
if [[ $RELEASE_SPECIFIED != 1 ]] && [[ $TAG_SPECIFIED != 1 ]]; then
TAG=$(git rev-parse --short HEAD)
ARGS+=" --tag $TAG"
fi
# Do a first pass to find images to build and their dependencies
for dockerfile in $(find "${DOCKERDIR}/${BASE}/${TYPE}" -name Dockerfile); do
init_image $(dirname $dockerfile)
done
# Process all images
for image in "${!img_dirs[@]}"; do
process_image $image
done
print_summary
[ -n "$TESTMODE" ] && print_parseable_summary
rm -rf $WORKDIR