Browse code

make end-to-end-docker a full test

deads2k authored on 2015/09/10 02:25:53
Showing 5 changed files
... ...
@@ -118,7 +118,6 @@ test:
118 118
 	hack/test-cmd.sh
119 119
 	KUBE_RACE=" " hack/test-integration-docker.sh
120 120
 	hack/test-end-to-end-docker.sh
121
-	hack/test-end-to-end.sh
122 121
 ifeq ($(EXTENDED),true)
123 122
 	hack/test-extended.sh
124 123
 endif
... ...
@@ -12,183 +12,103 @@ source "${OS_ROOT}/hack/util.sh"
12 12
 
13 13
 echo "[INFO] Starting containerized end-to-end test"
14 14
 
15
-# Use either the latest release built images, or latest.
16
-if [[ -z "${USE_IMAGES-}" ]]; then
17
-  tag="latest"
18
-  if [[ -e "${OS_ROOT}/_output/local/releases/.commit" ]]; then
19
-    COMMIT="$(cat "${OS_ROOT}/_output/local/releases/.commit")"
20
-    tag="${COMMIT}"
21
-  fi
22
-  USE_IMAGES="openshift/origin-\${component}:${tag}"
23
-fi
24
-
25 15
 unset KUBECONFIG
26 16
 
27
-if [[ -z "${BASETMPDIR-}" ]]; then
28
-  TMPDIR="${TMPDIR:-"/tmp"}"
29
-  BASETMPDIR="${TMPDIR}/openshift-e2e-containerized"
30
-  sudo rm -rf "${BASETMPDIR}"
31
-  mkdir -p "${BASETMPDIR}"
32
-fi
17
+TMPDIR="${TMPDIR:-"/tmp"}"
18
+BASETMPDIR="${BASETMPDIR:-${TMPDIR}/openshift-e2e-containerized}"
19
+setup_env_vars
20
+reset_tmp_dir
33 21
 
34
-VOLUME_DIR="${BASETMPDIR}/volumes"
35 22
 # when selinux is enforcing, the volume dir selinux label needs to be
36 23
 # svirt_sandbox_file_t
37 24
 #
38 25
 # TODO: fix the selinux policy to either allow openshift_var_lib_dir_t
39 26
 # or to default the volume dir to svirt_sandbox_file_t.
40
-sudo mkdir -p ${VOLUME_DIR}
41 27
 if selinuxenabled; then
42
-  sudo chcon -t svirt_sandbox_file_t ${VOLUME_DIR}
28
+	sudo chcon -t svirt_sandbox_file_t ${VOLUME_DIR}
43 29
 fi
44 30
 
45
-FAKE_HOME_DIR="${BASETMPDIR}/openshift.local.home"
46
-LOG_DIR="${LOG_DIR:-${BASETMPDIR}/logs}"
47
-ARTIFACT_DIR="${ARTIFACT_DIR:-${BASETMPDIR}/artifacts}"
48
-mkdir -p $LOG_DIR
49
-mkdir -p $ARTIFACT_DIR
50
-
51
-GO_OUT="${OS_ROOT}/_output/local/go/bin"
52
-
53
-# set path so OpenShift is available
54
-export PATH="${GO_OUT}:${PATH}"
55
-
56
-
57 31
 function cleanup()
58 32
 {
59
-  out=$?
60
-  echo
61
-  if [ $out -ne 0 ]; then
62
-    echo "[FAIL] !!!!! Test Failed !!!!"
63
-  else
64
-    echo "[INFO] Test Succeeded"
65
-  fi
66
-  echo
67
-
68
-  set +e
69
-  dump_container_logs
70
-
71
-  if [[ -z "${SKIP_TEARDOWN-}" ]]; then
72
-    echo "[INFO] Deleting test constructs"
73
-    sudo docker exec origin oc delete -n test all --all
74
-    sudo docker exec origin oc delete -n default all --all
75
-
76
-    echo "[INFO] Waiting for volume mounts to be cleaned up"
77
-    wait_for_command '[[ "$(mount | grep pods | grep ${VOLUME_DIR} | wc -l)" = "0" ]]' $((120*TIME_SEC))
78
-
79
-    echo "[INFO] Tearing down test"
80
-    docker stop origin
81
-    docker rm origin
82
-
83
-    echo "[INFO] Stopping k8s docker containers"; docker ps | awk 'index($NF,"k8s_")==1 { print $1 }' | xargs -l -r docker stop
84
-    if [[ -z "${SKIP_IMAGE_CLEANUP-}" ]]; then
85
-      echo "[INFO] Removing k8s docker containers"; docker ps -a | awk 'index($NF,"k8s_")==1 { print $1 }' | xargs -l -r docker rm
86
-    fi
87
-    set -u
88
-  fi
89
-  set -e
90
-
91
-  delete_large_and_empty_logs
92
-
93
-  echo "[INFO] Exiting"
94
-  exit $out
33
+	out=$?
34
+	echo
35
+	if [ $out -ne 0 ]; then
36
+		echo "[FAIL] !!!!! Test Failed !!!!"
37
+	else
38
+		echo "[INFO] Test Succeeded"
39
+	fi
40
+	echo
41
+
42
+	set +e
43
+	dump_container_logs
44
+	
45
+	echo "[INFO] Dumping all resources to ${LOG_DIR}/export_all.json"
46
+	oc export all --all-namespaces --raw -o json --config=${ADMIN_KUBECONFIG} > ${LOG_DIR}/export_all.json
47
+
48
+	echo "[INFO] Dumping etcd contents to ${ARTIFACT_DIR}/etcd_dump.json"
49
+	set_curl_args 0 1
50
+	ETCD_PORT="${ETCD_PORT:-4001}"
51
+	curl ${clientcert_args} -L "${API_SCHEME}://${API_HOST}:${ETCD_PORT}/v2/keys/?recursive=true" > "${ARTIFACT_DIR}/etcd_dump.json"
52
+	echo
53
+
54
+	if [[ -z "${SKIP_TEARDOWN-}" ]]; then
55
+		echo "[INFO] remove the openshift container"
56
+		docker stop origin
57
+		docker rm origin
58
+
59
+		echo "[INFO] Stopping k8s docker containers"; docker ps | awk 'index($NF,"k8s_")==1 { print $1 }' | xargs -l -r docker stop
60
+		if [[ -z "${SKIP_IMAGE_CLEANUP-}" ]]; then
61
+			echo "[INFO] Removing k8s docker containers"; docker ps -a | awk 'index($NF,"k8s_")==1 { print $1 }' | xargs -l -r docker rm
62
+		fi
63
+		set -u
64
+	fi
65
+
66
+	delete_large_and_empty_logs
67
+	set -e
68
+
69
+	echo "[INFO] Exiting"
70
+	exit $out
95 71
 }
96 72
 
97 73
 trap "exit" INT TERM
98 74
 trap "cleanup" EXIT
99 75
 
100
-function wait_for_app() {
101
-  echo "[INFO] Waiting for app in namespace $1"
102
-  echo "[INFO] Waiting for database pod to start"
103
-  wait_for_command "oc get -n $1 pods -l name=database | grep -i Running" $((60*TIME_SEC))
104
-
105
-  echo "[INFO] Waiting for database service to start"
106
-  wait_for_command "oc get -n $1 services | grep database" $((20*TIME_SEC))
107
-  DB_IP=$(oc get -n $1 --output-version=v1beta3 --template="{{ .spec.portalIP }}" service database)
108
-
109
-  echo "[INFO] Waiting for frontend pod to start"
110
-  wait_for_command "oc get -n $1 pods | grep frontend | grep -i Running" $((120*TIME_SEC))
111
-
112
-  echo "[INFO] Waiting for frontend service to start"
113
-  wait_for_command "oc get -n $1 services | grep frontend" $((20*TIME_SEC))
114
-  FRONTEND_IP=$(oc get -n $1 --output-version=v1beta3 --template="{{ .spec.portalIP }}" service frontend)
115
-
116
-  echo "[INFO] Waiting for database to start..."
117
-  wait_for_url_timed "http://${DB_IP}:5434" "[INFO] Database says: " $((3*TIME_MIN))
118
-
119
-  echo "[INFO] Waiting for app to start..."
120
-  wait_for_url_timed "http://${FRONTEND_IP}:5432" "[INFO] Frontend says: " $((2*TIME_MIN))
121
-
122
-  echo "[INFO] Testing app"
123
-  wait_for_command '[[ "$(curl -s -X POST http://${FRONTEND_IP}:5432/keys/foo -d value=1337)" = "Key created" ]]'
124
-  wait_for_command '[[ "$(curl -s http://${FRONTEND_IP}:5432/keys/foo)" = "1337" ]]'
125
-}
126
-
127
-# Wait for builds to complete
128
-# $1 namespace
129
-function wait_for_build() {
130
-  echo "[INFO] Waiting for $1 namespace build to complete"
131
-  wait_for_command "oc get -n $1 builds | grep -i complete" $((10*TIME_MIN)) "oc get -n $1 builds | grep -i -e failed -e error"
132
-  BUILD_ID=`oc get -n $1 builds --output-version=v1beta3 -t "{{with index .items 0}}{{.metadata.name}}{{end}}"`
133
-  echo "[INFO] Build ${BUILD_ID} finished"
134
-  # TODO: fix
135
-  set +e
136
-  oc build-logs -n $1 $BUILD_ID > $LOG_DIR/$1build.log
137
-  set -e
138
-}
139
-
140 76
 out=$(
141
-  set +e
142
-  docker stop origin 2>&1
143
-  docker rm origin 2>&1
144
-  set -e
77
+	set +e
78
+	docker stop origin 2>&1
79
+	docker rm origin 2>&1
80
+	set -e
145 81
 )
146 82
 
147 83
 # Setup
148 84
 echo "[INFO] `openshift version`"
149
-echo "[INFO] Using images:              ${USE_IMAGES}"
85
+echo "[INFO] Using images:							${USE_IMAGES}"
150 86
 
151 87
 echo "[INFO] Starting OpenShift containerized server"
152 88
 sudo docker run -d --name="origin" \
153
-  --privileged --net=host \
154
-  -v /:/rootfs:ro -v /var/run:/var/run:rw -v /sys:/sys:ro -v /var/lib/docker:/var/lib/docker:rw \
155
-  -v "${VOLUME_DIR}:${VOLUME_DIR}" \
156
-  "openshift/origin:${tag}" start --volume-dir=${VOLUME_DIR} --images="${USE_IMAGES}"
89
+	--privileged --net=host --pid=host \
90
+	-v /:/rootfs:ro -v /var/run:/var/run:rw -v /sys:/sys:ro -v /var/lib/docker:/var/lib/docker:rw \
91
+	-v "${VOLUME_DIR}:${VOLUME_DIR}" \
92
+	"openshift/origin:${TAG}" start --loglevel=4 --volume-dir=${VOLUME_DIR} --images="${USE_IMAGES}"
157 93
 
158
-export HOME="${FAKE_HOME_DIR}"
159
-# This directory must exist so Docker can store credentials in $HOME/.dockercfg
160
-mkdir -p ${FAKE_HOME_DIR}
161 94
 
95
+# the CA is in the container, log in as a different cluster admin to run the test
162 96
 CURL_EXTRA="-k"
163
-
164 97
 wait_for_url "https://localhost:8443/healthz/ready" "apiserver(ready): " 0.25 160
165 98
 
166
-# install the router
167
-echo "[INFO] Installing the router"
168
-sudo docker exec origin bash -c "echo '{\"kind\":\"ServiceAccount\",\"apiVersion\":\"v1\",\"metadata\":{\"name\":\"router\"}}' | openshift cli create -f -"
169
-sudo docker exec origin bash -c "openshift cli get scc privileged -o json | sed '/\"users\"/a \"system:serviceaccount:default:router\",' | openshift cli replace scc privileged -f -"
170
-sudo docker exec origin openshift admin router --create --credentials="./openshift.local.config/master/openshift-router.kubeconfig" --images="${USE_IMAGES}" --service-account=router
171
-
172
-# install the registry. The --mount-host option is provided to reuse local storage.
173
-echo "[INFO] Installing the registry"
174
-sudo docker exec origin openshift admin registry --create --credentials="./openshift.local.config/master/openshift-registry.kubeconfig" --images="${USE_IMAGES}"
175
-
176
-registry="$(dig @localhost "docker-registry.default.svc.cluster.local." +short A | head -n 1)"
177
-[ -n "${registry}" ]
178
-echo "[INFO] Verifying the docker-registry is up at ${registry}"
179
-wait_for_url_timed "http://${registry}:5000/healthz" "[INFO] Docker registry says: " $((2*TIME_MIN))
99
+IMAGE_WORKING_DIR=/var/lib/openshift
100
+docker cp origin:${IMAGE_WORKING_DIR}/openshift.local.config ${BASETMPDIR}
180 101
 
102
+export ADMIN_KUBECONFIG="${MASTER_CONFIG_DIR}/admin.kubeconfig"
103
+export CLUSTER_ADMIN_CONTEXT=$(oc config view --config=${ADMIN_KUBECONFIG} --flatten -o template -t '{{index . "current-context"}}')
104
+sudo chmod -R a+rwX "${ADMIN_KUBECONFIG}"
105
+export KUBECONFIG="${ADMIN_KUBECONFIG}"
106
+echo "[INFO] To debug: export KUBECONFIG=$ADMIN_KUBECONFIG"
181 107
 
182
-echo "[INFO] Login"
183
-oc login localhost:8443 -u test -p test --insecure-skip-tls-verify
184
-oc new-project test
185 108
 
186
-echo "[INFO] Applying STI application config"
187
-oc new-app -f examples/sample-app/application-template-stibuild.json
109
+wait_for_url "${KUBELET_SCHEME}://${KUBELET_HOST}:${KUBELET_PORT}/healthz" "[INFO] kubelet: " 0.5 60
110
+wait_for_url "${API_SCHEME}://${API_HOST}:${API_PORT}/healthz" "apiserver: " 0.25 80
111
+wait_for_url "${API_SCHEME}://${API_HOST}:${API_PORT}/healthz/ready" "apiserver(ready): " 0.25 80
188 112
 
189
-# Wait for build which should have triggered automatically
190
-echo "[INFO] Starting build..."
191
-#oc start-build -n test ruby-sample-build --follow
192
-wait_for_build "test"
193
-wait_for_app "test"
194 113
 
114
+${OS_ROOT}/hack/test-end-to-end-scenario.sh
195 115
\ No newline at end of file
196 116
new file mode 100755
... ...
@@ -0,0 +1,258 @@
0
+#!/bin/bash
1
+
2
+# This script tests the high level end-to-end functionality demonstrated
3
+# as part of the examples/sample-app
4
+
5
+set -o errexit
6
+set -o nounset
7
+set -o pipefail
8
+
9
+OS_ROOT=$(dirname "${BASH_SOURCE}")/..
10
+source "${OS_ROOT}/hack/util.sh"
11
+
12
+ROUTER_TESTS_ENABLED="${ROUTER_TESTS_ENABLED:-true}"
13
+TEST_ASSETS="${TEST_ASSETS:-false}"
14
+
15
+
16
+function wait_for_app() {
17
+	echo "[INFO] Waiting for app in namespace $1"
18
+	echo "[INFO] Waiting for database pod to start"
19
+	wait_for_command "oc get -n $1 pods -l name=database | grep -i Running" $((60*TIME_SEC))
20
+
21
+	echo "[INFO] Waiting for database service to start"
22
+	wait_for_command "oc get -n $1 services | grep database" $((20*TIME_SEC))
23
+	DB_IP=$(oc get -n $1 --output-version=v1beta3 --template="{{ .spec.portalIP }}" service database)
24
+
25
+	echo "[INFO] Waiting for frontend pod to start"
26
+	wait_for_command "oc get -n $1 pods | grep frontend | grep -i Running" $((120*TIME_SEC))
27
+
28
+	echo "[INFO] Waiting for frontend service to start"
29
+	wait_for_command "oc get -n $1 services | grep frontend" $((20*TIME_SEC))
30
+	FRONTEND_IP=$(oc get -n $1 --output-version=v1beta3 --template="{{ .spec.portalIP }}" service frontend)
31
+
32
+	echo "[INFO] Waiting for database to start..."
33
+	wait_for_url_timed "http://${DB_IP}:5434" "[INFO] Database says: " $((3*TIME_MIN))
34
+
35
+	echo "[INFO] Waiting for app to start..."
36
+	wait_for_url_timed "http://${FRONTEND_IP}:5432" "[INFO] Frontend says: " $((2*TIME_MIN))
37
+
38
+	echo "[INFO] Testing app"
39
+	wait_for_command '[[ "$(curl -s -X POST http://${FRONTEND_IP}:5432/keys/foo -d value=1337)" = "Key created" ]]'
40
+	wait_for_command '[[ "$(curl -s http://${FRONTEND_IP}:5432/keys/foo)" = "1337" ]]'
41
+}
42
+
43
+# add e2e-user as a viewer for the default namespace so we can see infrastructure pieces appear
44
+openshift admin policy add-role-to-user view e2e-user --namespace=default
45
+
46
+# pre-load some image streams and templates
47
+oc create -f examples/image-streams/image-streams-centos7.json --namespace=openshift
48
+oc create -f examples/sample-app/application-template-stibuild.json --namespace=openshift
49
+oc create -f examples/jenkins/application-template.json --namespace=openshift
50
+oc create -f examples/db-templates/mongodb-ephemeral-template.json --namespace=openshift
51
+oc create -f examples/db-templates/mysql-ephemeral-template.json --namespace=openshift
52
+oc create -f examples/db-templates/postgresql-ephemeral-template.json --namespace=openshift
53
+
54
+# create test project so that this shows up in the console
55
+openshift admin new-project test --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"
56
+openshift admin new-project docker --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"
57
+openshift admin new-project custom --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"
58
+openshift admin new-project cache --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"
59
+
60
+echo "The console should be available at ${API_SCHEME}://${PUBLIC_MASTER_HOST}:${API_PORT}/console."
61
+echo "Log in as 'e2e-user' to see the 'test' project."
62
+
63
+install_router
64
+install_registry
65
+
66
+echo "[INFO] Pre-pulling and pushing ruby-20-centos7"
67
+docker pull openshift/ruby-20-centos7:latest
68
+echo "[INFO] Pulled ruby-20-centos7"
69
+
70
+echo "[INFO] Waiting for Docker registry pod to start"
71
+wait_for_registry
72
+
73
+# services can end up on any IP.	Make sure we get the IP we need for the docker registry
74
+DOCKER_REGISTRY=$(oc get --output-version=v1beta3 --template="{{ .spec.portalIP }}:{{ with index .spec.ports 0 }}{{ .port }}{{ end }}" service docker-registry)
75
+
76
+registry="$(dig @${API_HOST} "docker-registry.default.svc.cluster.local." +short A | head -n 1)"
77
+[[ -n "${registry}" && "${registry}:5000" == "${DOCKER_REGISTRY}" ]]
78
+
79
+echo "[INFO] Verifying the docker-registry is up at ${DOCKER_REGISTRY}"
80
+wait_for_url_timed "http://${DOCKER_REGISTRY}/healthz" "[INFO] Docker registry says: " $((2*TIME_MIN))
81
+
82
+[ "$(dig @${API_HOST} "docker-registry.default.local." A)" ]
83
+
84
+# Client setup (log in as e2e-user and set 'test' as the default project)
85
+# This is required to be able to push to the registry!
86
+echo "[INFO] Logging in as a regular user (e2e-user:pass) with project 'test'..."
87
+oc login -u e2e-user -p pass
88
+[ "$(oc whoami | grep 'e2e-user')" ]
89
+ 
90
+# make sure viewers can see oc status
91
+oc status -n default
92
+
93
+oc project cache
94
+token=$(oc config view --flatten -o template -t '{{with index .users 0}}{{.user.token}}{{end}}')
95
+[[ -n ${token} ]]
96
+
97
+echo "[INFO] Docker login as e2e-user to ${DOCKER_REGISTRY}"
98
+docker login -u e2e-user -p ${token} -e e2e-user@openshift.com ${DOCKER_REGISTRY}
99
+echo "[INFO] Docker login successful"
100
+
101
+echo "[INFO] Tagging and pushing ruby-20-centos7 to ${DOCKER_REGISTRY}/cache/ruby-20-centos7:latest"
102
+docker tag -f openshift/ruby-20-centos7:latest ${DOCKER_REGISTRY}/cache/ruby-20-centos7:latest
103
+docker push ${DOCKER_REGISTRY}/cache/ruby-20-centos7:latest
104
+echo "[INFO] Pushed ruby-20-centos7"
105
+
106
+echo "[INFO] Back to 'default' project with 'admin' user..."
107
+oc project ${CLUSTER_ADMIN_CONTEXT}
108
+[ "$(oc whoami | grep 'system:admin')" ]
109
+
110
+# The build requires a dockercfg secret in the builder service account in order
111
+# to be able to push to the registry.  Make sure it exists first.
112
+echo "[INFO] Waiting for dockercfg secrets to be generated in project 'test' before building"
113
+wait_for_command "oc get -n test serviceaccount/builder -o yaml | grep dockercfg > /dev/null" $((60*TIME_SEC))
114
+
115
+# Process template and create
116
+echo "[INFO] Submitting application template json for processing..."
117
+STI_CONFIG_FILE="${ARTIFACT_DIR}/stiAppConfig.json"
118
+DOCKER_CONFIG_FILE="${ARTIFACT_DIR}/dockerAppConfig.json"
119
+CUSTOM_CONFIG_FILE="${ARTIFACT_DIR}/customAppConfig.json"
120
+oc process -n test -f examples/sample-app/application-template-stibuild.json > "${STI_CONFIG_FILE}"
121
+oc process -n docker -f examples/sample-app/application-template-dockerbuild.json > "${DOCKER_CONFIG_FILE}"
122
+oc process -n custom -f examples/sample-app/application-template-custombuild.json > "${CUSTOM_CONFIG_FILE}"
123
+
124
+echo "[INFO] Back to 'test' context with 'e2e-user' user"
125
+oc login -u e2e-user
126
+oc project test
127
+oc whoami
128
+
129
+echo "[INFO] Applying STI application config"
130
+oc create -f "${STI_CONFIG_FILE}"
131
+
132
+# Wait for build which should have triggered automatically
133
+echo "[INFO] Starting build from ${STI_CONFIG_FILE} and streaming its logs..."
134
+#oc start-build -n test ruby-sample-build --follow
135
+os::build:wait_for_start "test"
136
+# Ensure that the build pod doesn't allow exec
137
+[ "$(oc rsh ${BUILD_ID}-build 2>&1 | grep 'forbidden')" ]
138
+os::build:wait_for_end "test"
139
+wait_for_app "test"
140
+
141
+echo "[INFO] Starting build from ${STI_CONFIG_FILE} with non-existing commit..."
142
+set +e
143
+oc start-build test --commit=fffffff --wait && echo "The build was supposed to fail, but it succeeded." && exit 1
144
+set -e
145
+
146
+# Remote command execution
147
+echo "[INFO] Validating exec"
148
+frontend_pod=$(oc get pod -l deploymentconfig=frontend -t '{{(index .items 0).metadata.name}}')
149
+# when running as a restricted pod the registry will run with a pre-allocated
150
+# user in the neighborhood of 1000000+.  Look for a substring of the pre-allocated uid range
151
+oc exec -p ${frontend_pod} id | grep 10
152
+
153
+# Port forwarding
154
+echo "[INFO] Validating port-forward"
155
+oc port-forward -p ${frontend_pod} 10080:8080  &> "${LOG_DIR}/port-forward.log" &
156
+wait_for_url_timed "http://localhost:10080" "[INFO] Frontend says: " $((10*TIME_SEC))
157
+
158
+
159
+
160
+#echo "[INFO] Applying Docker application config"
161
+#oc create -n docker -f "${DOCKER_CONFIG_FILE}"
162
+#echo "[INFO] Invoking generic web hook to trigger new docker build using curl"
163
+#curl -k -X POST $API_SCHEME://$API_HOST:$API_PORT/osapi/v1beta3/namespaces/docker/buildconfigs/ruby-sample-build/webhooks/secret101/generic && sleep 3
164
+#os::build:wait_for_end "docker"
165
+#wait_for_app "docker"
166
+
167
+#echo "[INFO] Applying Custom application config"
168
+#oc create -n custom -f "${CUSTOM_CONFIG_FILE}"
169
+#echo "[INFO] Invoking generic web hook to trigger new custom build using curl"
170
+#curl -k -X POST $API_SCHEME://$API_HOST:$API_PORT/osapi/v1beta3/namespaces/custom/buildconfigs/ruby-sample-build/webhooks/secret101/generic && sleep 3
171
+#os::build:wait_for_end "custom"
172
+#wait_for_app "custom"
173
+
174
+echo "[INFO] Back to 'default' project with 'admin' user..."
175
+oc project ${CLUSTER_ADMIN_CONTEXT}
176
+
177
+# ensure the router is started
178
+# TODO: simplify when #4702 is fixed upstream
179
+wait_for_command '[[ "$(oc get endpoints router --output-version=v1beta3 -t "{{ if .subsets }}{{ len .subsets }}{{ else }}0{{ end }}" || echo "0")" != "0" ]]' $((5*TIME_MIN))
180
+
181
+echo "[INFO] Validating routed app response..."
182
+# use the docker bridge ip address until there is a good way to get the auto-selected address from master
183
+# this address is considered stable
184
+# used as a resolve IP to test routing
185
+CONTAINER_ACCESSIBLE_API_HOST="${CONTAINER_ACCESSIBLE_API_HOST:-172.17.42.1}"
186
+validate_response "-s -k --resolve www.example.com:443:${CONTAINER_ACCESSIBLE_API_HOST} https://www.example.com" "Hello from OpenShift" 0.2 50
187
+
188
+
189
+# Pod node selection
190
+echo "[INFO] Validating pod.spec.nodeSelector rejections"
191
+# Create a project that enforces an impossible to satisfy nodeSelector, and two pods, one of which has an explicit node name
192
+openshift admin new-project node-selector --description="This is an example project to test node selection prevents deployment" --admin="e2e-user" --node-selector="impossible-label=true"
193
+NODE_NAME=`oc get node --no-headers | awk '{print $1}'`
194
+oc process -n node-selector -v NODE_NAME="${NODE_NAME}" -f test/node-selector/pods.json | oc create -n node-selector -f -
195
+# The pod without a node name should fail to schedule
196
+wait_for_command "oc get events -n node-selector | grep pod-without-node-name | grep failedScheduling"        $((20*TIME_SEC))
197
+# The pod with a node name should be rejected by the kubelet
198
+wait_for_command "oc get events -n node-selector | grep pod-with-node-name    | grep NodeSelectorMismatching" $((20*TIME_SEC))
199
+
200
+
201
+# Image pruning
202
+echo "[INFO] Validating image pruning"
203
+docker pull busybox
204
+docker pull gcr.io/google_containers/pause
205
+docker pull openshift/hello-openshift
206
+
207
+# tag and push 1st image - layers unique to this image will be pruned
208
+docker tag -f busybox ${DOCKER_REGISTRY}/cache/prune
209
+docker push ${DOCKER_REGISTRY}/cache/prune
210
+
211
+# tag and push 2nd image - layers unique to this image will be pruned
212
+docker tag -f openshift/hello-openshift ${DOCKER_REGISTRY}/cache/prune
213
+docker push ${DOCKER_REGISTRY}/cache/prune
214
+
215
+# tag and push 3rd image - it won't be pruned
216
+docker tag -f gcr.io/google_containers/pause ${DOCKER_REGISTRY}/cache/prune
217
+docker push ${DOCKER_REGISTRY}/cache/prune
218
+
219
+# record the storage before pruning
220
+registry_pod=$(oc get pod -l deploymentconfig=docker-registry -t '{{(index .items 0).metadata.name}}')
221
+oc exec -p ${registry_pod} du /registry > ${LOG_DIR}/prune-images.before.txt
222
+
223
+# set up pruner user
224
+oadm policy add-cluster-role-to-user system:image-pruner e2e-pruner
225
+oc login -u e2e-pruner -p pass
226
+
227
+# run image pruning
228
+oadm prune images --keep-younger-than=0 --keep-tag-revisions=1 --confirm &> ${LOG_DIR}/prune-images.log
229
+! grep error ${LOG_DIR}/prune-images.log
230
+
231
+oc project ${CLUSTER_ADMIN_CONTEXT}
232
+# record the storage after pruning
233
+oc exec -p ${registry_pod} du /registry > ${LOG_DIR}/prune-images.after.txt
234
+
235
+# make sure there were changes to the registry's storage
236
+[ -n "$(diff ${LOG_DIR}/prune-images.before.txt ${LOG_DIR}/prune-images.after.txt)" ]
237
+
238
+
239
+# UI e2e tests can be found in assets/test/e2e
240
+if [[ "$TEST_ASSETS" == "true" ]]; then
241
+
242
+	if [[ "$TEST_ASSETS_HEADLESS" == "true" ]]; then
243
+		echo "[INFO] Starting virtual framebuffer for headless tests..."
244
+		export DISPLAY=:10
245
+		Xvfb :10 -screen 0 1024x768x24 -ac &
246
+	fi
247
+
248
+	echo "[INFO] Running UI e2e tests at time..."
249
+	echo `date`
250
+	pushd ${OS_ROOT}/assets > /dev/null
251
+		grunt test-e2e
252
+	echo "UI  e2e done at time "
253
+	echo `date`
254
+
255
+	popd > /dev/null
256
+
257
+fi
... ...
@@ -14,9 +14,6 @@ ensure_iptables_or_die
14 14
 
15 15
 echo "[INFO] Starting end-to-end test"
16 16
 
17
-ROUTER_TESTS_ENABLED="${ROUTER_TESTS_ENABLED:-true}"
18
-TEST_ASSETS="${TEST_ASSETS:-false}"
19
-
20 17
 function cleanup()
21 18
 {
22 19
 	out=$?
... ...
@@ -36,55 +33,6 @@ function cleanup()
36 36
 trap "exit" INT TERM
37 37
 trap "cleanup" EXIT
38 38
 
39
-function wait_for_app() {
40
-	echo "[INFO] Waiting for app in namespace $1"
41
-	echo "[INFO] Waiting for database pod to start"
42
-	wait_for_command "oc get -n $1 pods -l name=database | grep -i Running" $((60*TIME_SEC))
43
-
44
-	echo "[INFO] Waiting for database service to start"
45
-	wait_for_command "oc get -n $1 services | grep database" $((20*TIME_SEC))
46
-	DB_IP=$(oc get -n $1 --output-version=v1beta3 --template="{{ .spec.portalIP }}" service database)
47
-
48
-	echo "[INFO] Waiting for frontend pod to start"
49
-	wait_for_command "oc get -n $1 pods | grep frontend | grep -i Running" $((120*TIME_SEC))
50
-
51
-	echo "[INFO] Waiting for frontend service to start"
52
-	wait_for_command "oc get -n $1 services | grep frontend" $((20*TIME_SEC))
53
-	FRONTEND_IP=$(oc get -n $1 --output-version=v1beta3 --template="{{ .spec.portalIP }}" service frontend)
54
-
55
-	echo "[INFO] Waiting for database to start..."
56
-	wait_for_url_timed "http://${DB_IP}:5434" "[INFO] Database says: " $((3*TIME_MIN))
57
-
58
-	echo "[INFO] Waiting for app to start..."
59
-	wait_for_url_timed "http://${FRONTEND_IP}:5432" "[INFO] Frontend says: " $((2*TIME_MIN))
60
-
61
-	echo "[INFO] Testing app"
62
-	wait_for_command '[[ "$(curl -s -X POST http://${FRONTEND_IP}:5432/keys/foo -d value=1337)" = "Key created" ]]'
63
-	wait_for_command '[[ "$(curl -s http://${FRONTEND_IP}:5432/keys/foo)" = "1337" ]]'
64
-}
65
-
66
-# Wait for builds to start
67
-# $1 namespace
68
-function wait_for_build_start() {
69
-        echo "[INFO] Waiting for $1 namespace build to start"
70
-        wait_for_command "oc get -n $1 builds | grep -i running" $((10*TIME_MIN)) "oc get -n $1 builds | grep -i -e failed -e error"
71
-        BUILD_ID=`oc get -n $1 builds  --output-version=v1 -t "{{with index .items 0}}{{.metadata.name}}{{end}}"`
72
-        echo "[INFO] Build ${BUILD_ID} started"
73
-}
74
-
75
-# Wait for builds to complete
76
-# $1 namespace
77
-function wait_for_build() {
78
-	echo "[INFO] Waiting for $1 namespace build to complete"
79
-	wait_for_command "oc get -n $1 builds | grep -i complete" $((10*TIME_MIN)) "oc get -n $1 builds | grep -i -e failed -e error"
80
-	BUILD_ID=`oc get -n $1 builds --output-version=v1beta3 -t "{{with index .items 0}}{{.metadata.name}}{{end}}"`
81
-	echo "[INFO] Build ${BUILD_ID} finished"
82
-  # TODO: fix
83
-  set +e
84
-	oc build-logs -n $1 $BUILD_ID > $LOG_DIR/$1build.log
85
-  set -e
86
-}
87
-
88 39
 
89 40
 # Start All-in-one server and wait for health
90 41
 TMPDIR="${TMPDIR:-"/tmp"}"
... ...
@@ -98,217 +46,5 @@ start_os_server
98 98
 export KUBECONFIG="${ADMIN_KUBECONFIG}"
99 99
 
100 100
 
101
-# add e2e-user as a viewer for the default namespace so we can see infrastructure pieces appear
102
-openshift admin policy add-role-to-user view e2e-user --namespace=default
103
-
104
-# pre-load some image streams and templates
105
-oc create -f examples/image-streams/image-streams-centos7.json --namespace=openshift
106
-oc create -f examples/sample-app/application-template-stibuild.json --namespace=openshift
107
-oc create -f examples/jenkins/application-template.json --namespace=openshift
108
-oc create -f examples/db-templates/mongodb-ephemeral-template.json --namespace=openshift
109
-oc create -f examples/db-templates/mysql-ephemeral-template.json --namespace=openshift
110
-oc create -f examples/db-templates/postgresql-ephemeral-template.json --namespace=openshift
111
-
112
-# create test project so that this shows up in the console
113
-openshift admin new-project test --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"
114
-openshift admin new-project docker --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"
115
-openshift admin new-project custom --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"
116
-openshift admin new-project cache --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"
117
-
118
-echo "The console should be available at ${API_SCHEME}://${PUBLIC_MASTER_HOST}:${API_PORT}/console."
119
-echo "Log in as 'e2e-user' to see the 'test' project."
120
-
121
-install_router
122
-install_registry
123
-
124
-echo "[INFO] Pre-pulling and pushing ruby-20-centos7"
125
-docker pull openshift/ruby-20-centos7:latest
126
-echo "[INFO] Pulled ruby-20-centos7"
127
-
128
-echo "[INFO] Waiting for Docker registry pod to start"
129
-wait_for_registry
130
-
131
-# services can end up on any IP.	Make sure we get the IP we need for the docker registry
132
-DOCKER_REGISTRY=$(oc get --output-version=v1beta3 --template="{{ .spec.portalIP }}:{{ with index .spec.ports 0 }}{{ .port }}{{ end }}" service docker-registry)
133
-
134
-registry="$(dig @${API_HOST} "docker-registry.default.svc.cluster.local." +short A | head -n 1)"
135
-[[ -n "${registry}" && "${registry}:5000" == "${DOCKER_REGISTRY}" ]]
136
-
137
-echo "[INFO] Verifying the docker-registry is up at ${DOCKER_REGISTRY}"
138
-wait_for_url_timed "http://${DOCKER_REGISTRY}/healthz" "[INFO] Docker registry says: " $((2*TIME_MIN))
139
-
140
-[ "$(dig @${API_HOST} "docker-registry.default.local." A)" ]
141
-
142
-# Client setup (log in as e2e-user and set 'test' as the default project)
143
-# This is required to be able to push to the registry!
144
-echo "[INFO] Logging in as a regular user (e2e-user:pass) with project 'test'..."
145
-oc login -u e2e-user -p pass
146
-[ "$(oc whoami | grep 'e2e-user')" ]
147
- 
148
-# make sure viewers can see oc status
149
-oc status -n default
150
-
151
-oc project cache
152
-token=$(oc config view --flatten -o template -t '{{with index .users 0}}{{.user.token}}{{end}}')
153
-[[ -n ${token} ]]
154
-
155
-echo "[INFO] Docker login as e2e-user to ${DOCKER_REGISTRY}"
156
-docker login -u e2e-user -p ${token} -e e2e-user@openshift.com ${DOCKER_REGISTRY}
157
-echo "[INFO] Docker login successful"
158
-
159
-echo "[INFO] Tagging and pushing ruby-20-centos7 to ${DOCKER_REGISTRY}/cache/ruby-20-centos7:latest"
160
-docker tag -f openshift/ruby-20-centos7:latest ${DOCKER_REGISTRY}/cache/ruby-20-centos7:latest
161
-docker push ${DOCKER_REGISTRY}/cache/ruby-20-centos7:latest
162
-echo "[INFO] Pushed ruby-20-centos7"
163
-
164
-echo "[INFO] Back to 'default' project with 'admin' user..."
165
-oc project ${CLUSTER_ADMIN_CONTEXT}
166
-[ "$(oc whoami | grep 'system:admin')" ]
167
-
168
-# The build requires a dockercfg secret in the builder service account in order
169
-# to be able to push to the registry.  Make sure it exists first.
170
-echo "[INFO] Waiting for dockercfg secrets to be generated in project 'test' before building"
171
-wait_for_command "oc get -n test serviceaccount/builder -o yaml | grep dockercfg > /dev/null" $((60*TIME_SEC))
172
-
173
-# Process template and create
174
-echo "[INFO] Submitting application template json for processing..."
175
-STI_CONFIG_FILE="${ARTIFACT_DIR}/stiAppConfig.json"
176
-DOCKER_CONFIG_FILE="${ARTIFACT_DIR}/dockerAppConfig.json"
177
-CUSTOM_CONFIG_FILE="${ARTIFACT_DIR}/customAppConfig.json"
178
-oc process -n test -f examples/sample-app/application-template-stibuild.json > "${STI_CONFIG_FILE}"
179
-oc process -n docker -f examples/sample-app/application-template-dockerbuild.json > "${DOCKER_CONFIG_FILE}"
180
-oc process -n custom -f examples/sample-app/application-template-custombuild.json > "${CUSTOM_CONFIG_FILE}"
181
-
182
-echo "[INFO] Back to 'test' context with 'e2e-user' user"
183
-oc login -u e2e-user
184
-oc project test
185
-oc whoami
186
-
187
-echo "[INFO] Applying STI application config"
188
-oc create -f "${STI_CONFIG_FILE}"
189
-
190
-# Wait for build which should have triggered automatically
191
-echo "[INFO] Starting build from ${STI_CONFIG_FILE} and streaming its logs..."
192
-#oc start-build -n test ruby-sample-build --follow
193
-wait_for_build_start "test"
194
-# Ensure that the build pod doesn't allow exec
195
-[ "$(oc rsh ${BUILD_ID}-build 2>&1 | grep 'forbidden')" ]
196
-wait_for_build "test"
197
-wait_for_app "test"
198
-
199
-echo "[INFO] Starting build from ${STI_CONFIG_FILE} with non-existing commit..."
200
-set +e
201
-oc start-build test --commit=fffffff --wait && echo "The build was supposed to fail, but it succeeded." && exit 1
202
-set -e
203
-
204
-# Remote command execution
205
-echo "[INFO] Validating exec"
206
-frontend_pod=$(oc get pod -l deploymentconfig=frontend -t '{{(index .items 0).metadata.name}}')
207
-# when running as a restricted pod the registry will run with a pre-allocated
208
-# user in the neighborhood of 1000000+.  Look for a substring of the pre-allocated uid range
209
-oc exec -p ${frontend_pod} id | grep 10
210
-
211
-# Port forwarding
212
-echo "[INFO] Validating port-forward"
213
-oc port-forward -p ${frontend_pod} 10080:8080  &> "${LOG_DIR}/port-forward.log" &
214
-wait_for_url_timed "http://localhost:10080" "[INFO] Frontend says: " $((10*TIME_SEC))
215
-
216
-
217
-
218
-#echo "[INFO] Applying Docker application config"
219
-#oc create -n docker -f "${DOCKER_CONFIG_FILE}"
220
-#echo "[INFO] Invoking generic web hook to trigger new docker build using curl"
221
-#curl -k -X POST $API_SCHEME://$API_HOST:$API_PORT/osapi/v1beta3/namespaces/docker/buildconfigs/ruby-sample-build/webhooks/secret101/generic && sleep 3
222
-#wait_for_build "docker"
223
-#wait_for_app "docker"
224
-
225
-#echo "[INFO] Applying Custom application config"
226
-#oc create -n custom -f "${CUSTOM_CONFIG_FILE}"
227
-#echo "[INFO] Invoking generic web hook to trigger new custom build using curl"
228
-#curl -k -X POST $API_SCHEME://$API_HOST:$API_PORT/osapi/v1beta3/namespaces/custom/buildconfigs/ruby-sample-build/webhooks/secret101/generic && sleep 3
229
-#wait_for_build "custom"
230
-#wait_for_app "custom"
231
-
232
-echo "[INFO] Back to 'default' project with 'admin' user..."
233
-oc project ${CLUSTER_ADMIN_CONTEXT}
234
-
235
-# ensure the router is started
236
-# TODO: simplify when #4702 is fixed upstream
237
-wait_for_command '[[ "$(oc get endpoints router --output-version=v1beta3 -t "{{ if .subsets }}{{ len .subsets }}{{ else }}0{{ end }}" || echo "0")" != "0" ]]' $((5*TIME_MIN))
238
-
239
-echo "[INFO] Validating routed app response..."
240
-# use the docker bridge ip address until there is a good way to get the auto-selected address from master
241
-# this address is considered stable
242
-# used as a resolve IP to test routing
243
-CONTAINER_ACCESSIBLE_API_HOST="${CONTAINER_ACCESSIBLE_API_HOST:-172.17.42.1}"
244
-validate_response "-s -k --resolve www.example.com:443:${CONTAINER_ACCESSIBLE_API_HOST} https://www.example.com" "Hello from OpenShift" 0.2 50
245
-
246
-
247
-# Pod node selection
248
-echo "[INFO] Validating pod.spec.nodeSelector rejections"
249
-# Create a project that enforces an impossible to satisfy nodeSelector, and two pods, one of which has an explicit node name
250
-openshift admin new-project node-selector --description="This is an example project to test node selection prevents deployment" --admin="e2e-user" --node-selector="impossible-label=true"
251
-oc process -n node-selector -v NODE_NAME="${KUBELET_HOST}" -f test/node-selector/pods.json | oc create -n node-selector -f -
252
-# The pod without a node name should fail to schedule
253
-wait_for_command "oc get events -n node-selector | grep pod-without-node-name | grep failedScheduling"        $((20*TIME_SEC))
254
-# The pod with a node name should be rejected by the kubelet
255
-wait_for_command "oc get events -n node-selector | grep pod-with-node-name    | grep NodeSelectorMismatching" $((20*TIME_SEC))
256
-
257
-
258
-# Image pruning
259
-echo "[INFO] Validating image pruning"
260
-docker pull busybox
261
-docker pull gcr.io/google_containers/pause
262
-docker pull openshift/hello-openshift
263
-
264
-# tag and push 1st image - layers unique to this image will be pruned
265
-docker tag -f busybox ${DOCKER_REGISTRY}/cache/prune
266
-docker push ${DOCKER_REGISTRY}/cache/prune
267
-
268
-# tag and push 2nd image - layers unique to this image will be pruned
269
-docker tag -f openshift/hello-openshift ${DOCKER_REGISTRY}/cache/prune
270
-docker push ${DOCKER_REGISTRY}/cache/prune
271
-
272
-# tag and push 3rd image - it won't be pruned
273
-docker tag -f gcr.io/google_containers/pause ${DOCKER_REGISTRY}/cache/prune
274
-docker push ${DOCKER_REGISTRY}/cache/prune
275
-
276
-# record the storage before pruning
277
-registry_pod=$(oc get pod -l deploymentconfig=docker-registry -t '{{(index .items 0).metadata.name}}')
278
-oc exec -p ${registry_pod} du /registry > ${LOG_DIR}/prune-images.before.txt
279
-
280
-# set up pruner user
281
-oadm policy add-cluster-role-to-user system:image-pruner e2e-pruner
282
-oc login -u e2e-pruner -p pass
283
-
284
-# run image pruning
285
-oadm prune images --keep-younger-than=0 --keep-tag-revisions=1 --confirm &> ${LOG_DIR}/prune-images.log
286
-! grep error ${LOG_DIR}/prune-images.log
287
-
288
-oc project ${CLUSTER_ADMIN_CONTEXT}
289
-# record the storage after pruning
290
-oc exec -p ${registry_pod} du /registry > ${LOG_DIR}/prune-images.after.txt
291
-
292
-# make sure there were changes to the registry's storage
293
-[ -n "$(diff ${LOG_DIR}/prune-images.before.txt ${LOG_DIR}/prune-images.after.txt)" ]
294
-
295
-
296
-# UI e2e tests can be found in assets/test/e2e
297
-if [[ "$TEST_ASSETS" == "true" ]]; then
298
-
299
-	if [[ "$TEST_ASSETS_HEADLESS" == "true" ]]; then
300
-		echo "[INFO] Starting virtual framebuffer for headless tests..."
301
-		export DISPLAY=:10
302
-		Xvfb :10 -screen 0 1024x768x24 -ac &
303
-	fi
304
-
305
-	echo "[INFO] Running UI e2e tests at time..."
306
-	echo `date`
307
-	pushd ${OS_ROOT}/assets > /dev/null
308
-		grunt test-e2e
309
-	echo "UI  e2e done at time "
310
-	echo `date`
311
-
312
-	popd > /dev/null
101
+${OS_ROOT}/hack/test-end-to-end-scenario.sh
313 102
 
314
-fi
... ...
@@ -31,10 +31,12 @@ function setup_env_vars {
31 31
 	# Use either the latest release built images, or latest.
32 32
 	if [[ -z "${USE_IMAGES-}" ]]; then
33 33
 		IMAGES='openshift/origin-${component}:latest'
34
+		export TAG=latest
34 35
 		export USE_IMAGES=${IMAGES}
35 36
 		if [[ -e "${OS_ROOT}/_output/local/releases/.commit" ]]; then
36 37
 			COMMIT="$(cat "${OS_ROOT}/_output/local/releases/.commit")"
37 38
 			IMAGES="openshift/origin-\${component}:${COMMIT}"
39
+			export TAG=${COMMIT}
38 40
 			export USE_IMAGES=${IMAGES}
39 41
 		fi
40 42
 	fi
... ...
@@ -381,7 +383,7 @@ reset_tmp_dir() {
381 381
 		sudo rm -rf ${BASETMPDIR}
382 382
 	fi
383 383
 
384
-	mkdir -p ${BASETMPDIR} ${LOG_DIR} ${ARTIFACT_DIR} ${FAKE_HOME_DIR}
384
+	mkdir -p ${BASETMPDIR} ${LOG_DIR} ${ARTIFACT_DIR} ${FAKE_HOME_DIR} ${VOLUME_DIR}
385 385
 	set -e
386 386
 }
387 387
 
... ...
@@ -500,6 +502,30 @@ function wait_for_registry {
500 500
 	wait_for_command '[[ "$(oc get endpoints docker-registry --output-version=v1 -t "{{ if .subsets }}{{ len .subsets }}{{ else }}0{{ end }}" --config=${ADMIN_KUBECONFIG} || echo "0")" != "0" ]]' $((5*TIME_MIN))
501 501
 }
502 502
 
503
+
504
+# Wait for builds to start
505
+# $1 namespace
506
+function os::build:wait_for_start() {
507
+	echo "[INFO] Waiting for $1 namespace build to start"
508
+	wait_for_command "oc get -n $1 builds | grep -i running" $((10*TIME_MIN)) "oc get -n $1 builds | grep -i -e failed -e error"
509
+	BUILD_ID=`oc get -n $1 builds  --output-version=v1 -t "{{with index .items 0}}{{.metadata.name}}{{end}}"`
510
+	echo "[INFO] Build ${BUILD_ID} started"
511
+}
512
+
513
+# Wait for builds to complete
514
+# $1 namespace
515
+function os::build:wait_for_end() {
516
+	echo "[INFO] Waiting for $1 namespace build to complete"
517
+	wait_for_command "oc get -n $1 builds | grep -i complete" $((10*TIME_MIN)) "oc get -n $1 builds | grep -i -e failed -e error"
518
+	BUILD_ID=`oc get -n $1 builds --output-version=v1beta3 -t "{{with index .items 0}}{{.metadata.name}}{{end}}"`
519
+	echo "[INFO] Build ${BUILD_ID} finished"
520
+	# TODO: fix
521
+	set +e
522
+	oc build-logs -n $1 $BUILD_ID > $LOG_DIR/$1build.log
523
+	set -e
524
+}
525
+
526
+
503 527
 ######
504 528
 # end of common functions for extended test group's run.sh scripts
505 529
 ######