|
|
d988f44 |
# shellcheck shell=bash
|
|
|
d988f44 |
# some functions are used from test-lib.sh, that is usually in the same dir
|
|
|
d988f44 |
# shellcheck source=/dev/null
|
|
|
d988f44 |
source "$(dirname "${BASH_SOURCE[0]}")"/test-lib.sh
|
|
|
d988f44 |
|
|
|
d988f44 |
# Set of functions for testing docker images in OpenShift using 'oc' command
|
|
|
d988f44 |
|
|
|
d988f44 |
# A variable containing the overall test result; must be changed to 0 in the end
|
|
|
d988f44 |
# of the testing script:
|
|
|
d988f44 |
# OS_TESTSUITE_RESULT=0
|
|
|
d988f44 |
# And the following trap must be set, in the beginning of the test script:
|
|
|
d988f44 |
# trap ct_os_cleanup EXIT SIGINT
|
|
|
d988f44 |
OS_TESTSUITE_RESULT=1
|
|
|
d988f44 |
OS_CLUSTER_STARTED_BY_TEST=0
|
|
|
d988f44 |
|
|
|
d988f44 |
function ct_os_cleanup() {
|
|
|
d988f44 |
if [ $OS_TESTSUITE_RESULT -eq 0 ] ; then
|
|
|
d988f44 |
# shellcheck disable=SC2153
|
|
|
d988f44 |
echo "OpenShift tests for ${IMAGE_NAME} succeeded."
|
|
|
d988f44 |
else
|
|
|
d988f44 |
# shellcheck disable=SC2153
|
|
|
d988f44 |
echo "OpenShift tests for ${IMAGE_NAME} failed."
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_check_compulsory_vars
|
|
|
d988f44 |
# ---------------------------
|
|
|
d988f44 |
# Check the compulsory variables:
|
|
|
d988f44 |
# * IMAGE_NAME specifies a name of the candidate image used for testing.
|
|
|
d988f44 |
# * VERSION specifies the major version of the MariaDB in format of X.Y
|
|
|
d988f44 |
# * OS specifies RHEL version (e.g. OS=rhel7)
|
|
|
d988f44 |
function ct_os_check_compulsory_vars() {
|
|
|
d988f44 |
# shellcheck disable=SC2016
|
|
|
d988f44 |
test -n "${IMAGE_NAME-}" || ( echo 'make sure $IMAGE_NAME is defined' >&2 ; exit 1)
|
|
|
d988f44 |
# shellcheck disable=SC2016
|
|
|
d988f44 |
test -n "${VERSION-}" || ( echo 'make sure $VERSION is defined' >&2 ; exit 1)
|
|
|
d988f44 |
# shellcheck disable=SC2016
|
|
|
d988f44 |
test -n "${OS-}" || ( echo 'make sure $OS is defined' >&2 ; exit 1)
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_get_status
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Returns status of all objects to make debugging easier.
|
|
|
d988f44 |
function ct_os_get_status() {
|
|
|
d988f44 |
oc get all
|
|
|
d988f44 |
oc status
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_print_logs
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Returns status of all objects and logs from all pods.
|
|
|
d988f44 |
function ct_os_print_logs() {
|
|
|
d988f44 |
ct_os_get_status
|
|
|
d988f44 |
while read -r pod_name; do
|
|
|
d988f44 |
echo "INFO: printing logs for pod ${pod_name}"
|
|
|
d988f44 |
oc logs "${pod_name}"
|
|
|
d988f44 |
done < <(oc get pods --no-headers=true -o custom-columns=NAME:.metadata.name)
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_enable_print_logs
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Enables automatic printing of pod logs on ERR.
|
|
|
d988f44 |
function ct_os_enable_print_logs() {
|
|
|
d988f44 |
set -E
|
|
|
d988f44 |
trap ct_os_print_logs ERR
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_get_public_ip
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Returns best guess for the IP that the node is accessible from other computers.
|
|
|
d988f44 |
# This is a bit funny heuristic, simply goes through all IPv4 addresses that
|
|
|
d988f44 |
# hostname -I returns and de-prioritizes IP addresses commonly used for local
|
|
|
d988f44 |
# addressing. The rest of addresses are taken as public with higher probability.
|
|
|
d988f44 |
function ct_get_public_ip() {
|
|
|
d988f44 |
local hostnames
|
|
|
d988f44 |
local public_ip=''
|
|
|
d988f44 |
local found_ip
|
|
|
d988f44 |
hostnames=$(hostname -I)
|
|
|
d988f44 |
for guess_exp in '127\.0\.0\.1' '192\.168\.[0-9\.]*' '172\.[0-9\.]*' \
|
|
|
d988f44 |
'10\.[0-9\.]*' '[0-9\.]*' ; do
|
|
|
d988f44 |
found_ip=$(echo "${hostnames}" | grep -oe "${guess_exp}")
|
|
|
d988f44 |
if [ -n "${found_ip}" ] ; then
|
|
|
d988f44 |
# shellcheck disable=SC2001
|
|
|
d988f44 |
hostnames=$(echo "${hostnames}" | sed -e "s/${found_ip}//")
|
|
|
d988f44 |
public_ip="${found_ip}"
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
done
|
|
|
d988f44 |
if [ -z "${public_ip}" ] ; then
|
|
|
d988f44 |
echo "ERROR: public IP could not be guessed." >&2
|
|
|
d988f44 |
return 1
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
echo "${public_ip}"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_run_in_pod POD_NAME CMD
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Runs [cmd] in the pod specified by prefix [pod_prefix].
|
|
|
d988f44 |
# Arguments: pod_name - full name of the pod
|
|
|
d988f44 |
# Arguments: cmd - command to be run in the pod
|
|
|
d988f44 |
function ct_os_run_in_pod() {
|
|
|
d988f44 |
local pod_name="$1" ; shift
|
|
|
d988f44 |
|
|
|
d988f44 |
oc exec "$pod_name" -- "$@"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_get_service_ip SERVICE_NAME
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Returns IP of the service specified by [service_name].
|
|
|
d988f44 |
# Arguments: service_name - name of the service
|
|
|
d988f44 |
function ct_os_get_service_ip() {
|
|
|
d988f44 |
local service_name="${1}" ; shift
|
|
|
d988f44 |
oc get "svc/${service_name}" -o yaml | grep clusterIP | \
|
|
|
d988f44 |
cut -d':' -f2 | grep -oe '172\.30\.[0-9\.]*'
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_get_all_pods_status
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Returns status of all pods.
|
|
|
d988f44 |
function ct_os_get_all_pods_status() {
|
|
|
d988f44 |
oc get pods -o custom-columns=Ready:status.containerStatuses[0].ready,NAME:.metadata.name
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_get_all_pods_name
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Returns the full name of all pods.
|
|
|
d988f44 |
function ct_os_get_all_pods_name() {
|
|
|
d988f44 |
oc get pods --no-headers -o custom-columns=NAME:.metadata.name
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_get_pod_status POD_PREFIX
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Returns status of the pod specified by prefix [pod_prefix].
|
|
|
d988f44 |
# Note: Ignores -build and -deploy pods
|
|
|
d988f44 |
# Arguments: pod_prefix - prefix or whole ID of the pod
|
|
|
d988f44 |
function ct_os_get_pod_status() {
|
|
|
d988f44 |
local pod_prefix="${1}" ; shift
|
|
|
d988f44 |
ct_os_get_all_pods_status | grep -e "${pod_prefix}" | grep -Ev "(build|deploy)$" \
|
|
|
d988f44 |
| awk '{print $1}' | head -n 1
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_get_pod_name POD_PREFIX
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Returns the full name of pods specified by prefix [pod_prefix].
|
|
|
d988f44 |
# Note: Ignores -build and -deploy pods
|
|
|
d988f44 |
# Arguments: pod_prefix - prefix or whole ID of the pod
|
|
|
d988f44 |
function ct_os_get_pod_name() {
|
|
|
d988f44 |
local pod_prefix="${1}" ; shift
|
|
|
d988f44 |
ct_os_get_all_pods_name | grep -e "^${pod_prefix}" | grep -Ev "(build|deploy)$"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_get_pod_ip POD_NAME
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Returns the ip of the pod specified by [pod_name].
|
|
|
d988f44 |
# Arguments: pod_name - full name of the pod
|
|
|
d988f44 |
function ct_os_get_pod_ip() {
|
|
|
d988f44 |
local pod_name="${1}"
|
|
|
d988f44 |
oc get pod "$pod_name" --no-headers -o custom-columns=IP:status.podIP
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_check_pod_readiness POD_PREFIX STATUS
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Checks whether the pod is ready.
|
|
|
d988f44 |
# Arguments: pod_prefix - prefix or whole ID of the pod
|
|
|
d988f44 |
# Arguments: status - expected status (true, false)
|
|
|
d988f44 |
function ct_os_check_pod_readiness() {
|
|
|
d988f44 |
local pod_prefix="${1}" ; shift
|
|
|
d988f44 |
local status="${1}" ; shift
|
|
|
d988f44 |
test "$(ct_os_get_pod_status "${pod_prefix}")" == "${status}"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_wait_pod_ready POD_PREFIX TIMEOUT
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Wait maximum [timeout] for the pod becomming ready.
|
|
|
d988f44 |
# Arguments: pod_prefix - prefix or whole ID of the pod
|
|
|
d988f44 |
# Arguments: timeout - how many seconds to wait seconds
|
|
|
d988f44 |
function ct_os_wait_pod_ready() {
|
|
|
d988f44 |
local pod_prefix="${1}" ; shift
|
|
|
d988f44 |
local timeout="${1}" ; shift
|
|
|
d988f44 |
SECONDS=0
|
|
|
d988f44 |
echo -n "Waiting for ${pod_prefix} pod becoming ready ..."
|
|
|
d988f44 |
while ! ct_os_check_pod_readiness "${pod_prefix}" "true" ; do
|
|
|
d988f44 |
echo -n "."
|
|
|
d988f44 |
[ "${SECONDS}" -gt "${timeout}" ] && echo " FAIL" && return 1
|
|
|
d988f44 |
sleep 3
|
|
|
d988f44 |
done
|
|
|
d988f44 |
echo " DONE"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_wait_rc_ready POD_PREFIX TIMEOUT
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Wait maximum [timeout] for the rc having desired number of replicas ready.
|
|
|
d988f44 |
# Arguments: pod_prefix - prefix of the replication controller
|
|
|
d988f44 |
# Arguments: timeout - how many seconds to wait seconds
|
|
|
d988f44 |
function ct_os_wait_rc_ready() {
|
|
|
d988f44 |
local pod_prefix="${1}" ; shift
|
|
|
d988f44 |
local timeout="${1}" ; shift
|
|
|
d988f44 |
SECONDS=0
|
|
|
d988f44 |
echo -n "Waiting for ${pod_prefix} pod becoming ready ..."
|
|
|
d988f44 |
while ! test "$( (oc get --no-headers statefulsets; oc get --no-headers rc) 2>/dev/null \
|
|
|
d988f44 |
| grep "^${pod_prefix}" | awk '$2==$3 {print "ready"}')" == "ready" ; do
|
|
|
d988f44 |
echo -n "."
|
|
|
d988f44 |
[ "${SECONDS}" -gt "${timeout}" ] && echo " FAIL" && return 1
|
|
|
d988f44 |
sleep 3
|
|
|
d988f44 |
done
|
|
|
d988f44 |
echo " DONE"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_deploy_pure_image IMAGE [ENV_PARAMS, ...]
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Runs [image] in the openshift and optionally specifies env_params
|
|
|
d988f44 |
# as environment variables to the image.
|
|
|
d988f44 |
# Arguments: image - prefix or whole ID of the pod to run the cmd in
|
|
|
d988f44 |
# Arguments: env_params - environment variables parameters for the images.
|
|
|
d988f44 |
function ct_os_deploy_pure_image() {
|
|
|
d988f44 |
local image="${1}" ; shift
|
|
|
d988f44 |
# ignore error exit code, because oc new-app returns error when image exists
|
|
|
d988f44 |
oc new-app "${image}" "$@" || :
|
|
|
d988f44 |
# let openshift cluster to sync to avoid some race condition errors
|
|
|
d988f44 |
sleep 3
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_deploy_s2i_image IMAGE APP [ENV_PARAMS, ... ]
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Runs [image] and [app] in the openshift and optionally specifies env_params
|
|
|
d988f44 |
# as environment variables to the image.
|
|
|
d988f44 |
# Arguments: image - prefix or whole ID of the pod to run the cmd in
|
|
|
d988f44 |
# Arguments: app - url or local path to git repo with the application sources.
|
|
|
d988f44 |
# Arguments: env_params - environment variables parameters for the images.
|
|
|
d988f44 |
function ct_os_deploy_s2i_image() {
|
|
|
d988f44 |
local image="${1}" ; shift
|
|
|
d988f44 |
local app="${1}" ; shift
|
|
|
d988f44 |
# ignore error exit code, because oc new-app returns error when image exists
|
|
|
d988f44 |
oc new-app "${image}~${app}" "$@" || :
|
|
|
d988f44 |
|
|
|
d988f44 |
# let openshift cluster to sync to avoid some race condition errors
|
|
|
d988f44 |
sleep 3
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_deploy_template_image TEMPLATE [ENV_PARAMS, ...]
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Runs template in the openshift and optionally gives env_params to use
|
|
|
d988f44 |
# specific values in the template.
|
|
|
d988f44 |
# Arguments: template - prefix or whole ID of the pod to run the cmd in
|
|
|
d988f44 |
# Arguments: env_params - environment variables parameters for the template.
|
|
|
d988f44 |
# Example usage: ct_os_deploy_template_image mariadb-ephemeral-template.yaml \
|
|
|
d988f44 |
# DATABASE_SERVICE_NAME=mysql-57-centos7 \
|
|
|
d988f44 |
# DATABASE_IMAGE=mysql-57-centos7 \
|
|
|
d988f44 |
# MYSQL_USER=testu \
|
|
|
d988f44 |
# MYSQL_PASSWORD=testp \
|
|
|
d988f44 |
# MYSQL_DATABASE=testdb
|
|
|
d988f44 |
function ct_os_deploy_template_image() {
|
|
|
d988f44 |
local template="${1}" ; shift
|
|
|
d988f44 |
oc process -f "${template}" "$@" | oc create -f -
|
|
|
d988f44 |
# let openshift cluster to sync to avoid some race condition errors
|
|
|
d988f44 |
sleep 3
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# _ct_os_get_uniq_project_name
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Returns a uniq name of the OpenShift project.
|
|
|
d988f44 |
function _ct_os_get_uniq_project_name() {
|
|
|
d988f44 |
local r
|
|
|
d988f44 |
while true ; do
|
|
|
d988f44 |
r=${RANDOM}
|
|
|
d988f44 |
mkdir /var/tmp/sclorg-test-${r} &>/dev/null && echo sclorg-test-${r} && break
|
|
|
d988f44 |
done
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_new_project [PROJECT]
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Creates a new project in the openshfit using 'os' command.
|
|
|
d988f44 |
# Arguments: project - project name, uses a new random name if omitted
|
|
|
d988f44 |
# Expects 'os' command that is properly logged in to the OpenShift cluster.
|
|
|
d988f44 |
# Not using mktemp, because we cannot use uppercase characters.
|
|
|
d988f44 |
# The OPENSHIFT_CLUSTER_PULLSECRET_PATH environment variable can be set
|
|
|
d988f44 |
# to contain a path to a k8s secret definition which will be used
|
|
|
d988f44 |
# to authenticate to image registries.
|
|
|
d988f44 |
# shellcheck disable=SC2120
|
|
|
d988f44 |
function ct_os_new_project() {
|
|
|
d988f44 |
if [ "${CT_SKIP_NEW_PROJECT:-false}" == 'true' ] ; then
|
|
|
d988f44 |
echo "Creating project skipped."
|
|
|
d988f44 |
return
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
local project_name="${1:-$(_ct_os_get_uniq_project_name)}" ; shift || :
|
|
|
d988f44 |
oc new-project "${project_name}"
|
|
|
d988f44 |
# let openshift cluster to sync to avoid some race condition errors
|
|
|
d988f44 |
sleep 3
|
|
|
d988f44 |
if test -n "${OPENSHIFT_CLUSTER_PULLSECRET_PATH:-}" -a -e "${OPENSHIFT_CLUSTER_PULLSECRET_PATH:-}"; then
|
|
|
d988f44 |
oc create -f "$OPENSHIFT_CLUSTER_PULLSECRET_PATH"
|
|
|
d988f44 |
# add registry pullsecret to the serviceaccount if provided
|
|
|
d988f44 |
secret_name=$(grep '^\s*name:' "$OPENSHIFT_CLUSTER_PULLSECRET_PATH" | awk '{ print $2 }')
|
|
|
d988f44 |
secret_json='{"imagePullSecrets": [{"name": "'${secret_name}'"}]}'
|
|
|
d988f44 |
oc patch serviceaccount default -p "$secret_json"
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_delete_project [PROJECT]
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Deletes the specified project in the openshfit
|
|
|
d988f44 |
# Arguments: project - project name, uses the current project if omitted
|
|
|
d988f44 |
# shellcheck disable=SC2120
|
|
|
d988f44 |
function ct_os_delete_project() {
|
|
|
d988f44 |
if [ "${CT_SKIP_NEW_PROJECT:-false}" == 'true' ] ; then
|
|
|
d988f44 |
echo "Deleting project skipped, cleaning objects only."
|
|
|
d988f44 |
# when not having enough privileges (remote cluster), it might fail and
|
|
|
d988f44 |
# it is not a big problem, so ignore failure in this case
|
|
|
d988f44 |
ct_delete_all_objects || :
|
|
|
d988f44 |
return
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
local project_name="${1:-$(oc project -q)}" ; shift || :
|
|
|
d988f44 |
oc delete project "${project_name}"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_delete_all_objects
|
|
|
d988f44 |
# -----------------
|
|
|
d988f44 |
# Deletes all objects within the project.
|
|
|
d988f44 |
# Handy when we have one project and want to run more tests.
|
|
|
d988f44 |
function ct_delete_all_objects() {
|
|
|
d988f44 |
for x in bc builds dc is isimage istag po pv pvc rc routes secrets svc ; do
|
|
|
d988f44 |
oc delete "$x" --all
|
|
|
d988f44 |
done
|
|
|
d988f44 |
# for some objects it takes longer to be really deleted, so a dummy sleep
|
|
|
d988f44 |
# to avoid some races when other test can see not-yet-deleted objects and can fail
|
|
|
d988f44 |
sleep 10
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_docker_login
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Logs in into docker daemon
|
|
|
d988f44 |
# Uses global REGISRTY_ADDRESS environment variable for arbitrary registry address.
|
|
|
d988f44 |
# Does not do anything if REGISTRY_ADDRESS is set.
|
|
|
d988f44 |
function ct_os_docker_login() {
|
|
|
d988f44 |
[ -n "${REGISTRY_ADDRESS:-}" ] && "REGISTRY_ADDRESS set, not trying to docker login." && return 0
|
|
|
d988f44 |
# docker login fails with "404 page not found" error sometimes, just try it more times
|
|
|
d988f44 |
# shellcheck disable=SC2034
|
|
|
d988f44 |
for i in $(seq 12) ; do
|
|
|
d988f44 |
# shellcheck disable=SC2015
|
|
|
d988f44 |
docker login -u developer -p "$(oc whoami -t)" "${REGISRTY_ADDRESS:-172.30.1.1:5000}" && return 0 || :
|
|
|
d988f44 |
sleep 5
|
|
|
d988f44 |
done
|
|
|
d988f44 |
return 1
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_upload_image IMAGE [IMAGESTREAM]
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Uploads image from local registry to the OpenShift internal registry.
|
|
|
d988f44 |
# Arguments: image - image name to upload
|
|
|
d988f44 |
# Arguments: imagestream - name and tag to use for the internal registry.
|
|
|
d988f44 |
# In the format of name:tag ($image_name:latest by default)
|
|
|
d988f44 |
# Uses global REGISRTY_ADDRESS environment variable for arbitrary registry address.
|
|
|
d988f44 |
function ct_os_upload_image() {
|
|
|
d988f44 |
local input_name="${1}" ; shift
|
|
|
d988f44 |
local image_name=${input_name##*/}
|
|
|
d988f44 |
local imagestream=${1:-$image_name:latest}
|
|
|
d988f44 |
local output_name
|
|
|
d988f44 |
|
|
|
d988f44 |
output_name="${REGISRTY_ADDRESS:-172.30.1.1:5000}/$(oc project -q)/$imagestream"
|
|
|
d988f44 |
|
|
|
d988f44 |
ct_os_docker_login
|
|
|
d988f44 |
docker tag "${input_name}" "${output_name}"
|
|
|
d988f44 |
docker push "${output_name}"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_is_tag_exists IS_NAME TAG
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Checks whether the specified tag exists for an image stream
|
|
|
d988f44 |
# Arguments: is_name - name of the image stream
|
|
|
d988f44 |
# Arguments: tag - name of the tag (usually version)
|
|
|
d988f44 |
function ct_os_is_tag_exists() {
|
|
|
d988f44 |
local is_name=$1 ; shift
|
|
|
d988f44 |
local tag=$1 ; shift
|
|
|
d988f44 |
oc get is "${is_name}" -n openshift -o=jsonpath='{.spec.tags[*].name}' | grep -qw "${tag}"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_template_exists T_NAME
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Checks whether the specified template exists for an image stream
|
|
|
d988f44 |
# Arguments: t_name - template name of the image stream
|
|
|
d988f44 |
function ct_os_template_exists() {
|
|
|
d988f44 |
local t_name=$1 ; shift
|
|
|
d988f44 |
oc get templates -n openshift | grep -q "^${t_name}\s"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_install_in_centos
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Installs os cluster in CentOS
|
|
|
d988f44 |
function ct_os_install_in_centos() {
|
|
|
d988f44 |
yum install -y centos-release-openshift-origin
|
|
|
d988f44 |
yum install -y wget git net-tools bind-utils iptables-services bridge-utils\
|
|
|
d988f44 |
bash-completion origin-clients docker origin-clients
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_cluster_up [DIR, IS_PUBLIC, CLUSTER_VERSION]
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Runs the local OpenShift cluster using 'oc cluster up' and logs in as developer.
|
|
|
d988f44 |
# Arguments: dir - directory to keep configuration data in, random if omitted
|
|
|
d988f44 |
# Arguments: is_public - sets either private or public hostname for web-UI,
|
|
|
d988f44 |
# use "true" for allow remote access to the web-UI,
|
|
|
d988f44 |
# "false" is default
|
|
|
d988f44 |
# Arguments: cluster_version - version of the OpenShift cluster to use, empty
|
|
|
d988f44 |
# means default version of `oc`; example value: 3.7;
|
|
|
d988f44 |
# also can be specified outside by OC_CLUSTER_VERSION
|
|
|
d988f44 |
function ct_os_cluster_up() {
|
|
|
d988f44 |
ct_os_cluster_running && echo "Cluster already running. Nothing is done." && return 0
|
|
|
d988f44 |
ct_os_logged_in && echo "Already logged in to a cluster. Nothing is done." && return 0
|
|
|
d988f44 |
|
|
|
d988f44 |
mkdir -p /var/tmp/openshift
|
|
|
d988f44 |
local dir="${1:-$(mktemp -d /var/tmp/openshift/os-data-XXXXXX)}" ; shift || :
|
|
|
d988f44 |
local is_public="${1:-'false'}" ; shift || :
|
|
|
d988f44 |
local default_cluster_version=${OC_CLUSTER_VERSION:-}
|
|
|
d988f44 |
local cluster_version=${1:-${default_cluster_version}} ; shift || :
|
|
|
d988f44 |
if ! grep -qe '--insecure-registry.*172\.30\.0\.0' /etc/sysconfig/docker ; then
|
|
|
d988f44 |
sed -i "s|OPTIONS='|OPTIONS='--insecure-registry 172.30.0.0/16 |" /etc/sysconfig/docker
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
systemctl stop firewalld || :
|
|
|
d988f44 |
setenforce 0
|
|
|
d988f44 |
iptables -F
|
|
|
d988f44 |
|
|
|
d988f44 |
systemctl restart docker
|
|
|
d988f44 |
local cluster_ip="127.0.0.1"
|
|
|
d988f44 |
[ "${is_public}" == "true" ] && cluster_ip=$(ct_get_public_ip)
|
|
|
d988f44 |
|
|
|
d988f44 |
if [ -n "${cluster_version}" ] ; then
|
|
|
d988f44 |
# if $cluster_version is not set, we simply use oc that is available
|
|
|
d988f44 |
ct_os_set_path_oc "${cluster_version}"
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
mkdir -p "${dir}"/{config,data,pv}
|
|
|
d988f44 |
case $(oc version| head -n 1) in
|
|
|
d988f44 |
"oc v3.1"?.*)
|
|
|
d988f44 |
oc cluster up --base-dir="${dir}/data" --public-hostname="${cluster_ip}"
|
|
|
d988f44 |
;;
|
|
|
d988f44 |
"oc v3."*)
|
|
|
d988f44 |
oc cluster up --host-data-dir="${dir}/data" --host-config-dir="${dir}/config" \
|
|
|
d988f44 |
--host-pv-dir="${dir}/pv" --use-existing-config --public-hostname="${cluster_ip}"
|
|
|
d988f44 |
;;
|
|
|
d988f44 |
*)
|
|
|
d988f44 |
echo "ERROR: Unexpected oc version." >&2
|
|
|
d988f44 |
return 1
|
|
|
d988f44 |
;;
|
|
|
d988f44 |
esac
|
|
|
d988f44 |
oc version
|
|
|
d988f44 |
oc login -u system:admin
|
|
|
d988f44 |
oc project default
|
|
|
d988f44 |
ct_os_wait_rc_ready docker-registry 180
|
|
|
d988f44 |
ct_os_wait_rc_ready router 30
|
|
|
d988f44 |
oc login -u developer -p developer
|
|
|
d988f44 |
OS_CLUSTER_STARTED_BY_TEST=1
|
|
|
d988f44 |
# let openshift cluster to sync to avoid some race condition errors
|
|
|
d988f44 |
sleep 3
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_cluster_down
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Shuts down the local OpenShift cluster using 'oc cluster down'
|
|
|
d988f44 |
function ct_os_cluster_down() {
|
|
|
d988f44 |
if [ ${OS_CLUSTER_STARTED_BY_TEST:-0} -eq 1 ] ; then
|
|
|
d988f44 |
echo "Cluster started by the test, shutting down."
|
|
|
d988f44 |
oc cluster down
|
|
|
d988f44 |
else
|
|
|
d988f44 |
echo "Cluster not started by the test, shutting down skipped."
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_cluster_running
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Returns 0 if oc cluster is running
|
|
|
d988f44 |
function ct_os_cluster_running() {
|
|
|
d988f44 |
oc cluster status &>/dev/null
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_logged_in
|
|
|
d988f44 |
# ---------------
|
|
|
d988f44 |
# Returns 0 if logged in to a cluster (remote or local)
|
|
|
d988f44 |
function ct_os_logged_in() {
|
|
|
d988f44 |
oc whoami >/dev/null
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_set_path_oc OC_VERSION
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# This is a trick that helps using correct version of the `oc`:
|
|
|
d988f44 |
# The input is version of the openshift in format v3.6.0 etc.
|
|
|
d988f44 |
# If the currently available version of oc is not of this version,
|
|
|
d988f44 |
# it first takes a look into /usr/local/oc-<ver>/bin directory,
|
|
|
d988f44 |
# and if not found there it downloads the community release from github.
|
|
|
d988f44 |
# In the end the PATH variable is changed, so the other tests can still use just 'oc'.
|
|
|
d988f44 |
# Arguments: oc_version - X.Y part of the version of OSE (e.g. 3.9)
|
|
|
d988f44 |
function ct_os_set_path_oc() {
|
|
|
d988f44 |
local oc_version
|
|
|
d988f44 |
local oc_path
|
|
|
d988f44 |
|
|
|
d988f44 |
oc_version=$(ct_os_get_latest_ver "$1")
|
|
|
d988f44 |
|
|
|
d988f44 |
if oc version | grep -q "oc ${oc_version%.*}." ; then
|
|
|
d988f44 |
echo "Binary oc found already available in version ${oc_version}: $(command -v oc) Doing noting."
|
|
|
d988f44 |
return 0
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
# first check whether we already have oc available in /usr/local
|
|
|
d988f44 |
local installed_oc_path="/usr/local/oc-${oc_version%.*}/bin"
|
|
|
d988f44 |
|
|
|
d988f44 |
if [ -x "${installed_oc_path}/oc" ] ; then
|
|
|
d988f44 |
oc_path="${installed_oc_path}"
|
|
|
d988f44 |
echo "Binary oc found in ${installed_oc_path}" >&2
|
|
|
d988f44 |
else
|
|
|
d988f44 |
# oc not available in /usr/local, try to download it from github (community release)
|
|
|
d988f44 |
oc_path="/tmp/oc-${oc_version}-bin"
|
|
|
d988f44 |
ct_os_download_upstream_oc "${oc_version}" "${oc_path}"
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
if [ -z "${oc_path}" ] ; then
|
|
|
d988f44 |
echo "ERROR: oc not found installed, nor downloaded" >&1
|
|
|
d988f44 |
return 1
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
export PATH="${oc_path}:${PATH}"
|
|
|
d988f44 |
if ! oc version | grep -q "oc ${oc_version%.*}." ; then
|
|
|
d988f44 |
echo "ERROR: something went wrong, oc located at ${oc_path}, but oc of version ${oc_version} not found in PATH ($PATH)" >&1
|
|
|
d988f44 |
return 1
|
|
|
d988f44 |
else
|
|
|
d988f44 |
echo "PATH set correctly, binary oc found in version ${oc_version}: $(command -v oc)"
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_get_latest_ver VERSION_PART_X
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Returns full version (vX.Y.Z) from part of the version (X.Y)
|
|
|
d988f44 |
# Arguments: vxy - X.Y part of the version
|
|
|
d988f44 |
# Returns vX.Y.Z variant of the version
|
|
|
d988f44 |
function ct_os_get_latest_ver(){
|
|
|
d988f44 |
local vxy="v$1"
|
|
|
d988f44 |
for vz in {3..0} ; do
|
|
|
d988f44 |
curl -sif "https://github.com/openshift/origin/releases/tag/${vxy}.${vz}" >/dev/null && echo "${vxy}.${vz}" && return 0
|
|
|
d988f44 |
done
|
|
|
d988f44 |
echo "ERROR: version ${vxy} not found in https://github.com/openshift/origin/tags" >&2
|
|
|
d988f44 |
return 1
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_download_upstream_oc OC_VERSION OUTPUT_DIR
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Downloads a particular version of openshift-origin-client-tools from
|
|
|
d988f44 |
# github into specified output directory
|
|
|
d988f44 |
# Arguments: oc_version - version of OSE (e.g. v3.7.2)
|
|
|
d988f44 |
# Arguments: output_dir - output directory
|
|
|
d988f44 |
function ct_os_download_upstream_oc() {
|
|
|
d988f44 |
local oc_version=$1
|
|
|
d988f44 |
local output_dir=$2
|
|
|
d988f44 |
|
|
|
d988f44 |
# check whether we already have the binary in place
|
|
|
d988f44 |
[ -x "${output_dir}/oc" ] && return 0
|
|
|
d988f44 |
|
|
|
d988f44 |
mkdir -p "${output_dir}"
|
|
|
d988f44 |
# using html output instead of https://api.github.com/repos/openshift/origin/releases/tags/${oc_version},
|
|
|
d988f44 |
# because API is limited for number of queries if not authenticated
|
|
|
d988f44 |
tarball=$(curl -si "https://github.com/openshift/origin/releases/tag/${oc_version}" | grep -o -e "openshift-origin-client-tools-${oc_version}-[a-f0-9]*-linux-64bit.tar.gz" | head -n 1)
|
|
|
d988f44 |
|
|
|
d988f44 |
# download, unpack the binaries and then put them into output directory
|
|
|
d988f44 |
echo "Downloading https://github.com/openshift/origin/releases/download/${oc_version}/${tarball} into ${output_dir}/" >&2
|
|
|
d988f44 |
curl -sL https://github.com/openshift/origin/releases/download/"${oc_version}"/"${tarball}" | tar -C "${output_dir}" -xz
|
|
|
d988f44 |
mv -f "${output_dir}"/"${tarball%.tar.gz}"/* "${output_dir}/"
|
|
|
d988f44 |
|
|
|
d988f44 |
rmdir "${output_dir}"/"${tarball%.tar.gz}"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_test_s2i_app_func IMAGE APP CONTEXT_DIR CHECK_CMD [OC_ARGS]
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Runs [image] and [app] in the openshift and optionally specifies env_params
|
|
|
d988f44 |
# as environment variables to the image. Then check the container by arbitrary
|
|
|
d988f44 |
# function given as argument (such an argument may include <IP> string,
|
|
|
d988f44 |
# that will be replaced with actual IP).
|
|
|
d988f44 |
# Arguments: image - prefix or whole ID of the pod to run the cmd in (compulsory)
|
|
|
d988f44 |
# Arguments: app - url or local path to git repo with the application sources (compulsory)
|
|
|
d988f44 |
# Arguments: context_dir - sub-directory inside the repository with the application sources (compulsory)
|
|
|
d988f44 |
# Arguments: check_command - CMD line that checks whether the container works (compulsory; '<IP>' will be replaced with actual IP)
|
|
|
d988f44 |
# Arguments: oc_args - all other arguments are used as additional parameters for the `oc new-app`
|
|
|
d988f44 |
# command, typically environment variables (optional)
|
|
|
d988f44 |
function ct_os_test_s2i_app_func() {
|
|
|
d988f44 |
local image_name=${1}
|
|
|
d988f44 |
local app=${2}
|
|
|
d988f44 |
local context_dir=${3}
|
|
|
d988f44 |
local check_command=${4}
|
|
|
d988f44 |
local oc_args=${5:-}
|
|
|
d988f44 |
local import_image=${6:-}
|
|
|
d988f44 |
local image_name_no_namespace=${image_name##*/}
|
|
|
d988f44 |
local service_name="${image_name_no_namespace}-testing"
|
|
|
d988f44 |
local image_tagged="${image_name_no_namespace}:${VERSION}"
|
|
|
d988f44 |
|
|
|
d988f44 |
if [ $# -lt 4 ] || [ -z "${1}" ] || [ -z "${2}" ] || [ -z "${3}" ] || [ -z "${4}" ]; then
|
|
|
d988f44 |
echo "ERROR: ct_os_test_s2i_app_func() requires at least 4 arguments that cannot be emtpy." >&2
|
|
|
d988f44 |
return 1
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
# shellcheck disable=SC2119
|
|
|
d988f44 |
ct_os_new_project
|
|
|
d988f44 |
# Create a specific imagestream tag for the image so that oc cannot use anything else
|
|
|
d988f44 |
if [ "${CT_SKIP_UPLOAD_IMAGE:-false}" == 'true' ] ; then
|
|
|
d988f44 |
if [ -n "${import_image}" ] ; then
|
|
|
d988f44 |
echo "Importing image ${import_image} as ${image_name}:${VERSION}"
|
|
|
d988f44 |
oc import-image "${image_name}":"${VERSION}" --from "${import_image}" --confirm
|
|
|
d988f44 |
else
|
|
|
d988f44 |
echo "Uploading and importing image skipped."
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
else
|
|
|
d988f44 |
if [ -n "${import_image}" ] ; then
|
|
|
d988f44 |
echo "Warning: Import image ${import_image} requested, but uploading image ${image_name} instead."
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
ct_os_upload_image "${image_name}" "${image_tagged}"
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
local app_param="${app}"
|
|
|
d988f44 |
if [ -d "${app}" ] ; then
|
|
|
d988f44 |
# for local directory, we need to copy the content, otherwise too smart os command
|
|
|
d988f44 |
# pulls the git remote repository instead
|
|
|
d988f44 |
app_param=$(ct_obtain_input "${app}")
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
# shellcheck disable=SC2086
|
|
|
d988f44 |
ct_os_deploy_s2i_image "${image_tagged}" "${app_param}" \
|
|
|
d988f44 |
--context-dir="${context_dir}" \
|
|
|
d988f44 |
--name "${service_name}" \
|
|
|
d988f44 |
${oc_args}
|
|
|
d988f44 |
|
|
|
d988f44 |
if [ -d "${app}" ] ; then
|
|
|
d988f44 |
# in order to avoid weird race seen sometimes, let's wait shortly
|
|
|
d988f44 |
# before starting the build explicitly
|
|
|
d988f44 |
sleep 5
|
|
|
d988f44 |
oc start-build "${service_name}" --from-dir="${app_param}"
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
ct_os_wait_pod_ready "${service_name}" 300
|
|
|
d988f44 |
|
|
|
d988f44 |
local ip
|
|
|
d988f44 |
local check_command_exp
|
|
|
d988f44 |
|
|
|
d988f44 |
ip=$(ct_os_get_service_ip "${service_name}")
|
|
|
d988f44 |
# shellcheck disable=SC2001
|
|
|
d988f44 |
check_command_exp=$(echo "$check_command" | sed -e "s/<IP>/$ip/g")
|
|
|
d988f44 |
|
|
|
d988f44 |
echo " Checking APP using $check_command_exp ..."
|
|
|
d988f44 |
local result=0
|
|
|
d988f44 |
eval "$check_command_exp" || result=1
|
|
|
d988f44 |
|
|
|
d988f44 |
if [ $result -eq 0 ] ; then
|
|
|
d988f44 |
echo " Check passed."
|
|
|
d988f44 |
else
|
|
|
d988f44 |
echo " Check failed."
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
# shellcheck disable=SC2119
|
|
|
d988f44 |
ct_os_delete_project
|
|
|
d988f44 |
return $result
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_test_s2i_app IMAGE APP CONTEXT_DIR EXPECTED_OUTPUT [PORT, PROTOCOL, RESPONSE_CODE, OC_ARGS, ... ]
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Runs [image] and [app] in the openshift and optionally specifies env_params
|
|
|
d988f44 |
# as environment variables to the image. Then check the http response.
|
|
|
d988f44 |
# Arguments: image - prefix or whole ID of the pod to run the cmd in (compulsory)
|
|
|
d988f44 |
# Arguments: app - url or local path to git repo with the application sources (compulsory)
|
|
|
d988f44 |
# Arguments: context_dir - sub-directory inside the repository with the application sources (compulsory)
|
|
|
d988f44 |
# Arguments: expected_output - PCRE regular expression that must match the response body (compulsory)
|
|
|
d988f44 |
# Arguments: port - which port to use (optional; default: 8080)
|
|
|
d988f44 |
# Arguments: protocol - which protocol to use (optional; default: http)
|
|
|
d988f44 |
# Arguments: response_code - what http response code to expect (optional; default: 200)
|
|
|
d988f44 |
# Arguments: oc_args - all other arguments are used as additional parameters for the `oc new-app`
|
|
|
d988f44 |
# command, typically environment variables (optional)
|
|
|
d988f44 |
function ct_os_test_s2i_app() {
|
|
|
d988f44 |
local image_name=${1}
|
|
|
d988f44 |
local app=${2}
|
|
|
d988f44 |
local context_dir=${3}
|
|
|
d988f44 |
local expected_output=${4}
|
|
|
d988f44 |
local port=${5:-8080}
|
|
|
d988f44 |
local protocol=${6:-http}
|
|
|
d988f44 |
local response_code=${7:-200}
|
|
|
d988f44 |
local oc_args=${8:-}
|
|
|
d988f44 |
local import_image=${9:-}
|
|
|
d988f44 |
|
|
|
d988f44 |
if [ $# -lt 4 ] || [ -z "${1}" ] || [ -z "${2}" ] || [ -z "${3}" ] || [ -z "${4}" ]; then
|
|
|
d988f44 |
echo "ERROR: ct_os_test_s2i_app() requires at least 4 arguments that cannot be emtpy." >&2
|
|
|
d988f44 |
return 1
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
ct_os_test_s2i_app_func "${image_name}" \
|
|
|
d988f44 |
"${app}" \
|
|
|
d988f44 |
"${context_dir}" \
|
|
|
d988f44 |
"ct_os_test_response_internal '${protocol}://<IP>:${port}' '${response_code}' '${expected_output}'" \
|
|
|
d988f44 |
"${oc_args}" "${import_image}"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_test_template_app_func IMAGE APP IMAGE_IN_TEMPLATE CHECK_CMD [OC_ARGS]
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Runs [image] and [app] in the openshift and optionally specifies env_params
|
|
|
d988f44 |
# as environment variables to the image. Then check the container by arbitrary
|
|
|
d988f44 |
# function given as argument (such an argument may include <IP> string,
|
|
|
d988f44 |
# that will be replaced with actual IP).
|
|
|
d988f44 |
# Arguments: image_name - prefix or whole ID of the pod to run the cmd in (compulsory)
|
|
|
d988f44 |
# Arguments: template - url or local path to a template to use (compulsory)
|
|
|
d988f44 |
# Arguments: name_in_template - image name used in the template
|
|
|
d988f44 |
# Arguments: check_command - CMD line that checks whether the container works (compulsory; '<IP>' will be replaced with actual IP)
|
|
|
d988f44 |
# Arguments: oc_args - all other arguments are used as additional parameters for the `oc new-app`
|
|
|
d988f44 |
# command, typically environment variables (optional)
|
|
|
d988f44 |
# Arguments: other_images - some templates need other image to be pushed into the OpenShift registry,
|
|
|
d988f44 |
# specify them in this parameter as "<image>|<tag>", where "<image>" is a full image name
|
|
|
d988f44 |
# (including registry if needed) and "<tag>" is a tag under which the image should be available
|
|
|
d988f44 |
# in the OpenShift registry.
|
|
|
d988f44 |
function ct_os_test_template_app_func() {
|
|
|
d988f44 |
local image_name=${1}
|
|
|
d988f44 |
local template=${2}
|
|
|
d988f44 |
local name_in_template=${3}
|
|
|
d988f44 |
local check_command=${4}
|
|
|
d988f44 |
local oc_args=${5:-}
|
|
|
d988f44 |
local other_images=${6:-}
|
|
|
d988f44 |
local import_image=${7:-}
|
|
|
d988f44 |
|
|
|
d988f44 |
if [ $# -lt 4 ] || [ -z "${1}" ] || [ -z "${2}" ] || [ -z "${3}" ] || [ -z "${4}" ]; then
|
|
|
d988f44 |
echo "ERROR: ct_os_test_template_app_func() requires at least 4 arguments that cannot be emtpy." >&2
|
|
|
d988f44 |
return 1
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
local service_name="${name_in_template}-testing"
|
|
|
d988f44 |
local image_tagged="${name_in_template}:${VERSION}"
|
|
|
d988f44 |
|
|
|
d988f44 |
# shellcheck disable=SC2119
|
|
|
d988f44 |
ct_os_new_project
|
|
|
d988f44 |
|
|
|
d988f44 |
# Create a specific imagestream tag for the image so that oc cannot use anything else
|
|
|
d988f44 |
if [ "${CT_SKIP_UPLOAD_IMAGE:-false}" == 'true' ] ; then
|
|
|
d988f44 |
if [ -n "${import_image}" ] ; then
|
|
|
d988f44 |
echo "Importing image ${import_image} as ${image_name}:${VERSION}"
|
|
|
d988f44 |
oc import-image "${image_name}":"${VERSION}" --from "${import_image}" --confirm
|
|
|
d988f44 |
else
|
|
|
d988f44 |
echo "Uploading and importing image skipped."
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
else
|
|
|
d988f44 |
if [ -n "${import_image}" ] ; then
|
|
|
d988f44 |
echo "Warning: Import image ${import_image} requested, but uploading image ${image_name} instead."
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
ct_os_upload_image "${image_name}" "${image_tagged}"
|
|
|
d988f44 |
|
|
|
d988f44 |
# upload also other images, that template might need (list of pairs in the format <image>|<tag>
|
|
|
d988f44 |
local image_tag_a
|
|
|
d988f44 |
local i_t
|
|
|
d988f44 |
for i_t in ${other_images} ; do
|
|
|
d988f44 |
echo "${i_t}"
|
|
|
d988f44 |
IFS='|' read -ra image_tag_a <<< "${i_t}"
|
|
|
d988f44 |
docker pull "${image_tag_a[0]}"
|
|
|
d988f44 |
ct_os_upload_image "${image_tag_a[0]}" "${image_tag_a[1]}"
|
|
|
d988f44 |
done
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
# get the template file from remote or local location; if not found, it is
|
|
|
d988f44 |
# considered an internal template name, like 'mysql', so use the name
|
|
|
d988f44 |
# explicitly
|
|
|
d988f44 |
local local_template
|
|
|
d988f44 |
local namespace
|
|
|
d988f44 |
|
|
|
d988f44 |
namespace=${CT_NAMESPACE:-$(oc project -q)}
|
|
|
d988f44 |
|
|
|
d988f44 |
local_template=$(ct_obtain_input "${template}" 2>/dev/null || echo "--template=${template}")
|
|
|
d988f44 |
# shellcheck disable=SC2086
|
|
|
d988f44 |
oc new-app "${local_template}" \
|
|
|
d988f44 |
--name "${name_in_template}" \
|
|
|
d988f44 |
-p NAMESPACE="${namespace}" \
|
|
|
d988f44 |
${oc_args}
|
|
|
d988f44 |
|
|
|
d988f44 |
ct_os_wait_pod_ready "${service_name}" 300
|
|
|
d988f44 |
|
|
|
d988f44 |
local ip
|
|
|
d988f44 |
local check_command_exp
|
|
|
d988f44 |
|
|
|
d988f44 |
ip=$(ct_os_get_service_ip "${service_name}")
|
|
|
d988f44 |
# shellcheck disable=SC2001
|
|
|
d988f44 |
check_command_exp=$(echo "$check_command" | sed -e "s/<IP>/$ip/g")
|
|
|
d988f44 |
|
|
|
d988f44 |
echo " Checking APP using $check_command_exp ..."
|
|
|
d988f44 |
local result=0
|
|
|
d988f44 |
eval "$check_command_exp" || result=1
|
|
|
d988f44 |
|
|
|
d988f44 |
if [ $result -eq 0 ] ; then
|
|
|
d988f44 |
echo " Check passed."
|
|
|
d988f44 |
else
|
|
|
d988f44 |
echo " Check failed."
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
# shellcheck disable=SC2119
|
|
|
d988f44 |
ct_os_delete_project
|
|
|
d988f44 |
return $result
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# params:
|
|
|
d988f44 |
# ct_os_test_template_app IMAGE APP IMAGE_IN_TEMPLATE EXPECTED_OUTPUT [PORT, PROTOCOL, RESPONSE_CODE, OC_ARGS, ... ]
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Runs [image] and [app] in the openshift and optionally specifies env_params
|
|
|
d988f44 |
# as environment variables to the image. Then check the http response.
|
|
|
d988f44 |
# Arguments: image_name - prefix or whole ID of the pod to run the cmd in (compulsory)
|
|
|
d988f44 |
# Arguments: template - url or local path to a template to use (compulsory)
|
|
|
d988f44 |
# Arguments: name_in_template - image name used in the template
|
|
|
d988f44 |
# Arguments: expected_output - PCRE regular expression that must match the response body (compulsory)
|
|
|
d988f44 |
# Arguments: port - which port to use (optional; default: 8080)
|
|
|
d988f44 |
# Arguments: protocol - which protocol to use (optional; default: http)
|
|
|
d988f44 |
# Arguments: response_code - what http response code to expect (optional; default: 200)
|
|
|
d988f44 |
# Arguments: oc_args - all other arguments are used as additional parameters for the `oc new-app`
|
|
|
d988f44 |
# command, typically environment variables (optional)
|
|
|
d988f44 |
# Arguments: other_images - some templates need other image to be pushed into the OpenShift registry,
|
|
|
d988f44 |
# specify them in this parameter as "<image>|<tag>", where "<image>" is a full image name
|
|
|
d988f44 |
# (including registry if needed) and "<tag>" is a tag under which the image should be available
|
|
|
d988f44 |
# in the OpenShift registry.
|
|
|
d988f44 |
function ct_os_test_template_app() {
|
|
|
d988f44 |
local image_name=${1}
|
|
|
d988f44 |
local template=${2}
|
|
|
d988f44 |
local name_in_template=${3}
|
|
|
d988f44 |
local expected_output=${4}
|
|
|
d988f44 |
local port=${5:-8080}
|
|
|
d988f44 |
local protocol=${6:-http}
|
|
|
d988f44 |
local response_code=${7:-200}
|
|
|
d988f44 |
local oc_args=${8:-}
|
|
|
d988f44 |
local other_images=${9:-}
|
|
|
d988f44 |
local import_image=${10:-}
|
|
|
d988f44 |
|
|
|
d988f44 |
if [ $# -lt 4 ] || [ -z "${1}" ] || [ -z "${2}" ] || [ -z "${3}" ] || [ -z "${4}" ]; then
|
|
|
d988f44 |
echo "ERROR: ct_os_test_template_app() requires at least 4 arguments that cannot be emtpy." >&2
|
|
|
d988f44 |
return 1
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
|
|
|
d988f44 |
ct_os_test_template_app_func "${image_name}" \
|
|
|
d988f44 |
"${template}" \
|
|
|
d988f44 |
"${name_in_template}" \
|
|
|
d988f44 |
"ct_os_test_response_internal '${protocol}://<IP>:${port}' '${response_code}' '${expected_output}'" \
|
|
|
d988f44 |
"${oc_args}" \
|
|
|
d988f44 |
"${other_images}" \
|
|
|
d988f44 |
"${import_image}"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_test_image_update IMAGE_NAME OLD_IMAGE ISTAG CHECK_FUNCTION OC_ARGS
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Runs an image update test with [image] uploaded to [is] imagestream
|
|
|
d988f44 |
# and checks the services using an arbitrary function provided in [check_function].
|
|
|
d988f44 |
# Arguments: image_name - prefix or whole ID of the pod to run the cmd in (compulsory)
|
|
|
d988f44 |
# Arguments: old_image - valid name of the image from the registry
|
|
|
d988f44 |
# Arguments: istag - imagestream to upload the images into (compulsory)
|
|
|
d988f44 |
# Arguments: check_function - command to be run to check functionality of created services (compulsory)
|
|
|
d988f44 |
# Arguments: oc_args - arguments to use during oc new-app (compulsory)
|
|
|
d988f44 |
ct_os_test_image_update() {
|
|
|
d988f44 |
local image_name=$1; shift
|
|
|
d988f44 |
local old_image=$1; shift
|
|
|
d988f44 |
local istag=$1; shift
|
|
|
d988f44 |
local check_function=$1; shift
|
|
|
d988f44 |
local service_name=${image_name##*/}
|
|
|
d988f44 |
local ip="" check_command_exp=""
|
|
|
d988f44 |
|
|
|
d988f44 |
echo "Running image update test for: $image_name"
|
|
|
d988f44 |
# shellcheck disable=SC2119
|
|
|
d988f44 |
ct_os_new_project
|
|
|
d988f44 |
|
|
|
d988f44 |
# Get current image from repository and create an imagestream
|
|
|
d988f44 |
docker pull "$old_image:latest" 2>/dev/null
|
|
|
d988f44 |
ct_os_upload_image "$old_image" "$istag"
|
|
|
d988f44 |
|
|
|
d988f44 |
# Setup example application with curent image
|
|
|
d988f44 |
oc new-app "$@" --name "$service_name"
|
|
|
d988f44 |
ct_os_wait_pod_ready "$service_name" 60
|
|
|
d988f44 |
|
|
|
d988f44 |
# Check application output
|
|
|
d988f44 |
ip=$(ct_os_get_service_ip "$service_name")
|
|
|
d988f44 |
check_command_exp=${check_function//<IP>/$ip}
|
|
|
d988f44 |
ct_assert_cmd_success "$check_command_exp"
|
|
|
d988f44 |
|
|
|
d988f44 |
# Tag built image into the imagestream and wait for rebuild
|
|
|
d988f44 |
ct_os_upload_image "$image_name" "$istag"
|
|
|
d988f44 |
ct_os_wait_pod_ready "${service_name}-2" 60
|
|
|
d988f44 |
|
|
|
d988f44 |
# Check application output
|
|
|
d988f44 |
ip=$(ct_os_get_service_ip "$service_name")
|
|
|
d988f44 |
check_command_exp=${check_function//<IP>/$ip}
|
|
|
d988f44 |
ct_assert_cmd_success "$check_command_exp"
|
|
|
d988f44 |
|
|
|
d988f44 |
# shellcheck disable=SC2119
|
|
|
d988f44 |
ct_os_delete_project
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_deploy_cmd_image IMAGE_NAME
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Runs a special command pod, a pod that does nothing, but includes utilities for testing.
|
|
|
d988f44 |
# A typical usage is a mysql pod that includes mysql commandline, that we need for testing.
|
|
|
d988f44 |
# Running commands inside this command pod is done via ct_os_cmd_image_run function.
|
|
|
d988f44 |
# The pod is not run again if already running.
|
|
|
d988f44 |
# Arguments: image_name - image to be used as a command pod
|
|
|
d988f44 |
function ct_os_deploy_cmd_image() {
|
|
|
d988f44 |
local image_name=${1}
|
|
|
d988f44 |
oc get pod command-app &>/dev/null && echo "command POD already running" && return 0
|
|
|
d988f44 |
echo "command POD not running yet, will start one called command-app"
|
|
|
d988f44 |
oc create -f - <
|
|
|
d988f44 |
apiVersion: v1
|
|
|
d988f44 |
kind: Pod
|
|
|
d988f44 |
metadata:
|
|
|
d988f44 |
name: command-app
|
|
|
d988f44 |
spec:
|
|
|
d988f44 |
containers:
|
|
|
d988f44 |
- name: command-container
|
|
|
d988f44 |
image: "${image_name}"
|
|
|
d988f44 |
command: ["sleep"]
|
|
|
d988f44 |
args: ["3h"]
|
|
|
d988f44 |
restartPolicy: OnFailure
|
|
|
d988f44 |
EOF
|
|
|
d988f44 |
|
|
|
d988f44 |
SECONDS=0
|
|
|
d988f44 |
echo -n "Waiting for command POD ."
|
|
|
d988f44 |
while [ $SECONDS -lt 180 ] ; do
|
|
|
d988f44 |
# shellcheck disable=SC2016
|
|
|
d988f44 |
sout="$(ct_os_cmd_image_run 'echo $((11*11))' 2>/dev/null)"
|
|
|
d988f44 |
# shellcheck disable=SC2015
|
|
|
d988f44 |
grep -q '^121$' <<< "$sout" && echo "DONE" && return 0 || :
|
|
|
d988f44 |
sleep 3
|
|
|
d988f44 |
echo -n "."
|
|
|
d988f44 |
done
|
|
|
d988f44 |
echo "FAIL"
|
|
|
d988f44 |
return 1
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_cmd_image_run CMD [ ARG ... ]
|
|
|
d988f44 |
# --------------------
|
|
|
d988f44 |
# Runs a command CMD inside a special command pod
|
|
|
d988f44 |
# Arguments: cmd - shell command with args to run in a pod
|
|
|
d988f44 |
function ct_os_cmd_image_run() {
|
|
|
d988f44 |
oc exec command-app -- bash -c "$@"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_test_response_internal
|
|
|
d988f44 |
# ----------------
|
|
|
d988f44 |
# Perform GET request to the application container, checks output with
|
|
|
d988f44 |
# a reg-exp and HTTP response code.
|
|
|
d988f44 |
# That all is done inside an image in the cluster, so the function is used
|
|
|
d988f44 |
# typically in clusters that are not accessible outside.
|
|
|
d988f44 |
# The interanal image is a python image that should include the most of the useful commands.
|
|
|
d988f44 |
# The check is repeated until timeout.
|
|
|
d988f44 |
# Argument: url - request URL path
|
|
|
d988f44 |
# Argument: expected_code - expected HTTP response code
|
|
|
d988f44 |
# Argument: body_regexp - PCRE regular expression that must match the response body
|
|
|
d988f44 |
# Argument: max_attempts - Optional number of attempts (default: 20), three seconds sleep between
|
|
|
d988f44 |
# Argument: ignore_error_attempts - Optional number of attempts when we ignore error output (default: 10)
|
|
|
d988f44 |
ct_os_test_response_internal() {
|
|
|
d988f44 |
local url="$1"
|
|
|
d988f44 |
local expected_code="$2"
|
|
|
d988f44 |
local body_regexp="$3"
|
|
|
d988f44 |
local max_attempts=${4:-20}
|
|
|
d988f44 |
local ignore_error_attempts=${5:-10}
|
|
|
d988f44 |
|
|
|
d988f44 |
: " Testing the HTTP(S) response for <${url}>"
|
|
|
d988f44 |
local sleep_time=3
|
|
|
d988f44 |
local attempt=1
|
|
|
d988f44 |
local result=1
|
|
|
d988f44 |
local status
|
|
|
d988f44 |
local response_code
|
|
|
d988f44 |
local response_file
|
|
|
d988f44 |
local util_image_name='python:3.6'
|
|
|
d988f44 |
|
|
|
d988f44 |
response_file=$(mktemp /tmp/ct_test_response_XXXXXX)
|
|
|
d988f44 |
ct_os_deploy_cmd_image "${util_image_name}"
|
|
|
d988f44 |
|
|
|
d988f44 |
while [ "${attempt}" -le "${max_attempts}" ]; do
|
|
|
d988f44 |
ct_os_cmd_image_run "curl --connect-timeout 10 -s -w '%{http_code}' '${url}'" >"${response_file}" && status=0 || status=1
|
|
|
d988f44 |
if [ "${status}" -eq 0 ]; then
|
|
|
d988f44 |
response_code=$(tail -c 3 "${response_file}")
|
|
|
d988f44 |
if [ "${response_code}" -eq "${expected_code}" ]; then
|
|
|
d988f44 |
result=0
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
grep -qP -e "${body_regexp}" "${response_file}" || result=1;
|
|
|
d988f44 |
# Some services return 40x code until they are ready, so let's give them
|
|
|
d988f44 |
# some chance and not end with failure right away
|
|
|
d988f44 |
# Do not wait if we already have expected outcome though
|
|
|
d988f44 |
if [ "${result}" -eq 0 ] || [ "${attempt}" -gt "${ignore_error_attempts}" ] || [ "${attempt}" -eq "${max_attempts}" ] ; then
|
|
|
d988f44 |
break
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
attempt=$(( attempt + 1 ))
|
|
|
d988f44 |
sleep "${sleep_time}"
|
|
|
d988f44 |
done
|
|
|
d988f44 |
rm -f "${response_file}"
|
|
|
d988f44 |
return "${result}"
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_get_image_from_pod
|
|
|
d988f44 |
# ------------------------
|
|
|
d988f44 |
# Print image identifier from an existing pod to stdout
|
|
|
d988f44 |
# Argument: pod_prefix - prefix or full name of the pod to get image from
|
|
|
d988f44 |
ct_os_get_image_from_pod() {
|
|
|
d988f44 |
local pod_prefix=$1 ; shift
|
|
|
d988f44 |
local pod_name
|
|
|
d988f44 |
pod_name=$(ct_os_get_pod_name "$pod_prefix")
|
|
|
d988f44 |
oc get "po/${pod_name}" -o yaml | sed -ne 's/^\s*image:\s*\(.*\)\s*$/\1/ p' | head -1
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# ct_os_check_cmd_internal
|
|
|
d988f44 |
# ----------------
|
|
|
d988f44 |
# Runs a specified command, checks exit code and compares the output with expected regexp.
|
|
|
d988f44 |
# That all is done inside an image in the cluster, so the function is used
|
|
|
d988f44 |
# typically in clusters that are not accessible outside.
|
|
|
d988f44 |
# The check is repeated until timeout.
|
|
|
d988f44 |
# Argument: util_image_name - name of the image in the cluster that is used for running the cmd
|
|
|
d988f44 |
# Argument: service_name - kubernetes' service name to work with (IP address is taken from this one)
|
|
|
d988f44 |
# Argument: check_command - command that is run within the util_image_name container
|
|
|
d988f44 |
# Argument: expected_content_match - regexp that must be in the output (use .* to ignore check)
|
|
|
d988f44 |
# Argument: timeout - number of seconds to wait till the check succeeds
|
|
|
d988f44 |
function ct_os_check_cmd_internal() {
|
|
|
d988f44 |
local util_image_name=$1 ; shift
|
|
|
d988f44 |
local service_name=$1 ; shift
|
|
|
d988f44 |
local check_command=$1 ; shift
|
|
|
d988f44 |
local expected_content_match=${1:-.*} ; shift
|
|
|
d988f44 |
local timeout=${1:-60} ; shift || :
|
|
|
d988f44 |
|
|
|
d988f44 |
: " Service ${service_name} check ..."
|
|
|
d988f44 |
|
|
|
d988f44 |
local output
|
|
|
d988f44 |
local ret
|
|
|
d988f44 |
local ip
|
|
|
d988f44 |
local check_command_exp
|
|
|
d988f44 |
|
|
|
d988f44 |
ip=$(ct_os_get_service_ip "${service_name}")
|
|
|
d988f44 |
# shellcheck disable=SC2001
|
|
|
d988f44 |
check_command_exp=$(echo "$check_command" | sed -e "s/<IP>/$ip/g")
|
|
|
d988f44 |
|
|
|
d988f44 |
ct_os_deploy_cmd_image "$(ct_os_get_image_from_pod "${util_image_name##*/}" | head -n 1)"
|
|
|
d988f44 |
SECONDS=0
|
|
|
d988f44 |
|
|
|
d988f44 |
echo -n "Waiting for ${service_name} service becoming ready ..."
|
|
|
d988f44 |
while true ; do
|
|
|
d988f44 |
output=$(ct_os_cmd_image_run "$check_command_exp")
|
|
|
d988f44 |
ret=$?
|
|
|
d988f44 |
echo "${output}" | grep -qe "${expected_content_match}" || ret=1
|
|
|
d988f44 |
if [ ${ret} -eq 0 ] ; then
|
|
|
d988f44 |
echo " PASS"
|
|
|
d988f44 |
return 0
|
|
|
d988f44 |
fi
|
|
|
d988f44 |
echo -n "."
|
|
|
d988f44 |
[ ${SECONDS} -gt "${timeout}" ] && break
|
|
|
d988f44 |
sleep 3
|
|
|
d988f44 |
done
|
|
|
d988f44 |
echo " FAIL"
|
|
|
d988f44 |
return 1
|
|
|
d988f44 |
}
|
|
|
d988f44 |
|
|
|
d988f44 |
# vim: set tabstop=2:shiftwidth=2:expandtab:
|