Skip to content

Commit 3a4637b

Browse files
l0rdkadel
authored andcommitted
Fix terminating containers (devfile#102)
1 parent 0fda85f commit 3a4637b

File tree

25 files changed

+203
-7
lines changed

25 files changed

+203
-7
lines changed

.ci/openshift_integration.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,4 @@ $(realpath odo) registry delete DefaultDevfileRegistry -f
6262
$(realpath odo) registry add TestDevfileRegistry http://$REGISTRY_HOSTNAME
6363

6464
# Run the devfile validation tests
65-
ENV=openshift REGISTRY=remote tests/test.sh $(realpath odo) $YQ_PATH
65+
ENV=openshift REGISTRY=remote tests/check_odo_happy_path.sh $(realpath odo) $YQ_PATH

.github/workflows/validate-devfiles-minikube.yaml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ jobs:
3131
- name: Checkout
3232
uses: actions/checkout@v1
3333
- name: Setup Minikube
34-
uses: manusa/actions-setup-minikube@v2.4.2
34+
uses: manusa/actions-setup-minikube@v2.7.0
3535
with:
36-
minikube version: 'v1.21.0'
37-
kubernetes version: 'v1.21.0'
36+
minikube version: 'v1.26.1'
37+
kubernetes version: '1.25.0'
3838
driver: 'docker'
3939
github token: ${{ secrets.GITHUB_TOKEN }}
4040
start args: '--addons=ingress'
@@ -43,5 +43,7 @@ jobs:
4343
with:
4444
# Installs the latest release of odo
4545
odo: "2.5.1"
46-
- name: Validate the devfile stacks
47-
run: tests/test.sh odo
46+
- name: Check that containers components are non terminating
47+
run: tests/check_non_terminating.sh
48+
- name: Run odo happy path tests
49+
run: tests/check_odo_happy_path.sh odo

stacks/dotnet50/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ components:
2424
- name: dotnet
2525
container:
2626
image: registry.access.redhat.com/ubi8/dotnet-50:5.0
27+
args: ["tail", "-f", "/dev/null"]
2728
mountSources: true
2829
env:
2930
- name: CONFIGURATION

stacks/dotnet60/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ components:
2424
- name: dotnet
2525
container:
2626
image: registry.access.redhat.com/ubi8/dotnet-60:6.0
27+
args: ["tail", "-f", "/dev/null"]
2728
mountSources: true
2829
env:
2930
- name: CONFIGURATION

stacks/dotnetcore31/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ components:
2424
- name: dotnet
2525
container:
2626
image: registry.access.redhat.com/ubi8/dotnet-31:3.1
27+
args: ["tail", "-f", "/dev/null"]
2728
mountSources: true
2829
env:
2930
- name: CONFIGURATION

stacks/go/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ components:
2323
- name: http-go
2424
targetPort: 8080
2525
image: quay.io/devfile/golang:latest
26+
args: ["tail", "-f", "/dev/null"]
2627
memoryLimit: 1024Mi
2728
mountSources: true
2829
name: runtime

stacks/java-openliberty-gradle/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ components:
4040
- name: dev
4141
container:
4242
image: icr.io/appcafe/open-liberty-devfile-stack:{{liberty-version}}-gradle
43+
args: ["tail", "-f", "/dev/null"]
4344
memoryLimit: 1280Mi
4445
mountSources: true
4546
endpoints:

stacks/java-openliberty/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ components:
4242
container:
4343
# In the original upstream of this devfile, the image used is openliberty/devfile-stack:<x.y.z>, which is built from the repository: https://github.com/OpenLiberty/devfile-stack
4444
image: icr.io/appcafe/open-liberty-devfile-stack:{{liberty-version}}
45+
args: ["tail", "-f", "/dev/null"]
4546
memoryLimit: 768Mi
4647
mountSources: true
4748
endpoints:

stacks/java-quarkus/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ components:
2020
- name: tools
2121
container:
2222
image: registry.access.redhat.com/ubi8/openjdk-11
23+
args: ["tail", "-f", "/dev/null"]
2324
memoryLimit: 512Mi ## default app nowhere needs this but leaving room for expansion.
2425
mountSources: true
2526
volumeMounts:

stacks/java-websphereliberty-gradle/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ components:
4040
- name: dev
4141
container:
4242
image: icr.io/appcafe/websphere-liberty-devfile-stack:{{liberty-version}}-gradle
43+
args: ["tail", "-f", "/dev/null"]
4344
memoryLimit: 1280Mi
4445
mountSources: true
4546
endpoints:

stacks/java-websphereliberty/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ components:
4242
container:
4343
# In the original upstream of this devfile, the image used is openliberty/devfile-stack:<x.y.z>, which is built from the repository: https://github.com/OpenLiberty/devfile-stack
4444
image: icr.io/appcafe/websphere-liberty-devfile-stack:{{liberty-version}}
45+
command: ["tail", "-f", "/dev/null"]
4546
memoryLimit: 768Mi
4647
mountSources: true
4748
endpoints:

stacks/java-wildfly-bootable-jar/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ components:
9393
- name: wildfly
9494
container:
9595
image: registry.access.redhat.com/ubi8/openjdk-11
96+
args: ["tail", "-f", "/dev/null"]
9697
memoryLimit: 1512Mi
9798
mountSources: true
9899
volumeMounts:

stacks/nodejs-angular/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ components:
2828
- name: http-angular
2929
targetPort: 4200
3030
image: registry.access.redhat.com/ubi8/nodejs-16:latest
31+
args: ["tail", "-f", "/dev/null"]
3132
memoryLimit: 1024Mi
3233
name: runtime
3334
commands:

stacks/nodejs-nextjs/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ components:
2727
- name: http-nextjs
2828
targetPort: 3000
2929
image: registry.access.redhat.com/ubi8/nodejs-16:latest
30+
command: ["tail", "-f", "/dev/null"]
3031
memoryLimit: 1024Mi
3132
name: runtime
3233
commands:

stacks/nodejs-nuxtjs/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ components:
2626
- name: http-nuxtjs
2727
targetPort: 3000
2828
image: registry.access.redhat.com/ubi8/nodejs-16:latest
29+
args: ["tail", "-f", "/dev/null"]
2930
memoryLimit: 1024Mi
3031
name: runtime
3132
commands:

stacks/nodejs-react/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ components:
2626
- name: http-react
2727
targetPort: 3000
2828
image: registry.access.redhat.com/ubi8/nodejs-16:latest
29+
args: ["tail", "-f", "/dev/null"]
2930
memoryLimit: 1024Mi
3031
name: runtime
3132
commands:

stacks/nodejs-svelte/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ components:
2525
- name: http-svelte
2626
targetPort: 3000
2727
image: registry.access.redhat.com/ubi8/nodejs-16:latest
28+
args: ["tail", "-f", "/dev/null"]
2829
memoryLimit: 1024Mi
2930
name: runtime
3031
commands:

stacks/nodejs-vue/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ components:
2828
- name: http-vue
2929
targetPort: 3000
3030
image: registry.access.redhat.com/ubi8/nodejs-16:latest
31+
args: ["tail", "-f", "/dev/null"]
3132
memoryLimit: 1024Mi
3233
name: runtime
3334
commands:

stacks/nodejs/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ components:
1717
- name: runtime
1818
container:
1919
image: registry.access.redhat.com/ubi8/nodejs-16:latest
20+
args: ["tail", "-f", "/dev/null"]
2021
memoryLimit: 1024Mi
2122
mountSources: true
2223
endpoints:

stacks/php-laravel/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ components:
2828
- name: http-laravel
2929
targetPort: 8000
3030
image: quay.io/devfile/composer:2.1.11
31+
args: ["tail", "-f", "/dev/null"]
3132
memoryLimit: 1024Mi
3233
mountSources: true
3334
name: runtime

stacks/python-django/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ components:
2424
- name: py-web
2525
container:
2626
image: registry.access.redhat.com/ubi9/python-39:latest
27+
args: ["tail", "-f", "/dev/null"]
2728
mountSources: true
2829
endpoints:
2930
- name: http-django

stacks/python-flask/devfile.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ components:
2323
- name: py-web
2424
container:
2525
image: registry.access.redhat.com/ubi9/python-39:latest
26+
args: ["tail", "-f", "/dev/null"]
2627
mountSources: true
2728
endpoints:
2829
- name: http-python

tests/README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,20 @@
1212

1313
1) Ensure minikube is running and `minikube ip` reports a valid ip address
1414

15-
2) From the root of this repository, run `tests/test.sh`.
15+
2) From the root of this repository, run `tests/check_odo_happy_path.sh`.
1616

1717
- The test script will validate each devfile stack under `stacks/` with odo, verifying that the stack can be used to build a starter project and that the application is properly built and exposed.
1818
- The test script checks for an HTTP 200 status code to determine "properly exposed".
1919
- Each devfile stack **must** have at least one starter project specified in the devfile.yaml
2020

21+
3) From the root of this repository, run `tests/check_non_terminating.sh`.
22+
23+
- The test script will validate each devfile stack under `stacks/`, verifying that the components of type container are terminating.
24+
- The test script retrieves the `image`, `command` and `args` of a container component and uses them to run a pod and wait until it reaches the `Running` state:
25+
```bash
26+
kubectl run test-terminating -n default --attach=false --restart=Never --image="<image>" --command=true -- "<command>" "<args>"
27+
```
28+
- Each container component **must** be non-terminating. If the default `image` entrypoint is terminating an `args` (preferred) or `command` should be specified in the defile (e.g. `["tail", "-f", "/dev/null"]`).
2129

2230
## Limitations
2331

tests/check_non_terminating.sh

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
#!/bin/bash
2+
set -o nounset
3+
set -o errexit
4+
5+
DEVFILES_DIR="$(pwd)/stacks"
6+
7+
replaceVariables() {
8+
image=$1
9+
VAR_KEYS=(liberty-version)
10+
VAR_VALUES=(22.0.0.1)
11+
12+
for i in "${!VAR_KEYS[@]}"; do
13+
key='{{'
14+
key+=${VAR_KEYS[i]}
15+
key+='}}'
16+
value=${VAR_VALUES[i]}
17+
image=${image/${key}/${value}}
18+
done
19+
echo "$image"
20+
}
21+
22+
getContainerComponentsNum() {
23+
devfilePath=$1
24+
component_num=$($YQ_PATH eval '[ .components[] | select(has("container")) ] | length' "$devfilePath" -r)
25+
echo "${component_num}"
26+
}
27+
28+
getName() {
29+
devfilePath=$1
30+
name=$($YQ_PATH eval '.metadata.name' "$devfilePath" -r)
31+
echo "${name}"
32+
}
33+
34+
getFirstContainerComponentImage() {
35+
devfilePath=$1
36+
37+
image_original=$($YQ_PATH eval '[ .components[] | select(has("container")) ] | .[0].container.image' "$devfilePath" -r)
38+
image_processed=$(replaceVariables "${image_original}")
39+
echo "${image_processed}"
40+
}
41+
42+
getFirstContainerComponentCommand() {
43+
devfilePath=$1
44+
local _gfccc_command=()
45+
local _gfccc_command_string=()
46+
47+
IFS=" " read -r -a _gfccc_command_string <<< "$($YQ_PATH eval '[ .components[] | select(has("container")) ] | .[0].container.command[]? + " "' "$devfilePath" -r | paste -s -d '\0' -)"
48+
if (( ${#_gfccc_command_string[@]} == 0 )); then
49+
echo ""
50+
else
51+
for command_word in "${_gfccc_command_string[@]}"; do
52+
_gfccc_command+=("${command_word}")
53+
done
54+
echo "${_gfccc_command[@]}"
55+
fi
56+
}
57+
58+
getFirstContainerComponentArgs() {
59+
devfilePath=$1
60+
local _gfcca_args=()
61+
local _gfcca_args_string=()
62+
63+
IFS=" " read -r -a _gfcca_args_string <<< "$($YQ_PATH eval '[ .components[] | select(has("container")) ] | .[0].container.args[]? + " "' "$devfilePath" -r | paste -s -d '\0' -)"
64+
if (( ${#_gfcca_args_string[@]} == 0 )); then
65+
echo ""
66+
else
67+
for arg in "${_gfcca_args_string[@]}"; do
68+
_gfcca_args+=("${arg}")
69+
done
70+
echo "${_gfcca_args[@]}"
71+
fi
72+
}
73+
74+
isNonTerminating() {
75+
_int_image=$1
76+
_int_command=("$2")
77+
_int_command_args=("$3")
78+
79+
timeout_in_sec=60 # <== includes image pulling
80+
81+
echo " PARAMS: image --> $_int_image, command --> ${_int_command[*]}, args --> ${_int_command_args[*]}"
82+
83+
if [ "${_int_command[*]}" == "null" ] && [ "${_int_command_args[*]}" == "null" ]; then
84+
echo " COMMAND: \"kubectl run test-terminating -n ${TEST_NAMESPACE} --attach=false --restart=Never --image=$_int_image\""
85+
kubectl run test-terminating -n "${TEST_NAMESPACE}" --attach=false --restart=Never --image="$_int_image" >/dev/null 2>&1
86+
elif [ "${_int_command[*]}" == "null" ]; then
87+
echo " COMMAND: \"kubectl run test-terminating -n ${TEST_NAMESPACE} --attach=false --restart=Never --image=$_int_image -- ${_int_command_args[*]}\""
88+
kubectl run test-terminating -n "${TEST_NAMESPACE}" --attach=false --restart=Never --image="$_int_image" -- ${_int_command_args[*]} >/dev/null 2>&1
89+
elif [ "${_int_command_args[*]}" == "null" ]; then
90+
echo " COMMAND: \"kubectl run test-terminating -n ${TEST_NAMESPACE} --attach=false --restart=Never --image=$_int_image --command -- ${_int_command[*]}\""
91+
kubectl run test-terminating -n "${TEST_NAMESPACE}" --attach=false --restart=Never --image="$_int_image" --command=true -- ${_int_command[*]} >/dev/null 2>&1
92+
else
93+
echo " COMMAND: \"kubectl run test-terminating -n ${TEST_NAMESPACE} --attach=false --restart=Never --image=$_int_image --command -- ${_int_command[*]} ${_int_command_args[*]}\""
94+
kubectl run test-terminating -n "${TEST_NAMESPACE}" --attach=false --restart=Never --image="$_int_image" --command=true -- ${_int_command[*]} ${_int_command_args[*]} >/dev/null 2>&1
95+
fi
96+
97+
if kubectl wait pods -n "${TEST_NAMESPACE}" test-terminating --for condition=Ready --timeout=${timeout_in_sec}s >/dev/null 2>&1; then
98+
echo " SUCCESS: The container started successfully and didn't terminate"
99+
kubectl delete pod test-terminating -n "${TEST_NAMESPACE}" >/dev/null 2>&1
100+
return 0
101+
else
102+
echo " ERROR: Failed to reach \"Ready\" condition after $timeout_in_sec seconds"
103+
echo " ↓↓↓↓↓↓↓↓↓ Pod description ↓↓↓↓↓↓↓↓"
104+
echo ""
105+
kubectl describe pod -n "${TEST_NAMESPACE}" test-terminating
106+
echo ""
107+
echo " ↑↑↑↑↑↑↑↑↑ Pod description ↑↑↑↑↑↑↑↑"
108+
kubectl delete pod test-terminating -n "${TEST_NAMESPACE}" >/dev/null 2>&1
109+
return 1
110+
fi
111+
}
112+
113+
YQ_PATH=${YQ_PATH:-yq}
114+
TEST_NAMESPACE=${TEST_NAMESPACE:-default}
115+
116+
find "$DEVFILES_DIR" -maxdepth 1 -type d ! -path "$DEVFILES_DIR" -print0 | while IFS= read -r -d '' devfile_dir; do
117+
118+
devfile_path=$devfile_dir/devfile.yaml
119+
120+
echo "======================="
121+
echo "Testing ${devfile_path}"
122+
123+
IFS=" " read -r -a components_num <<< "$(getContainerComponentsNum "$devfile_path")"
124+
# components_num=($(getContainerComponentsNum "$devfile_path"))
125+
126+
# if there are zero components of type container skip
127+
if (( components_num = 0 )); then
128+
echo "WARNING: Devfile with no container component found (""$devfile_path""). Skipping."
129+
echo "======================="
130+
continue
131+
fi
132+
133+
# if there is more than one component of type container skip (we may want to cover this case in the future)
134+
if (( components_num > 1 )); then
135+
echo "WARNING: Devfile with more than one container component found (""$devfile_path""). Skipping."
136+
echo "======================="
137+
continue
138+
fi
139+
140+
name=$(getName "$devfile_path")
141+
image=$(getFirstContainerComponentImage "$devfile_path")
142+
143+
declare -a command=()
144+
IFS=" " read -r -a command <<< "$(getFirstContainerComponentCommand "$devfile_path")"
145+
146+
declare -a command_args=()
147+
IFS=" " read -r -a command_args <<< "$(getFirstContainerComponentArgs "$devfile_path")"
148+
149+
if (( ${#command[@]} > 0 )); then
150+
command_string="${command[*]}"
151+
else
152+
command_string="null"
153+
fi
154+
155+
if (( ${#command_args[@]} > 0 )); then
156+
command_args_string="${command_args[*]}"
157+
else
158+
command_args_string="null"
159+
fi
160+
161+
isNonTerminating "${image}" "${command_string}" "${command_args_string}";
162+
163+
echo "======================="
164+
done
165+
166+
exit 0
File renamed without changes.

0 commit comments

Comments
 (0)