hack/test-end-to-end.sh
5541f577
 #!/bin/bash
 
 # This script tests the high level end-to-end functionality demonstrated
6d660e3d
 # as part of the examples/sample-app
5541f577
 
cfc65438
 if [[ -z "$(which iptables)" ]]; then
466b5c3a
 	echo "IPTables not found - the end-to-end test requires a system with iptables for Kubernetes services."
 	exit 1
cfc65438
 fi
4fc93a99
 iptables --list > /dev/null 2>&1
 if [ $? -ne 0 ]; then
466b5c3a
 	sudo iptables --list > /dev/null 2>&1
 	if [ $? -ne 0 ]; then
 		echo "You do not have iptables or sudo privileges.	Kubernetes services will not work without iptables access.	See https://github.com/GoogleCloudPlatform/kubernetes/issues/1859.	Try 'sudo hack/test-end-to-end.sh'."
 		exit 1
 	fi
4fc93a99
 fi
 
5541f577
 set -o errexit
 set -o nounset
 set -o pipefail
 
e3bb13a1
 OS_ROOT=$(dirname "${BASH_SOURCE}")/..
 source "${OS_ROOT}/hack/util.sh"
 
2cf3cf74
 echo "[INFO] Starting end-to-end test"
5541f577
 
776b67b2
 # Use either the latest release built images, or latest.
 if [[ -z "${USE_IMAGES-}" ]]; then
 	USE_IMAGES='openshift/origin-${component}:latest'
 	if [[ -e "${OS_ROOT}/_output/local/releases/.commit" ]]; then
 		COMMIT="$(cat "${OS_ROOT}/_output/local/releases/.commit")"
 		USE_IMAGES="openshift/origin-\${component}:${COMMIT}"
 	fi
 fi
 
6bfba153
 ROUTER_TESTS_ENABLED="${ROUTER_TESTS_ENABLED:-true}"
c705715f
 TEST_ASSETS="${TEST_ASSETS:-false}"
5541f577
 
1a0786b4
 if [[ -z "${BASETMPDIR-}" ]]; then
466b5c3a
 	TMPDIR="${TMPDIR:-"/tmp"}"
 	BASETMPDIR="${TMPDIR}/openshift-e2e"
 	sudo rm -rf "${BASETMPDIR}"
 	mkdir -p "${BASETMPDIR}"
1a0786b4
 fi
366baa89
 ETCD_DATA_DIR="${BASETMPDIR}/etcd"
 VOLUME_DIR="${BASETMPDIR}/volumes"
40be29be
 FAKE_HOME_DIR="${BASETMPDIR}/openshift.local.home"
366baa89
 LOG_DIR="${LOG_DIR:-${BASETMPDIR}/logs}"
 ARTIFACT_DIR="${ARTIFACT_DIR:-${BASETMPDIR}/artifacts}"
87192d34
 mkdir -p $LOG_DIR
c773c9cf
 mkdir -p $ARTIFACT_DIR
30380339
 
c9768a7d
 DEFAULT_SERVER_IP=`ifconfig | grep -Ev "(127.0.0.1|172.17.42.1)" | grep "inet " | head -n 1 | sed 's/adr://' | awk '{print $2}'`
30380339
 API_HOST="${API_HOST:-${DEFAULT_SERVER_IP}}"
ab7ef450
 API_PORT="${API_PORT:-8443}"
 API_SCHEME="${API_SCHEME:-https}"
30380339
 MASTER_ADDR="${API_SCHEME}://${API_HOST}:${API_PORT}"
961eecb6
 PUBLIC_MASTER_HOST="${PUBLIC_MASTER_HOST:-${API_HOST}}"
53c7aa34
 KUBELET_SCHEME="${KUBELET_SCHEME:-https}"
 KUBELET_HOST="${KUBELET_HOST:-127.0.0.1}"
e3bb13a1
 KUBELET_PORT="${KUBELET_PORT:-10250}"
 
40be29be
 SERVER_CONFIG_DIR="${BASETMPDIR}/openshift.local.config"
 MASTER_CONFIG_DIR="${SERVER_CONFIG_DIR}/master"
 NODE_CONFIG_DIR="${SERVER_CONFIG_DIR}/node-${KUBELET_HOST}"
 
ab7ef450
 # use the docker bridge ip address until there is a good way to get the auto-selected address from master
 # this address is considered stable
d1326a10
 # used as a resolve IP to test routing
028b5f55
 CONTAINER_ACCESSIBLE_API_HOST="${CONTAINER_ACCESSIBLE_API_HOST:-172.17.42.1}"
ab7ef450
 
2cf3cf74
 STI_CONFIG_FILE="${LOG_DIR}/stiAppConfig.json"
 DOCKER_CONFIG_FILE="${LOG_DIR}/dockerAppConfig.json"
 CUSTOM_CONFIG_FILE="${LOG_DIR}/customAppConfig.json"
e3bb13a1
 GO_OUT="${OS_ROOT}/_output/local/go/bin"
5541f577
 
cfc65438
 # set path so OpenShift is available
 export PATH="${GO_OUT}:${PATH}"
5541f577
 
eeaac221
 
 function cleanup()
5541f577
 {
466b5c3a
 	out=$?
 	echo
 	if [ $out -ne 0 ]; then
 		echo "[FAIL] !!!!! Test Failed !!!!"
 	else
 		echo "[INFO] Test Succeeded"
 	fi
 	echo
 
22d4002c
 	set +e
466b5c3a
 	echo "[INFO] Dumping container logs to ${LOG_DIR}"
 	for container in $(docker ps -aq); do
 		docker logs "$container" >&"${LOG_DIR}/container-$container.log"
 	done
 
 	echo "[INFO] Dumping build log to ${LOG_DIR}"
 
2d3b17b9
 	osc get -n test builds --output-version=v1beta1 -t '{{ range .items }}{{.metadata.name}}{{ "\n" }}{{end}}' | xargs -r -l osc build-logs -n test >"${LOG_DIR}/stibuild.log"
 	osc get -n docker builds --output-version=v1beta1 -t '{{ range .items }}{{.metadata.name}}{{ "\n" }}{{end}}' | xargs -r -l osc build-logs -n docker >"${LOG_DIR}/dockerbuild.log"
 	osc get -n custom builds --output-version=v1beta1 -t '{{ range .items }}{{.metadata.name}}{{ "\n" }}{{end}}' | xargs -r -l osc build-logs -n custom >"${LOG_DIR}/custombuild.log"
53c7aa34
 
 	echo "[INFO] Dumping etcd contents to ${ARTIFACT_DIR}/etcd_dump.json"
 	set_curl_args 0 1
 	curl ${clientcert_args} -L "${API_SCHEME}://${API_HOST}:4001/v2/keys/?recursive=true" > "${ARTIFACT_DIR}/etcd_dump.json"
466b5c3a
 	echo
 
 	if [[ -z "${SKIP_TEARDOWN-}" ]]; then
 		echo "[INFO] Tearing down test"
 		pids="$(jobs -pr)"
 		echo "[INFO] Children: ${pids}"
 		sudo kill ${pids}
 		sudo ps f
 		set +u
5baccde3
 		echo "[INFO] Stopping k8s docker containers"; docker ps | awk 'index($NF,"k8s_")==1 { print $1 }' | xargs -l -r docker stop
466b5c3a
 		if [[ -z "${SKIP_IMAGE_CLEANUP-}" ]]; then
5baccde3
 			echo "[INFO] Removing k8s docker containers"; docker ps -a | awk 'index($NF,"k8s_")==1 { print $1 }' | xargs -l -r docker rm
466b5c3a
 		fi
 		set -u
 	fi
 	set -e
 
 	# clean up zero byte log files
 	# Clean up large log files so they don't end up on jenkins
 	find ${ARTIFACT_DIR} -name *.log -size +20M -exec echo Deleting {} because it is too big. \; -exec rm -f {} \;
 	find ${LOG_DIR} -name *.log -size +20M -exec echo Deleting {} because it is too big. \; -exec rm -f {} \;
 	find ${LOG_DIR} -name *.log -size 0 -exec echo Deleting {} because it is empty. \; -exec rm -f {} \;
 
 	echo "[INFO] Exiting"
 	exit $out
5541f577
 }
 
eeaac221
 trap "exit" INT TERM
 trap "cleanup" EXIT
 
2cf3cf74
 function wait_for_app() {
466b5c3a
 	echo "[INFO] Waiting for app in namespace $1"
 	echo "[INFO] Waiting for database pod to start"
cf2a6754
 	wait_for_command "osc get -n $1 pods -l name=database | grep -i Running" $((60*TIME_SEC))
2cf3cf74
 
466b5c3a
 	echo "[INFO] Waiting for database service to start"
 	wait_for_command "osc get -n $1 services | grep database" $((20*TIME_SEC))
2d3b17b9
 	DB_IP=$(osc get -n $1 --output-version=v1beta1 --template="{{ .portalIP }}" service database)
2cf3cf74
 
466b5c3a
 	echo "[INFO] Waiting for frontend pod to start"
 	wait_for_command "osc get -n $1 pods | grep frontend | grep -i Running" $((120*TIME_SEC))
2cf3cf74
 
466b5c3a
 	echo "[INFO] Waiting for frontend service to start"
 	wait_for_command "osc get -n $1 services | grep frontend" $((20*TIME_SEC))
2d3b17b9
 	FRONTEND_IP=$(osc get -n $1 --output-version=v1beta1 --template="{{ .portalIP }}" service frontend)
2cf3cf74
 
466b5c3a
 	echo "[INFO] Waiting for database to start..."
 	wait_for_url_timed "http://${DB_IP}:5434" "[INFO] Database says: " $((3*TIME_MIN))
2cf3cf74
 
466b5c3a
 	echo "[INFO] Waiting for app to start..."
cab06f2e
 	wait_for_url_timed "http://${FRONTEND_IP}:5432" "[INFO] Frontend says: " $((2*TIME_MIN))
c4c8c236
 
 	echo "[INFO] Testing app"
 	wait_for_command '[[ "$(curl -s -X POST http://${FRONTEND_IP}:5432/keys/foo -d value=1337)" = "Key created" ]]'
 	wait_for_command '[[ "$(curl -s http://${FRONTEND_IP}:5432/keys/foo)" = "1337" ]]'
2cf3cf74
 }
 
 # Wait for builds to complete
 # $1 namespace
 function wait_for_build() {
466b5c3a
 	echo "[INFO] Waiting for $1 namespace build to complete"
 	wait_for_command "osc get -n $1 builds | grep -i complete" $((10*TIME_MIN)) "osc get -n $1 builds | grep -i -e failed -e error"
2d3b17b9
 	BUILD_ID=`osc get -n $1 builds --output-version=v1beta1 -t "{{with index .items 0}}{{.metadata.name}}{{end}}"`
466b5c3a
 	echo "[INFO] Build ${BUILD_ID} finished"
bab21a83
   # TODO: fix
   set +e
466b5c3a
 	osc build-logs -n $1 $BUILD_ID > $LOG_DIR/$1build.log
bab21a83
   set -e
2cf3cf74
 }
 
cfc65438
 # Setup
 stop_openshift_server
 echo "[INFO] `openshift version`"
6401bcd6
 echo "[INFO] Server logs will be at:    ${LOG_DIR}/openshift.log"
366baa89
 echo "[INFO] Test artifacts will be in: ${ARTIFACT_DIR}"
6401bcd6
 echo "[INFO] Volumes dir is:            ${VOLUME_DIR}"
40be29be
 echo "[INFO] Config dir is:             ${SERVER_CONFIG_DIR}"
776b67b2
 echo "[INFO] Using images:              ${USE_IMAGES}"
5541f577
 
 # Start All-in-one server and wait for health
30380339
 echo "[INFO] Create certificates for the OpenShift server"
 # find the same IP that openshift start will bind to.  This allows access from pods that have to talk back to master
c9768a7d
 ALL_IP_ADDRESSES=`ifconfig | grep "inet " | sed 's/adr://' | awk '{print $2}'`
30380339
 SERVER_HOSTNAME_LIST="${PUBLIC_MASTER_HOST},localhost"
 while read -r IP_ADDRESS
 do
 	SERVER_HOSTNAME_LIST="${SERVER_HOSTNAME_LIST},${IP_ADDRESS}"
 done <<< "${ALL_IP_ADDRESSES}"
 
53c7aa34
 openshift admin create-master-certs \
40be29be
 	--overwrite=false \
 	--cert-dir="${MASTER_CONFIG_DIR}" \
 	--hostnames="${SERVER_HOSTNAME_LIST}" \
 	--master="${MASTER_ADDR}" \
 	--public-master="${API_SCHEME}://${PUBLIC_MASTER_HOST}"
53c7aa34
 
 openshift admin create-node-config \
40be29be
 	--listen="${KUBELET_SCHEME}://0.0.0.0:${KUBELET_PORT}" \
 	--node-dir="${NODE_CONFIG_DIR}" \
 	--node="${KUBELET_HOST}" \
 	--hostnames="${KUBELET_HOST}" \
 	--master="${MASTER_ADDR}" \
 	--node-client-certificate-authority="${MASTER_CONFIG_DIR}/ca.crt" \
 	--certificate-authority="${MASTER_CONFIG_DIR}/ca.crt" \
 	--signer-cert="${MASTER_CONFIG_DIR}/ca.crt" \
 	--signer-key="${MASTER_CONFIG_DIR}/ca.key" \
 	--signer-serial="${MASTER_CONFIG_DIR}/ca.serial.txt"
 
 osadm create-bootstrap-policy-file --filename="${MASTER_CONFIG_DIR}/policy.json"
 
 # create openshift config
 openshift start \
 	--write-config=${SERVER_CONFIG_DIR} \
 	--create-certs=false \
     --listen="${API_SCHEME}://0.0.0.0:${API_PORT}" \
     --master="${MASTER_ADDR}" \
     --public-master="${API_SCHEME}://${PUBLIC_MASTER_HOST}" \
     --hostname="${KUBELET_HOST}" \
     --volume-dir="${VOLUME_DIR}" \
     --etcd-dir="${ETCD_DATA_DIR}" \
     --images="${USE_IMAGES}"
 
30380339
 
9de089a8
 echo "[INFO] Starting OpenShift server"
8fb6ec59
 sudo env "PATH=${PATH}" OPENSHIFT_PROFILE=web OPENSHIFT_ON_PANIC=crash openshift start \
40be29be
 	--master-config=${MASTER_CONFIG_DIR}/master-config.yaml \
 	--node-config=${NODE_CONFIG_DIR}/node-config.yaml \
     --loglevel=4 \
     &> "${LOG_DIR}/openshift.log" &
cfc65438
 OS_PID=$!
cab06f2e
 
40be29be
 export HOME="${FAKE_HOME_DIR}"
5541f577
 
366baa89
 if [[ "${API_SCHEME}" == "https" ]]; then
40be29be
 	export CURL_CA_BUNDLE="${MASTER_CONFIG_DIR}/ca.crt"
 	export CURL_CERT="${MASTER_CONFIG_DIR}/admin.crt"
 	export CURL_KEY="${MASTER_CONFIG_DIR}/admin.key"
 
 	# Make osc use ${MASTER_CONFIG_DIR}/admin.kubeconfig, and ignore anything in the running user's $HOME dir
 	export OPENSHIFTCONFIG="${MASTER_CONFIG_DIR}/admin.kubeconfig"
 	sudo chmod -R a+rwX "${OPENSHIFTCONFIG}"
ce40bd34
 	echo "[INFO] To debug: export OPENSHIFTCONFIG=$OPENSHIFTCONFIG"
ab7ef450
 fi
5541f577
 
53c7aa34
 wait_for_url "${KUBELET_SCHEME}://${KUBELET_HOST}:${KUBELET_PORT}/healthz" "[INFO] kubelet: " 0.5 60
6401bcd6
 wait_for_url "${API_SCHEME}://${API_HOST}:${API_PORT}/healthz" "apiserver: " 0.25 80
53c7aa34
 wait_for_url "${API_SCHEME}://${API_HOST}:${API_PORT}/api/v1beta1/minions/${KUBELET_HOST}" "apiserver(minions): " 0.25 80
6401bcd6
 
30380339
 # add e2e-user as a viewer for the default namespace so we can see infrastructure pieces appear
a600f8ce
 openshift admin policy add-role-to-user view e2e-user --namespace=default
30380339
 
961eecb6
 # create test project so that this shows up in the console
a600f8ce
 openshift admin new-project test --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"
f07b2e98
 openshift admin new-project docker --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"
 openshift admin new-project custom --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"
c98eb29f
 openshift admin new-project cache --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"
961eecb6
 
ccb307cf
 echo "The console should be available at ${API_SCHEME}://${PUBLIC_MASTER_HOST}:${API_PORT}/console."
4258b754
 echo "Log in as 'e2e-user' to see the 'test' project."
961eecb6
 
fbfd1713
 # install the router
 echo "[INFO] Installing the router"
40be29be
 openshift admin router --create --credentials="${MASTER_CONFIG_DIR}/openshift-router.kubeconfig" --images="${USE_IMAGES}"
961eecb6
 
22d4002c
 # install the registry. The --mount-host option is provided to reuse local storage.
fbfd1713
 echo "[INFO] Installing the registry"
c98eb29f
 openshift admin registry --create --credentials="${MASTER_CONFIG_DIR}/openshift-registry.kubeconfig" --mount-host="/tmp/openshift.local.registry" --images="${USE_IMAGES}"
5541f577
 
cf2a6754
 echo "[INFO] Pre-pulling and pushing ruby-20-centos7"
 docker pull openshift/ruby-20-centos7:latest
 echo "[INFO] Pulled ruby-20-centos7"
5541f577
 
22d4002c
 echo "[INFO] Waiting for Docker registry pod to start"
 # TODO: simplify when #4702 is fixed upstream
2d3b17b9
 wait_for_command '[[ "$(osc get endpoints docker-registry --output-version=v1beta1 -t "{{ if .endpoints }}{{ len .endpoints }}{{ else }}0{{ end }}" || echo "0")" != "0" ]]' $((5*TIME_MIN))
cfc65438
 
466b5c3a
 # services can end up on any IP.	Make sure we get the IP we need for the docker registry
1dcda276
 DOCKER_REGISTRY=$(osc get --output-version=v1beta3 --template="{{ .spec.portalIP }}:{{ with index .spec.ports 0 }}{{ .port }}{{ end }}" service docker-registry)
5541f577
 
22d4002c
 echo "[INFO] Verifying the docker-registry is up at ${DOCKER_REGISTRY}"
bfacaf33
 wait_for_url_timed "http://${DOCKER_REGISTRY}/v2/" "[INFO] Docker registry says: " $((2*TIME_MIN))
8defe754
 
3befb47d
 [ "$(dig @${API_HOST} "docker-registry.default.local." A)" ]
 
c98eb29f
 # Client setup (log in as e2e-user and set 'test' as the default project)
 # This is required to be able to push to the registry!
 echo "[INFO] Logging in as a regular user (e2e-user:pass) with project 'test'..."
 osc login -u e2e-user -p pass
 osc project cache
33b7dabd
 token=$(osc config view --flatten -o template -t '{{with index .users 0}}{{.user.token}}{{end}}')
c98eb29f
 [[ -n ${token} ]]
 
 # TODO reenable this once we've got docker push secrets 100% ready
 #docker login -u e2e-user -p ${token} -e e2e-user@openshift.com ${DOCKER_REGISTRY}
 # TODO remove the following line once we've got docker push secrets 100% ready
 echo '{"apiVersion": "v1beta1", "kind": "ImageStream", "metadata": {"name": "ruby-20-centos7"}}' | osc create -f -
 
 docker tag -f openshift/ruby-20-centos7:latest ${DOCKER_REGISTRY}/cache/ruby-20-centos7:latest
 docker push ${DOCKER_REGISTRY}/cache/ruby-20-centos7:latest
cf2a6754
 echo "[INFO] Pushed ruby-20-centos7"
8defe754
 
c98eb29f
 echo "[INFO] Back to 'master' context with 'admin' user..."
 osc project default
 
f89cda25
 # Process template and create
aba61fe0
 echo "[INFO] Submitting application template json for processing..."
2cf3cf74
 osc process -n test -f examples/sample-app/application-template-stibuild.json > "${STI_CONFIG_FILE}"
 osc process -n docker -f examples/sample-app/application-template-dockerbuild.json > "${DOCKER_CONFIG_FILE}"
 osc process -n custom -f examples/sample-app/application-template-custombuild.json > "${CUSTOM_CONFIG_FILE}"
 
c98eb29f
 echo "[INFO] Back to 'test' context with 'e2e-user' user"
ce40bd34
 osc project test
 
2cf3cf74
 echo "[INFO] Applying STI application config"
ce40bd34
 osc create -f "${STI_CONFIG_FILE}"
5541f577
 
10a73724
 
c98eb29f
 # this needs to be done before waiting for the build because right now only cluster-admins can see build logs, because that uses proxy
10a73724
 echo "[INFO] Back to 'master' context with 'admin' user..."
 osc project default
16df0e88
 
5541f577
 # Trigger build
50f134ea
 echo "[INFO] Starting build from ${STI_CONFIG_FILE} and streaming its logs..."
ae1dca33
 #osc start-build -n test ruby-sample-build --follow
2cf3cf74
 wait_for_build "test"
 wait_for_app "test"
 
ad390e66
 #echo "[INFO] Applying Docker application config"
f89cda25
 #osc create -n docker -f "${DOCKER_CONFIG_FILE}"
ad390e66
 #echo "[INFO] Invoking generic web hook to trigger new docker build using curl"
 #curl -k -X POST $API_SCHEME://$API_HOST:$API_PORT/osapi/v1beta1/buildConfigHooks/ruby-sample-build/secret101/generic?namespace=docker && sleep 3
 #wait_for_build "docker"
 #wait_for_app "docker"
 
 #echo "[INFO] Applying Custom application config"
f89cda25
 #osc create -n custom -f "${CUSTOM_CONFIG_FILE}"
ad390e66
 #echo "[INFO] Invoking generic web hook to trigger new custom build using curl"
 #curl -k -X POST $API_SCHEME://$API_HOST:$API_PORT/osapi/v1beta1/buildConfigHooks/ruby-sample-build/secret101/generic?namespace=custom && sleep 3
 #wait_for_build "custom"
 #wait_for_app "custom"
6bfba153
 
fbfd1713
 # ensure the router is started
22d4002c
 # TODO: simplify when #4702 is fixed upstream
2d3b17b9
 wait_for_command '[[ "$(osc get endpoints router --output-version=v1beta1 -t "{{ if .endpoints }}{{ len .endpoints }}{{ else }}0{{ end }}" || echo "0")" != "0" ]]' $((5*TIME_MIN))
6bfba153
 
fbfd1713
 echo "[INFO] Validating routed app response..."
 validate_response "-s -k --resolve www.example.com:443:${CONTAINER_ACCESSIBLE_API_HOST} https://www.example.com" "Hello from OpenShift" 0.2 50
c705715f
 
87d9e2ab
 # Remote command execution
47e4f92d
 echo "[INFO] Validating exec"
d53a2fa2
 registry_pod=$(osc get pod | grep deployment=docker-registry | grep docker-registry | awk '{print $1}')
87d9e2ab
 osc exec -p ${registry_pod} whoami | grep root
 
 # Port forwarding
47e4f92d
 echo "[INFO] Validating port-forward"
50eb1bbd
 osc port-forward -p ${registry_pod} 5001:5000  &> "${LOG_DIR}/port-forward.log" &
c98eb29f
 wait_for_url_timed "http://localhost:5001/healthz" "[INFO] Docker registry says: " $((10*TIME_SEC))
87d9e2ab
 
c705715f
 # UI e2e tests can be found in assets/test/e2e
 if [[ "$TEST_ASSETS" == "true" ]]; then
 	echo "[INFO] Running UI e2e tests..."
 	pushd ${OS_ROOT}/assets > /dev/null
 		grunt test-e2e
 	popd > /dev/null
 fi