The latest fixes and enhancenments from upstream

This commit is contained in:
Lumir Balhar 2020-02-05 13:31:25 +01:00
commit 1425f4c95f
5 changed files with 255 additions and 142 deletions

View file

@ -41,6 +41,13 @@ mv /tmp/src/* "$HOME"
# set permissions for any installed artifacts
fix-permissions /opt/app-root -P
# We have to first upgrade pip to at least 19.3 because:
# * pip < 9 does not support different packages' versions for Python 2/3
# * pip < 19.3 does not support manylinux2014 wheels. Only manylinux2014 wheels
# support platforms like ppc64le, aarch64 or armv7
echo "---> Upgrading pip to version 19.3.1 ..."
pip install -U "pip==19.3.1"
if [[ ! -z "$UPGRADE_PIP_TO_LATEST" ]]; then
echo "---> Upgrading pip to latest version ..."
pip install -U pip setuptools wheel

View file

@ -2,23 +2,6 @@
# Test virtualenv environment and pip upgrade
# Get the latest stable version of the package released on PyPI
function get_latest_stable_version() {
echo $(curl -sL 'https://pypi.org/pypi/'$1'/json' | python -c \
"""
import sys
import json
from pip._vendor.packaging.version import parse
versions = [parse(v) for v in json.load(sys.stdin)['releases'].keys()]
print(str((sorted([v for v in versions if not v.is_prerelease])[-1])))
""")
}
# Get version of the package installed on the system
function get_installed_version() {
echo $(pip freeze --all | grep $1 | cut -d"=" -f3)
}
echo "Testing that the virtual environment's Python is being used ..."
if [ "$(which python)" != "/opt/app-root/bin/python" ]; then
echo "ERROR: Initialization of the virtual environment failed."
@ -28,7 +11,10 @@ fi
echo "Testing UPGRADE_PIP_TO_LATEST=1 (set in .s2i/environment) ..."
packages=("pip" "setuptools" "wheel")
for pkg in ${packages[@]}; do
if [ $(get_latest_stable_version $pkg) != $(get_installed_version $pkg) ]; then
# grep returns exit code 1 if the output contains only one line starting
# with "Requirement already …" which means that the package is updated
python -m pip install -U --no-python-version-warning $pkg 2>&1 | grep -v "^Requirement already up-to-date: "
if [ $? -eq 0 ]; then
echo "ERROR: Failed to upgrade '$pkg' to the latest version."
exit 1
fi

View file

@ -16,16 +16,23 @@ set -exo nounset
test -n "${IMAGE_NAME-}" || false 'make sure $IMAGE_NAME is defined'
test -n "${VERSION-}" || false 'make sure $VERSION is defined'
if [ -z "${EPHEMERAL_TEMPLATES:-}" ]; then
EPHEMERAL_TEMPLATES="
https://raw.githubusercontent.com/sclorg/django-ex/master/openshift/templates/django-postgresql.json \
https://raw.githubusercontent.com/openshift/origin/master/examples/quickstarts/django-postgresql.json"
fi
ct_os_cluster_up
ct_os_test_s2i_app "${IMAGE_NAME}" "${THISDIR}/standalone-test-app" . "Hello World from standalone WSGI application!"
ct_os_test_s2i_app "${IMAGE_NAME}" "https://github.com/sclorg/django-ex.git" . 'Welcome to your Django application on OpenShift'
ct_os_test_template_app "${IMAGE_NAME}" \
https://raw.githubusercontent.com/sclorg/django-ex/master/openshift/templates/django-postgresql.json \
python \
'Welcome to your Django application on OpenShift' \
8080 http 200 "-p SOURCE_REPOSITORY_REF=master -p PYTHON_VERSION=${VERSION} -p POSTGRESQL_VERSION=9.6 -p NAME=python-testing" \
"centos/postgresql-96-centos7|postgresql:9.6"
for template in $EPHEMERAL_TEMPLATES; do
ct_os_test_template_app "$IMAGE_NAME" \
"$template" \
python \
'Welcome to your Django application on OpenShift' \
8080 http 200 "-p SOURCE_REPOSITORY_REF=master -p PYTHON_VERSION=${VERSION} -p POSTGRESQL_VERSION=9.6 -p NAME=python-testing" \
"centos/postgresql-96-centos7|postgresql:9.6"
done

View file

@ -1,5 +1,7 @@
# shellcheck shell=bash
# some functions are used from test-lib.sh, that is usually in the same dir
source $(dirname ${BASH_SOURCE[0]})/test-lib.sh
# shellcheck source=/dev/null
source "$(dirname "${BASH_SOURCE[0]}")"/test-lib.sh
# Set of functions for testing docker images in OpenShift using 'oc' command
@ -13,8 +15,10 @@ OS_CLUSTER_STARTED_BY_TEST=0
function ct_os_cleanup() {
if [ $OS_TESTSUITE_RESULT -eq 0 ] ; then
# shellcheck disable=SC2153
echo "OpenShift tests for ${IMAGE_NAME} succeeded."
else
# shellcheck disable=SC2153
echo "OpenShift tests for ${IMAGE_NAME} failed."
fi
}
@ -26,8 +30,11 @@ function ct_os_cleanup() {
# * VERSION specifies the major version of the MariaDB in format of X.Y
# * OS specifies RHEL version (e.g. OS=rhel7)
function ct_os_check_compulsory_vars() {
# shellcheck disable=SC2016
test -n "${IMAGE_NAME-}" || ( echo 'make sure $IMAGE_NAME is defined' >&2 ; exit 1)
# shellcheck disable=SC2016
test -n "${VERSION-}" || ( echo 'make sure $VERSION is defined' >&2 ; exit 1)
# shellcheck disable=SC2016
test -n "${OS-}" || ( echo 'make sure $OS is defined' >&2 ; exit 1)
}
@ -44,9 +51,9 @@ function ct_os_get_status() {
# Returns status of all objects and logs from all pods.
function ct_os_print_logs() {
ct_os_get_status
while read pod_name; do
while read -r pod_name; do
echo "INFO: printing logs for pod ${pod_name}"
oc logs ${pod_name}
oc logs "${pod_name}"
done < <(oc get pods --no-headers=true -o custom-columns=NAME:.metadata.name)
}
@ -65,13 +72,15 @@ function ct_os_enable_print_logs() {
# hostname -I returns and de-prioritizes IP addresses commonly used for local
# addressing. The rest of addresses are taken as public with higher probability.
function ct_get_public_ip() {
local hostnames=$(hostname -I)
local hostnames
local public_ip=''
local found_ip
hostnames=$(hostname -I)
for guess_exp in '127\.0\.0\.1' '192\.168\.[0-9\.]*' '172\.[0-9\.]*' \
'10\.[0-9\.]*' '[0-9\.]*' ; do
found_ip=$(echo "${hostnames}" | grep -oe "${guess_exp}")
if [ -n "${found_ip}" ] ; then
# shellcheck disable=SC2001
hostnames=$(echo "${hostnames}" | sed -e "s/${found_ip}//")
public_ip="${found_ip}"
fi
@ -157,7 +166,7 @@ function ct_os_get_pod_ip() {
function ct_os_check_pod_readiness() {
local pod_prefix="${1}" ; shift
local status="${1}" ; shift
test "$(ct_os_get_pod_status ${pod_prefix})" == "${status}"
test "$(ct_os_get_pod_status "${pod_prefix}")" == "${status}"
}
# ct_os_wait_pod_ready POD_PREFIX TIMEOUT
@ -172,7 +181,7 @@ function ct_os_wait_pod_ready() {
echo -n "Waiting for ${pod_prefix} pod becoming ready ..."
while ! ct_os_check_pod_readiness "${pod_prefix}" "true" ; do
echo -n "."
[ ${SECONDS} -gt ${timeout} ] && echo " FAIL" && return 1
[ "${SECONDS}" -gt "${timeout}" ] && echo " FAIL" && return 1
sleep 3
done
echo " DONE"
@ -188,10 +197,10 @@ function ct_os_wait_rc_ready() {
local timeout="${1}" ; shift
SECONDS=0
echo -n "Waiting for ${pod_prefix} pod becoming ready ..."
while ! test "$((oc get --no-headers statefulsets; oc get --no-headers rc) 2>/dev/null \
while ! test "$( (oc get --no-headers statefulsets; oc get --no-headers rc) 2>/dev/null \
| grep "^${pod_prefix}" | awk '$2==$3 {print "ready"}')" == "ready" ; do
echo -n "."
[ ${SECONDS} -gt ${timeout} ] && echo " FAIL" && return 1
[ "${SECONDS}" -gt "${timeout}" ] && echo " FAIL" && return 1
sleep 3
done
echo " DONE"
@ -206,7 +215,7 @@ function ct_os_wait_rc_ready() {
function ct_os_deploy_pure_image() {
local image="${1}" ; shift
# ignore error exit code, because oc new-app returns error when image exists
oc new-app ${image} "$@" || :
oc new-app "${image}" "$@" || :
# let openshift cluster to sync to avoid some race condition errors
sleep 3
}
@ -267,13 +276,14 @@ function _ct_os_get_uniq_project_name() {
# The OPENSHIFT_CLUSTER_PULLSECRET_PATH environment variable can be set
# to contain a path to a k8s secret definition which will be used
# to authenticate to image registries.
# shellcheck disable=SC2120
function ct_os_new_project() {
if [ "${CT_SKIP_NEW_PROJECT:-false}" == 'true' ] ; then
echo "Creating project skipped."
return
fi
local project_name="${1:-$(_ct_os_get_uniq_project_name)}" ; shift || :
oc new-project ${project_name}
oc new-project "${project_name}"
# let openshift cluster to sync to avoid some race condition errors
sleep 3
if test -n "${OPENSHIFT_CLUSTER_PULLSECRET_PATH:-}" -a -e "${OPENSHIFT_CLUSTER_PULLSECRET_PATH:-}"; then
@ -289,6 +299,7 @@ function ct_os_new_project() {
# --------------------
# Deletes the specified project in the openshfit
# Arguments: project - project name, uses the current project if omitted
# shellcheck disable=SC2120
function ct_os_delete_project() {
if [ "${CT_SKIP_NEW_PROJECT:-false}" == 'true' ] ; then
echo "Deleting project skipped, cleaning objects only."
@ -307,7 +318,7 @@ function ct_os_delete_project() {
# Handy when we have one project and want to run more tests.
function ct_delete_all_objects() {
for x in bc builds dc is isimage istag po pv pvc rc routes secrets svc ; do
oc delete $x --all
oc delete "$x" --all
done
# for some objects it takes longer to be really deleted, so a dummy sleep
# to avoid some races when other test can see not-yet-deleted objects and can fail
@ -322,8 +333,10 @@ function ct_delete_all_objects() {
function ct_os_docker_login() {
[ -n "${REGISTRY_ADDRESS:-}" ] && "REGISTRY_ADDRESS set, not trying to docker login." && return 0
# docker login fails with "404 page not found" error sometimes, just try it more times
for i in `seq 12` ; do
docker login -u developer -p $(oc whoami -t) ${REGISRTY_ADDRESS:-172.30.1.1:5000} && return 0 || :
# shellcheck disable=SC2034
for i in $(seq 12) ; do
# shellcheck disable=SC2015
docker login -u developer -p "$(oc whoami -t)" "${REGISRTY_ADDRESS:-172.30.1.1:5000}" && return 0 || :
sleep 5
done
return 1
@ -340,11 +353,13 @@ function ct_os_upload_image() {
local input_name="${1}" ; shift
local image_name=${input_name##*/}
local imagestream=${1:-$image_name:latest}
local output_name="${REGISRTY_ADDRESS:-172.30.1.1:5000}/$(oc project -q)/$imagestream"
local output_name
output_name="${REGISRTY_ADDRESS:-172.30.1.1:5000}/$(oc project -q)/$imagestream"
ct_os_docker_login
docker tag ${input_name} ${output_name}
docker push ${output_name}
docker tag "${input_name}" "${output_name}"
docker push "${output_name}"
}
# ct_os_is_tag_exists IS_NAME TAG
@ -412,7 +427,7 @@ function ct_os_cluster_up() {
ct_os_set_path_oc "${cluster_version}"
fi
mkdir -p ${dir}/{config,data,pv}
mkdir -p "${dir}"/{config,data,pv}
case $(oc version| head -n 1) in
"oc v3.1"?.*)
oc cluster up --base-dir="${dir}/data" --public-hostname="${cluster_ip}"
@ -473,11 +488,13 @@ function ct_os_logged_in() {
# In the end the PATH variable is changed, so the other tests can still use just 'oc'.
# Arguments: oc_version - X.Y part of the version of OSE (e.g. 3.9)
function ct_os_set_path_oc() {
local oc_version=$(ct_os_get_latest_ver $1)
local oc_version
local oc_path
oc_version=$(ct_os_get_latest_ver "$1")
if oc version | grep -q "oc ${oc_version%.*}." ; then
echo "Binary oc found already available in version ${oc_version}: `which oc` Doing noting."
echo "Binary oc found already available in version ${oc_version}: $(command -v oc) Doing noting."
return 0
fi
@ -492,7 +509,7 @@ function ct_os_set_path_oc() {
oc_path="/tmp/oc-${oc_version}-bin"
ct_os_download_upstream_oc "${oc_version}" "${oc_path}"
fi
if [ -z "${oc_path}/oc" ] ; then
if [ -z "${oc_path}" ] ; then
echo "ERROR: oc not found installed, nor downloaded" >&1
return 1
fi
@ -501,7 +518,7 @@ function ct_os_set_path_oc() {
echo "ERROR: something went wrong, oc located at ${oc_path}, but oc of version ${oc_version} not found in PATH ($PATH)" >&1
return 1
else
echo "PATH set correctly, binary oc found in version ${oc_version}: `which oc`"
echo "PATH set correctly, binary oc found in version ${oc_version}: $(command -v oc)"
fi
}
@ -539,7 +556,7 @@ function ct_os_download_upstream_oc() {
# download, unpack the binaries and then put them into output directory
echo "Downloading https://github.com/openshift/origin/releases/download/${oc_version}/${tarball} into ${output_dir}/" >&2
curl -sL https://github.com/openshift/origin/releases/download/${oc_version}/"${tarball}" | tar -C "${output_dir}" -xz
curl -sL https://github.com/openshift/origin/releases/download/"${oc_version}"/"${tarball}" | tar -C "${output_dir}" -xz
mv -f "${output_dir}"/"${tarball%.tar.gz}"/* "${output_dir}/"
rmdir "${output_dir}"/"${tarball%.tar.gz}"
@ -569,17 +586,18 @@ function ct_os_test_s2i_app_func() {
local service_name="${image_name_no_namespace}-testing"
local image_tagged="${image_name_no_namespace}:${VERSION}"
if [ $# -lt 4 ] || [ -z "${1}" -o -z "${2}" -o -z "${3}" -o -z "${4}" ]; then
if [ $# -lt 4 ] || [ -z "${1}" ] || [ -z "${2}" ] || [ -z "${3}" ] || [ -z "${4}" ]; then
echo "ERROR: ct_os_test_s2i_app_func() requires at least 4 arguments that cannot be emtpy." >&2
return 1
fi
# shellcheck disable=SC2119
ct_os_new_project
# Create a specific imagestream tag for the image so that oc cannot use anything else
if [ "${CT_SKIP_UPLOAD_IMAGE:-false}" == 'true' ] ; then
if [ -n "${import_image}" ] ; then
echo "Importing image ${import_image} as ${image_name}:${VERSION}"
oc import-image ${image_name}:${VERSION} --from ${import_image} --confirm
oc import-image "${image_name}":"${VERSION}" --from "${import_image}" --confirm
else
echo "Uploading and importing image skipped."
fi
@ -597,6 +615,7 @@ function ct_os_test_s2i_app_func() {
app_param=$(ct_obtain_input "${app}")
fi
# shellcheck disable=SC2086
ct_os_deploy_s2i_image "${image_tagged}" "${app_param}" \
--context-dir="${context_dir}" \
--name "${service_name}" \
@ -611,8 +630,12 @@ function ct_os_test_s2i_app_func() {
ct_os_wait_pod_ready "${service_name}" 300
local ip=$(ct_os_get_service_ip "${service_name}")
local check_command_exp=$(echo "$check_command" | sed -e "s/<IP>/$ip/g")
local ip
local check_command_exp
ip=$(ct_os_get_service_ip "${service_name}")
# shellcheck disable=SC2001
check_command_exp=$(echo "$check_command" | sed -e "s/<IP>/$ip/g")
echo " Checking APP using $check_command_exp ..."
local result=0
@ -624,6 +647,7 @@ function ct_os_test_s2i_app_func() {
echo " Check failed."
fi
# shellcheck disable=SC2119
ct_os_delete_project
return $result
}
@ -652,7 +676,7 @@ function ct_os_test_s2i_app() {
local oc_args=${8:-}
local import_image=${9:-}
if [ $# -lt 4 ] || [ -z "${1}" -o -z "${2}" -o -z "${3}" -o -z "${4}" ]; then
if [ $# -lt 4 ] || [ -z "${1}" ] || [ -z "${2}" ] || [ -z "${3}" ] || [ -z "${4}" ]; then
echo "ERROR: ct_os_test_s2i_app() requires at least 4 arguments that cannot be emtpy." >&2
return 1
fi
@ -689,7 +713,7 @@ function ct_os_test_template_app_func() {
local other_images=${6:-}
local import_image=${7:-}
if [ $# -lt 4 ] || [ -z "${1}" -o -z "${2}" -o -z "${3}" -o -z "${4}" ]; then
if [ $# -lt 4 ] || [ -z "${1}" ] || [ -z "${2}" ] || [ -z "${3}" ] || [ -z "${4}" ]; then
echo "ERROR: ct_os_test_template_app_func() requires at least 4 arguments that cannot be emtpy." >&2
return 1
fi
@ -697,13 +721,14 @@ function ct_os_test_template_app_func() {
local service_name="${name_in_template}-testing"
local image_tagged="${name_in_template}:${VERSION}"
# shellcheck disable=SC2119
ct_os_new_project
# Create a specific imagestream tag for the image so that oc cannot use anything else
if [ "${CT_SKIP_UPLOAD_IMAGE:-false}" == 'true' ] ; then
if [ -n "${import_image}" ] ; then
echo "Importing image ${import_image} as ${image_name}:${VERSION}"
oc import-image ${image_name}:${VERSION} --from ${import_image} --confirm
oc import-image "${image_name}":"${VERSION}" --from "${import_image}" --confirm
else
echo "Uploading and importing image skipped."
fi
@ -714,7 +739,7 @@ function ct_os_test_template_app_func() {
ct_os_upload_image "${image_name}" "${image_tagged}"
# upload also other images, that template might need (list of pairs in the format <image>|<tag>
local images_tags_a
local image_tag_a
local i_t
for i_t in ${other_images} ; do
echo "${i_t}"
@ -727,17 +752,26 @@ function ct_os_test_template_app_func() {
# get the template file from remote or local location; if not found, it is
# considered an internal template name, like 'mysql', so use the name
# explicitly
local local_template=$(ct_obtain_input "${template}" 2>/dev/null || echo "--template=${template}")
local namespace=${CT_NAMESPACE:-$(oc project -q)}
oc new-app ${local_template} \
local local_template
local namespace
namespace=${CT_NAMESPACE:-$(oc project -q)}
local_template=$(ct_obtain_input "${template}" 2>/dev/null || echo "--template=${template}")
# shellcheck disable=SC2086
oc new-app "${local_template}" \
--name "${name_in_template}" \
-p NAMESPACE="${namespace}" \
${oc_args}
ct_os_wait_pod_ready "${service_name}" 300
local ip=$(ct_os_get_service_ip "${service_name}")
local check_command_exp=$(echo "$check_command" | sed -e "s/<IP>/$ip/g")
local ip
local check_command_exp
ip=$(ct_os_get_service_ip "${service_name}")
# shellcheck disable=SC2001
check_command_exp=$(echo "$check_command" | sed -e "s/<IP>/$ip/g")
echo " Checking APP using $check_command_exp ..."
local result=0
@ -749,6 +783,7 @@ function ct_os_test_template_app_func() {
echo " Check failed."
fi
# shellcheck disable=SC2119
ct_os_delete_project
return $result
}
@ -783,7 +818,7 @@ function ct_os_test_template_app() {
local other_images=${9:-}
local import_image=${10:-}
if [ $# -lt 4 ] || [ -z "${1}" -o -z "${2}" -o -z "${3}" -o -z "${4}" ]; then
if [ $# -lt 4 ] || [ -z "${1}" ] || [ -z "${2}" ] || [ -z "${3}" ] || [ -z "${4}" ]; then
echo "ERROR: ct_os_test_template_app() requires at least 4 arguments that cannot be emtpy." >&2
return 1
fi
@ -815,6 +850,7 @@ ct_os_test_image_update() {
local ip="" check_command_exp=""
echo "Running image update test for: $image_name"
# shellcheck disable=SC2119
ct_os_new_project
# Get current image from repository and create an imagestream
@ -839,6 +875,7 @@ ct_os_test_image_update() {
check_command_exp=${check_function//<IP>/$ip}
ct_assert_cmd_success "$check_command_exp"
# shellcheck disable=SC2119
ct_os_delete_project
}
@ -870,7 +907,9 @@ EOF
SECONDS=0
echo -n "Waiting for command POD ."
while [ $SECONDS -lt 180 ] ; do
# shellcheck disable=SC2016
sout="$(ct_os_cmd_image_run 'echo $((11*11))' 2>/dev/null)"
# shellcheck disable=SC2015
grep -q '^121$' <<< "$sout" && echo "DONE" && return 0 || :
sleep 3
echo -n "."
@ -913,31 +952,32 @@ ct_os_test_response_internal() {
local result=1
local status
local response_code
local response_file=$(mktemp /tmp/ct_test_response_XXXXXX)
local response_file
local util_image_name='python:3.6'
response_file=$(mktemp /tmp/ct_test_response_XXXXXX)
ct_os_deploy_cmd_image "${util_image_name}"
while [ ${attempt} -le ${max_attempts} ]; do
ct_os_cmd_image_run "curl --connect-timeout 10 -s -w '%{http_code}' '${url}'" >${response_file} && status=0 || status=1
if [ ${status} -eq 0 ]; then
response_code=$(cat ${response_file} | tail -c 3)
while [ "${attempt}" -le "${max_attempts}" ]; do
ct_os_cmd_image_run "curl --connect-timeout 10 -s -w '%{http_code}' '${url}'" >"${response_file}" && status=0 || status=1
if [ "${status}" -eq 0 ]; then
response_code=$(tail -c 3 "${response_file}")
if [ "${response_code}" -eq "${expected_code}" ]; then
result=0
fi
cat ${response_file} | grep -qP -e "${body_regexp}" || result=1;
grep -qP -e "${body_regexp}" "${response_file}" || result=1;
# Some services return 40x code until they are ready, so let's give them
# some chance and not end with failure right away
# Do not wait if we already have expected outcome though
if [ ${result} -eq 0 -o ${attempt} -gt ${ignore_error_attempts} -o ${attempt} -eq ${max_attempts} ] ; then
if [ "${result}" -eq 0 ] || [ "${attempt}" -gt "${ignore_error_attempts}" ] || [ "${attempt}" -eq "${max_attempts}" ] ; then
break
fi
fi
attempt=$(( ${attempt} + 1 ))
sleep ${sleep_time}
attempt=$(( attempt + 1 ))
sleep "${sleep_time}"
done
rm -f ${response_file}
return ${result}
rm -f "${response_file}"
return "${result}"
}
# ct_os_get_image_from_pod
@ -946,7 +986,8 @@ ct_os_test_response_internal() {
# Argument: pod_prefix - prefix or full name of the pod to get image from
ct_os_get_image_from_pod() {
local pod_prefix=$1 ; shift
local pod_name=$(ct_os_get_pod_name $pod_prefix)
local pod_name
pod_name=$(ct_os_get_pod_name "$pod_prefix")
oc get "po/${pod_name}" -o yaml | sed -ne 's/^\s*image:\s*\(.*\)\s*$/\1/ p' | head -1
}
@ -972,10 +1013,14 @@ function ct_os_check_cmd_internal() {
local output
local ret
local ip=$(ct_os_get_service_ip "${service_name}")
local check_command_exp=$(echo "$check_command" | sed -e "s/<IP>/$ip/g")
local ip
local check_command_exp
ct_os_deploy_cmd_image $(ct_os_get_image_from_pod "${util_image_name##*/}" | head -n 1)
ip=$(ct_os_get_service_ip "${service_name}")
# shellcheck disable=SC2001
check_command_exp=$(echo "$check_command" | sed -e "s/<IP>/$ip/g")
ct_os_deploy_cmd_image "$(ct_os_get_image_from_pod "${util_image_name##*/}" | head -n 1)"
SECONDS=0
echo -n "Waiting for ${service_name} service becoming ready ..."
@ -988,7 +1033,7 @@ function ct_os_check_cmd_internal() {
return 0
fi
echo -n "."
[ ${SECONDS} -gt ${timeout} ] && break
[ ${SECONDS} -gt "${timeout}" ] && break
sleep 3
done
echo " FAIL"

View file

@ -1,3 +1,4 @@
# shellcheck shell=bash
#
# Test a container image.
#
@ -24,20 +25,21 @@ EXPECTED_EXIT_CODE=0
# Uses: $CID_FILE_DIR - path to directory containing cid_files
# Uses: $EXPECTED_EXIT_CODE - expected container exit code
function ct_cleanup() {
for cid_file in $CID_FILE_DIR/* ; do
local container=$(cat $cid_file)
for cid_file in "$CID_FILE_DIR"/* ; do
local container
container=$(cat "$cid_file")
: "Stopping and removing container $container..."
docker stop $container
exit_status=$(docker inspect -f '{{.State.ExitCode}}' $container)
docker stop "$container"
exit_status=$(docker inspect -f '{{.State.ExitCode}}' "$container")
if [ "$exit_status" != "$EXPECTED_EXIT_CODE" ]; then
: "Dumping logs for $container"
docker logs $container
docker logs "$container"
fi
docker rm -v $container
rm $cid_file
docker rm -v "$container"
rm "$cid_file"
done
rmdir $CID_FILE_DIR
rmdir "$CID_FILE_DIR"
: "Done."
}
@ -55,7 +57,7 @@ function ct_enable_cleanup() {
# Uses: $CID_FILE_DIR - path to directory containing cid_files
function ct_get_cid() {
local name="$1" ; shift || return 1
echo $(cat "$CID_FILE_DIR/$name")
cat "$CID_FILE_DIR/$name"
}
# ct_get_cip [id]
@ -64,7 +66,7 @@ function ct_get_cid() {
# Argument: id - container id
function ct_get_cip() {
local id="$1" ; shift
docker inspect --format='{{.NetworkSettings.IPAddress}}' $(ct_get_cid "$id")
docker inspect --format='{{.NetworkSettings.IPAddress}}' "$(ct_get_cid "$id")"
}
# ct_wait_for_cid [cid_file]
@ -79,9 +81,9 @@ function ct_wait_for_cid() {
local attempt=1
local result=1
while [ $attempt -le $max_attempts ]; do
[ -f $cid_file ] && [ -s $cid_file ] && return 0
[ -f "$cid_file" ] && [ -s "$cid_file" ] && return 0
: "Waiting for container start..."
attempt=$(( $attempt + 1 ))
attempt=$(( attempt + 1 ))
sleep $sleep_time
done
return 1
@ -100,30 +102,32 @@ function ct_assert_container_creation_fails() {
local cid_file=assert
set +e
local old_container_args="${CONTAINER_ARGS-}"
# we really work with CONTAINER_ARGS as with a string
# shellcheck disable=SC2124
CONTAINER_ARGS="$@"
ct_create_container $cid_file
if [ $? -eq 0 ]; then
local cid=$(ct_get_cid $cid_file)
if ct_create_container "$cid_file" ; then
local cid
cid=$(ct_get_cid "$cid_file")
while [ "$(docker inspect -f '{{.State.Running}}' $cid)" == "true" ] ; do
while [ "$(docker inspect -f '{{.State.Running}}' "$cid")" == "true" ] ; do
sleep 2
attempt=$(( $attempt + 1 ))
if [ $attempt -gt $max_attempts ]; then
docker stop $cid
attempt=$(( attempt + 1 ))
if [ "$attempt" -gt "$max_attempts" ]; then
docker stop "$cid"
ret=1
break
fi
done
exit_status=$(docker inspect -f '{{.State.ExitCode}}' $cid)
exit_status=$(docker inspect -f '{{.State.ExitCode}}' "$cid")
if [ "$exit_status" == "0" ]; then
ret=1
fi
docker rm -v $cid
rm $CID_FILE_DIR/$cid_file
docker rm -v "$cid"
rm "$CID_FILE_DIR/$cid_file"
fi
[ ! -z $old_container_args ] && CONTAINER_ARGS="$old_container_args"
[ -n "$old_container_args" ] && CONTAINER_ARGS="$old_container_args"
set -e
return $ret
return "$ret"
}
# ct_create_container [name, command]
@ -139,9 +143,10 @@ function ct_assert_container_creation_fails() {
function ct_create_container() {
local cid_file="$CID_FILE_DIR/$1" ; shift
# create container with a cidfile in a directory for cleanup
docker run --cidfile="$cid_file" -d ${CONTAINER_ARGS:-} $IMAGE_NAME "$@"
ct_wait_for_cid $cid_file || return 1
: "Created container $(cat $cid_file)"
# shellcheck disable=SC2086
docker run --cidfile="$cid_file" -d ${CONTAINER_ARGS:-} "$IMAGE_NAME" "$@"
ct_wait_for_cid "$cid_file" || return 1
: "Created container $(cat "$cid_file")"
}
# ct_scl_usage_old [name, command, expected]
@ -159,19 +164,19 @@ function ct_scl_usage_old() {
local expected="$3"
local out=""
: " Testing the image SCL enable"
out=$(docker run --rm ${IMAGE_NAME} /bin/bash -c "${command}")
out=$(docker run --rm "${IMAGE_NAME}" /bin/bash -c "${command}")
if ! echo "${out}" | grep -q "${expected}"; then
echo "ERROR[/bin/bash -c "${command}"] Expected '${expected}', got '${out}'" >&2
echo "ERROR[/bin/bash -c \"${command}\"] Expected '${expected}', got '${out}'" >&2
return 1
fi
out=$(docker exec $(ct_get_cid $name) /bin/bash -c "${command}" 2>&1)
out=$(docker exec "$(ct_get_cid "$name")" /bin/bash -c "${command}" 2>&1)
if ! echo "${out}" | grep -q "${expected}"; then
echo "ERROR[exec /bin/bash -c "${command}"] Expected '${expected}', got '${out}'" >&2
echo "ERROR[exec /bin/bash -c \"${command}\"] Expected '${expected}', got '${out}'" >&2
return 1
fi
out=$(docker exec $(ct_get_cid $name) /bin/sh -ic "${command}" 2>&1)
out=$(docker exec "$(ct_get_cid "$name")" /bin/sh -ic "${command}" 2>&1)
if ! echo "${out}" | grep -q "${expected}"; then
echo "ERROR[exec /bin/sh -ic "${command}"] Expected '${expected}', got '${out}'" >&2
echo "ERROR[exec /bin/sh -ic \"${command}\"] Expected '${expected}', got '${out}'" >&2
return 1
fi
}
@ -183,22 +188,24 @@ function ct_scl_usage_old() {
# Argument: strings - strings expected to appear in the documentation
# Uses: $IMAGE_NAME - name of the image being tested
function ct_doc_content_old() {
local tmpdir=$(mktemp -d)
local tmpdir
tmpdir=$(mktemp -d)
local f
: " Testing documentation in the container image"
# Extract the help files from the container
# shellcheck disable=SC2043
for f in help.1 ; do
docker run --rm ${IMAGE_NAME} /bin/bash -c "cat /${f}" >${tmpdir}/$(basename ${f})
docker run --rm "${IMAGE_NAME}" /bin/bash -c "cat /${f}" >"${tmpdir}/$(basename "${f}")"
# Check whether the files contain some important information
for term in $@ ; do
if ! cat ${tmpdir}/$(basename ${f}) | grep -F -q -e "${term}" ; then
for term in "$@" ; do
if ! grep -F -q -e "${term}" "${tmpdir}/$(basename "${f}")" ; then
echo "ERROR: File /${f} does not include '${term}'." >&2
return 1
fi
done
# Check whether the files use the correct format
for term in TH PP SH ; do
if ! grep -q "^\.${term}" ${tmpdir}/help.1 ; then
if ! grep -q "^\.${term}" "${tmpdir}/help.1" ; then
echo "ERROR: /help.1 is probably not in troff or groff format, since '${term}' is missing." >&2
return 1
fi
@ -222,7 +229,7 @@ function ct_mount_ca_file()
# mount CA file only if NPM_REGISTRY variable is present.
local mount_parameter=""
if [ -n "$NPM_REGISTRY" ] && [ -f "$(full_ca_file_path)" ]; then
mount_parameter="-v $(full_ca_file_path):$(full_ca_file_path):ro,Z"
mount_parameter="-v $(full_ca_file_path):$(full_ca_file_path):Z"
fi
echo "$mount_parameter"
}
@ -244,21 +251,37 @@ function ct_build_s2i_npm_variables()
# --------------------
# Checks existance of the npm tool and runs it.
function ct_npm_works() {
local tmpdir=$(mktemp -d)
local tmpdir
tmpdir=$(mktemp -d)
: " Testing npm in the container image"
docker run --rm ${IMAGE_NAME} /bin/bash -c "npm --version" >${tmpdir}/version
if [ $? -ne 0 ] ; then
cid_file="${tmpdir}/cid"
if ! docker run --rm "${IMAGE_NAME}" /bin/bash -c "npm --version" >"${tmpdir}/version" ; then
echo "ERROR: 'npm --version' does not work inside the image ${IMAGE_NAME}." >&2
return 1
fi
docker run $(ct_mount_ca_file) --rm ${IMAGE_NAME} /bin/bash -c "npm install jquery && test -f node_modules/jquery/src/jquery.js"
# shellcheck disable=SC2046
docker run -d $(ct_mount_ca_file) --rm --cidfile="$cid_file" "${IMAGE_NAME}-testapp"
if [ $? -ne 0 ] ; then
# Wait for the container to write it's CID file
ct_wait_for_cid "$cid_file" || return 1
if ! docker exec "$(cat "$cid_file")" /bin/bash -c "npm --verbose install jquery && test -f node_modules/jquery/src/jquery.js" >"${tmpdir}/jquery" 2>&1 ; then
echo "ERROR: npm could not install jquery inside the image ${IMAGE_NAME}." >&2
return 1
fi
if [ -n "$NPM_REGISTRY" ] && [ -f "$(full_ca_file_path)" ]; then
if ! grep -qo "$NPM_REGISTRY" "${tmpdir}/jquery"; then
echo "ERROR: Internal repository is NOT set. Even it is requested."
return 1
fi
fi
if [ -f "$cid_file" ]; then
docker stop "$(cat "$cid_file")"
rm "$cid_file"
fi
: " Success!"
}
@ -301,8 +324,10 @@ ct_path_foreach ()
function ct_run_test_list() {
for test_case in $TEST_LIST; do
: "Running test $test_case"
[ -f test/$test_case ] && source test/$test_case
[ -f ../test/$test_case ] && source ../test/$test_case
# shellcheck source=/dev/null
[ -f "test/$test_case" ] && source "test/$test_case"
# shellcheck source=/dev/null
[ -f "../test/$test_case" ] && source "../test/$test_case"
$test_case
done;
}
@ -318,9 +343,9 @@ function ct_run_test_list() {
ct_gen_self_signed_cert_pem() {
local output_dir=$1 ; shift
local base_name=$1 ; shift
mkdir -p ${output_dir}
openssl req -newkey rsa:2048 -nodes -keyout ${output_dir}/${base_name}-key.pem -subj '/C=GB/ST=Berkshire/L=Newbury/O=My Server Company' > ${base_name}-req.pem
openssl req -new -x509 -nodes -key ${output_dir}/${base_name}-key.pem -batch > ${output_dir}/${base_name}-cert-selfsigned.pem
mkdir -p "${output_dir}"
openssl req -newkey rsa:2048 -nodes -keyout "${output_dir}"/"${base_name}"-key.pem -subj '/C=GB/ST=Berkshire/L=Newbury/O=My Server Company' > "${base_name}"-req.pem
openssl req -new -x509 -nodes -key "${output_dir}"/"${base_name}"-key.pem -batch > "${output_dir}"/"${base_name}"-cert-selfsigned.pem
}
# ct_obtain_input FILE|DIR|URL
@ -336,7 +361,8 @@ function ct_obtain_input() {
# Try to use same extension for the temporary file if possible
[[ "${extension}" =~ ^[a-z0-9]*$ ]] && extension=".${extension}" || extension=""
local output=$(mktemp "/var/tmp/test-input-XXXXXX$extension")
local output
output=$(mktemp "/var/tmp/test-input-XXXXXX$extension")
if [ -f "${input}" ] ; then
cp -f "${input}" "${output}"
elif [ -d "${input}" ] ; then
@ -373,27 +399,28 @@ ct_test_response() {
local result=1
local status
local response_code
local response_file=$(mktemp /tmp/ct_test_response_XXXXXX)
while [ ${attempt} -le ${max_attempts} ]; do
curl --connect-timeout 10 -s -w '%{http_code}' "${url}" >${response_file} && status=0 || status=1
if [ ${status} -eq 0 ]; then
response_code=$(cat ${response_file} | tail -c 3)
local response_file
response_file=$(mktemp /tmp/ct_test_response_XXXXXX)
while [ "${attempt}" -le "${max_attempts}" ]; do
curl --connect-timeout 10 -s -w '%{http_code}' "${url}" >"${response_file}" && status=0 || status=1
if [ "${status}" -eq 0 ]; then
response_code=$(tail -c 3 "${response_file}")
if [ "${response_code}" -eq "${expected_code}" ]; then
result=0
fi
cat ${response_file} | grep -qP -e "${body_regexp}" || result=1;
grep -qP -e "${body_regexp}" "${response_file}" || result=1;
# Some services return 40x code until they are ready, so let's give them
# some chance and not end with failure right away
# Do not wait if we already have expected outcome though
if [ ${result} -eq 0 -o ${attempt} -gt ${ignore_error_attempts} -o ${attempt} -eq ${max_attempts} ] ; then
if [ "${result}" -eq 0 ] || [ "${attempt}" -gt "${ignore_error_attempts}" ] || [ "${attempt}" -eq "${max_attempts}" ] ; then
break
fi
fi
attempt=$(( ${attempt} + 1 ))
sleep ${sleep_time}
attempt=$(( attempt + 1 ))
sleep "${sleep_time}"
done
rm -f ${response_file}
return ${result}
rm -f "${response_file}"
return "${result}"
}
# ct_registry_from_os OS
@ -404,7 +431,7 @@ ct_registry_from_os() {
local registry=""
case $1 in
rhel*)
registry=registry.access.redhat.com
registry=registry.redhat.io
;;
*)
registry=docker.io
@ -413,6 +440,32 @@ ct_registry_from_os() {
echo "$registry"
}
# ct_get_public_image_name OS BASE_IMAGE_NAME VERSION
# ----------------
# Transform the arguments into public image name
# Argument: OS - string containing the os version
# Argument: BASE_IMAGE_NAME - string containing the base name of the image as defined in the Makefile
# Argument: VERSION - string containing the version of the image as defined in the Makefile
ct_get_public_image_name() {
local os=$1; shift
local base_image_name=$1; shift
local version=$1; shift
local public_image_name
local registry
registry=$(ct_registry_from_os "$os")
if [ "x$os" == "xrhel7" ]; then
public_image_name=$registry/rhscl/$base_image_name-${version//./}-rhel7
elif [ "x$os" == "xrhel8" ]; then
public_image_name=$registry/rhel8/$base_image_name-${version//./}
elif [ "x$os" == "xcentos7" ]; then
public_image_name=$registry/centos/$base_image_name-${version//./}-centos7
fi
echo "$public_image_name"
}
# ct_assert_cmd_success CMD
# ----------------
# Evaluates [cmd] and fails if it does not succeed.
@ -555,9 +608,9 @@ EOF
# Add in artifacts if doing an incremental build
if $incremental; then
echo "RUN mkdir /tmp/artifacts" >>"$df_name"
echo "ADD artifacts.tar /tmp/artifacts" >>"$df_name"
echo "RUN chown -R $user_id:0 /tmp/artifacts" >>"$df_name"
{ echo "RUN mkdir /tmp/artifacts"
echo "ADD artifacts.tar /tmp/artifacts"
echo "RUN chown -R $user_id:0 /tmp/artifacts" ; } >>"$df_name"
fi
echo "USER $user_id" >>"$df_name"
@ -578,8 +631,23 @@ EOF
mount_options=$(echo "$s2i_args" | grep -o -e '\(-v\)[[:space:]]\.*\S*' || true)
# Run the build and tag the result
# shellcheck disable=SC2086
docker build $mount_options -f "$df_name" --no-cache=true -t "$dst_image" .
)
}
# ct_check_image_availability PUBLIC_IMAGE_NAME
# ----------------------------
# Pull an image from the public repositories to see if the image is already available.
# Argument: PUBLIC_IMAGE_NAME - string containing the public name of the image to pull
ct_check_image_availability() {
local public_image_name=$1;
# Try pulling the image to see if it is accessible
if ! docker pull "$public_image_name" &>/dev/null; then
echo "$public_image_name could not be downloaded via 'docker'"
return 1
fi
}
# vim: set tabstop=2:shiftwidth=2:expandtab: