Skip to content

Commit 682f653

Browse files
Merge pull request #429 from jstourac/checkParamsEnv
Add a GitHub action to perform validation of `params.env` file
2 parents c4cd154 + 4db8c31 commit 682f653

File tree

2 files changed

+353
-0
lines changed

2 files changed

+353
-0
lines changed

.github/workflows/params-env.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
name: Validation of params.env content (image SHAs)
3+
on: # yamllint disable-line rule:truthy
4+
pull_request:
5+
paths:
6+
- 'manifests/base/params.env'
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
validation-of-params-env:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v3
16+
17+
- name: Install dependencies
18+
run: |
19+
sudo apt-get install -y skopeo jq
20+
21+
- name: Validate the 'manifests/base/params.env' file content
22+
run: |
23+
bash ./ci/check-params-env.sh

ci/check-params-env.sh

Lines changed: 330 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,330 @@
1+
#!/bin/bash
2+
#
3+
# This script serves to check and validate the `params.env` file that contains
4+
# definitions of the notebook images that are supposed to be used in the resulting
5+
# release.
6+
#
7+
# It is verified that particular image link exists and is a proper type for the
8+
# assigned variable name. Structure of the `params.env` file is also checked.
9+
#
10+
# THIS FILE DOESN'T CHECK THAT THE USED LINK TO IMAGE IS THE LATEST ONE AVAILABLE!
11+
#
12+
# This script uses `skopeo` and `jq` tools installed locally for retrieving
13+
# information about the particular remote images.
14+
#
15+
# Local execution: ./ci/check-params-env.sh
16+
# Note: please execute from the root directory so that relative path matches
17+
#
18+
# In case of the PR on GitHub, this check is tied to GitHub actions automatically,
19+
# see `.github/workflows` directory.
20+
21+
# ----------------------------- GLOBAL VARIABLES ----------------------------- #
22+
23+
PARAMS_ENV_PATH="manifests/base/params.env"
24+
25+
# This value needs to be updated everytime we deliberately change number of the
26+
# images we want to have in the `params.env` file.
27+
EXPECTED_NUM_RECORDS=24
28+
29+
# ---------------------------- DEFINED FUNCTIONS ----------------------------- #
30+
31+
function check_variables_uniq() {
32+
local params_env_path="${1}"
33+
local ret_code=0
34+
35+
echo "Checking that all variables in the file '${params_env_path}' are unique and expected"
36+
37+
local content
38+
content=$(sed 's#\(.*\)=.*#\1#' "${params_env_path}" | sort)
39+
40+
local num_records
41+
num_records=$(echo "${content}" | wc -l)
42+
43+
local num_uniq_records
44+
num_uniq_records=$(echo "${content}" | uniq | wc -l)
45+
46+
test "${num_records}" -eq "${num_uniq_records}" || {
47+
echo "Some of the records in the file aren't unique!"
48+
ret_code=1
49+
}
50+
51+
test "${num_records}" -eq "${EXPECTED_NUM_RECORDS}" || {
52+
echo "Number of records in the file is incorrect - expected '${EXPECTED_NUM_RECORDS}' but got '${num_records}'!"
53+
ret_code=1
54+
}
55+
56+
echo "---------------------------------------------"
57+
return "${ret_code}"
58+
}
59+
60+
function check_image_variable_matches_name_and_commitref() {
61+
local image_variable="${1}"
62+
local image_name="${2}"
63+
local image_commitref="${3}"
64+
local openshift_build_name="${4}"
65+
66+
local expected_name
67+
local expected_commitref
68+
local expected_build_name # Why some of the images has `-amd64` suffix and others not?
69+
case "${image_variable}" in
70+
odh-minimal-notebook-image-n)
71+
expected_name="odh-notebook-jupyter-minimal-ubi9-python-3.9"
72+
expected_commitref="2023b"
73+
expected_build_name="jupyter-minimal-ubi9-python-3.9-amd64"
74+
;;
75+
odh-minimal-notebook-image-n-1)
76+
expected_name="odh-notebook-jupyter-minimal-ubi9-python-3.9"
77+
expected_commitref="2023a"
78+
expected_build_name="jupyter-minimal-ubi9-python-3.9-amd64"
79+
;;
80+
odh-minimal-notebook-image-n-2)
81+
expected_name="odh-notebook-jupyter-minimal-ubi8-python-3.8"
82+
expected_commitref="main"
83+
expected_build_name="jupyter-minimal-ubi8-python-3.8"
84+
;;
85+
odh-minimal-gpu-notebook-image-n)
86+
expected_name="odh-notebook-jupyter-minimal-ubi9-python-3.9"
87+
expected_commitref="2023b"
88+
expected_build_name="cuda-jupyter-minimal-ubi9-python-3.9-amd64"
89+
;;
90+
odh-minimal-gpu-notebook-image-n-1)
91+
expected_name="odh-notebook-jupyter-minimal-ubi9-python-3.9"
92+
expected_commitref="2023a"
93+
expected_build_name="cuda-jupyter-minimal-ubi9-python-3.9-amd64"
94+
;;
95+
odh-minimal-gpu-notebook-image-n-2)
96+
expected_name="odh-notebook-jupyter-minimal-ubi8-python-3.8"
97+
expected_commitref="main"
98+
expected_build_name="cuda-jupyter-minimal-ubi8-python-3.8"
99+
;;
100+
odh-pytorch-gpu-notebook-image-n)
101+
expected_name="odh-notebook-jupyter-pytorch-ubi9-python-3.9"
102+
expected_commitref="2023b"
103+
expected_build_name="jupyter-pytorch-ubi9-python-3.9-amd64"
104+
;;
105+
odh-pytorch-gpu-notebook-image-n-1)
106+
expected_name="odh-notebook-jupyter-pytorch-ubi9-python-3.9"
107+
expected_commitref="2023a"
108+
expected_build_name="jupyter-pytorch-ubi9-python-3.9-amd64"
109+
;;
110+
odh-pytorch-gpu-notebook-image-n-2)
111+
expected_name="odh-notebook-cuda-jupyter-pytorch-ubi8-python-3.8"
112+
expected_commitref="main"
113+
expected_build_name="cuda-jupyter-pytorch-ubi8-python-3.8"
114+
;;
115+
odh-generic-data-science-notebook-image-n)
116+
expected_name="odh-notebook-jupyter-datascience-ubi9-python-3.9"
117+
expected_commitref="2023b"
118+
expected_build_name="jupyter-datascience-ubi9-python-3.9-amd64"
119+
;;
120+
odh-generic-data-science-notebook-image-n-1)
121+
expected_name="odh-notebook-jupyter-datascience-ubi9-python-3.9"
122+
expected_commitref="2023a"
123+
expected_build_name="jupyter-datascience-ubi9-python-3.9-amd64"
124+
;;
125+
odh-generic-data-science-notebook-image-n-2)
126+
expected_name="odh-notebook-jupyter-datascience-ubi8-python-3.8"
127+
expected_commitref="main"
128+
expected_build_name="jupyter-datascience-ubi8-python-3.8"
129+
;;
130+
odh-tensorflow-gpu-notebook-image-n)
131+
expected_name="odh-notebook-cuda-jupyter-tensorflow-ubi9-python-3.9"
132+
expected_commitref="2023b"
133+
expected_build_name="cuda-jupyter-tensorflow-ubi9-python-3.9-amd64"
134+
;;
135+
odh-tensorflow-gpu-notebook-image-n-1)
136+
expected_name="odh-notebook-cuda-jupyter-tensorflow-ubi9-python-3.9"
137+
expected_commitref="2023a"
138+
expected_build_name="cuda-jupyter-tensorflow-ubi9-python-3.9-amd64"
139+
;;
140+
odh-tensorflow-gpu-notebook-image-n-2)
141+
expected_name="odh-notebook-cuda-jupyter-tensorflow-ubi8-python-3.8"
142+
expected_commitref="main"
143+
expected_build_name="cuda-jupyter-tensorflow-ubi8-python-3.8"
144+
;;
145+
odh-trustyai-notebook-image-n)
146+
expected_name="odh-notebook-jupyter-trustyai-ubi9-python-3.9"
147+
expected_commitref="2023b"
148+
expected_build_name="jupyter-trustyai-ubi9-python-3.9-amd64"
149+
;;
150+
odh-trustyai-notebook-image-n-1)
151+
expected_name="odh-notebook-jupyter-trustyai-ubi9-python-3.9"
152+
expected_commitref="2023a"
153+
expected_build_name="jupyter-trustyai-ubi9-python-3.9-amd64"
154+
;;
155+
odh-habana-notebook-image-n)
156+
expected_name="odh-notebook-habana-jupyter-1.10.0-ubi8-python-3.8"
157+
# expected_commitref="2023b"
158+
expected_commitref="main"
159+
expected_build_name="habana-jupyter-1.10.0-ubi8-python-3.8"
160+
;;
161+
odh-codeserver-notebook-n)
162+
expected_name="odh-notebook-code-server-ubi9-python-3.9"
163+
expected_commitref="2023b"
164+
expected_build_name="codeserver-ubi9-python-3.9-amd64"
165+
;;
166+
odh-codeserver-notebook-n-1)
167+
expected_name="odh-notebook-code-server-c9s-python-3.9"
168+
# expected_commitref="2023a"
169+
expected_commitref="main"
170+
expected_build_name="codeserver-c9s-python-3.9"
171+
;;
172+
odh-rstudio-notebook-n)
173+
expected_name="odh-notebook-rstudio-c9s-python-3.9"
174+
expected_commitref="2023b"
175+
expected_build_name="rstudio-c9s-python-3.9-amd64"
176+
;;
177+
odh-rstudio-notebook-n-1)
178+
expected_name="odh-notebook-rstudio-c9s-python-3.9"
179+
# expected_commitref="2023a"
180+
expected_commitref="main"
181+
expected_build_name="rstudio-c9s-python-3.9"
182+
;;
183+
# For both RStudio GPU workbenches - the final name labels are identical to plain RStudio ones
184+
# This is because the very same RStudio Dockerfile is used but different base images in both cases
185+
# We should consider what to do with this - in ideal case, we should have different labels for these cases.
186+
odh-rstudio-gpu-notebook-n)
187+
expected_name="odh-notebook-rstudio-c9s-python-3.9"
188+
expected_commitref="2023b"
189+
expected_build_name="cuda-rstudio-c9s-python-3.9-amd64"
190+
;;
191+
odh-rstudio-gpu-notebook-n-1)
192+
expected_name="odh-notebook-rstudio-c9s-python-3.9"
193+
# expected_commitref="2023a"
194+
expected_commitref="main"
195+
expected_build_name="cuda-rstudio-c9s-python-3.9"
196+
;;
197+
*)
198+
echo "Unimplemented variable name: '${image_variable}'"
199+
return 1
200+
esac
201+
202+
test "${image_name}" = "${expected_name}" || {
203+
echo "Image URL points to an incorrect image: expected name '${expected_name}'; actual '${image_name}'"
204+
return 1
205+
}
206+
207+
test "${image_commitref}" = "${expected_commitref}" || {
208+
echo "Image URL points to an incorrect image: expected commitref '${expected_commitref}'; actual '${image_commitref}'"
209+
return 1
210+
}
211+
212+
test "${openshift_build_name}" = "${expected_build_name}" || {
213+
echo "Image URL points to an incorrect image: expected OPENSHIFT_BUILD_NAME '${expected_build_name}'; actual '${openshift_build_name}'"
214+
return 1
215+
}
216+
}
217+
218+
function check_image() {
219+
local image_variable="${1}"
220+
local image_url="${2}"
221+
222+
echo "Checking metadata for image '${image_variable}' with URL '${image_url}'"
223+
224+
local image_metadata
225+
local image_name
226+
local image_commitref
227+
228+
image_metadata="$(skopeo inspect --config "docker://${image_url}")" || {
229+
echo "Couldn't download image metadata with skopeo tool!"
230+
return 1
231+
}
232+
image_name=$(echo "${image_metadata}" | jq --raw-output '.config.Labels.name') || {
233+
echo "Couldn't parse '.config.Labels.name' from image metadata!"
234+
return 1
235+
}
236+
image_commitref=$(echo "${image_metadata}" | jq --raw-output '.config.Labels."io.openshift.build.commit.ref"') || {
237+
echo "Couldn't parse '.config.Labels."io.openshift.build.commit.ref"' from image metadata!"
238+
return 1
239+
}
240+
241+
local config_env
242+
local build_name_raw
243+
local openshift_build_name
244+
245+
config_env=$(echo "${image_metadata}" | jq --raw-output '.config.Env') || {
246+
echo "Couldn't parse '.config.Env' from image metadata!"
247+
return 1
248+
}
249+
build_name_raw=$(echo "${config_env}" | grep '"OPENSHIFT_BUILD_NAME=') || {
250+
echo "Couldn't get 'OPENSHIFT_BUILD_NAME' from set of the image environment variables!"
251+
return 1
252+
}
253+
openshift_build_name=$(echo "${build_name_raw}" | sed 's/.*"OPENSHIFT_BUILD_NAME=\(.*\)".*/\1/') || {
254+
echo "Couldn't parse value of the 'OPENSHIFT_BUILD_NAME' variable from '${build_name_raw}'!"
255+
return 1
256+
}
257+
258+
test -n "${image_name}" || {
259+
echo "Couldn't retrieve the name of the image - got empty value!"
260+
return 1
261+
}
262+
263+
echo "Image name retrieved: '${image_name}'"
264+
265+
check_image_variable_matches_name_and_commitref "${image_variable}" "${image_name}" "${image_commitref}" "${openshift_build_name}" || return 1
266+
267+
echo "---------------------------------------------"
268+
}
269+
270+
# ------------------------------ MAIN SCRIPT --------------------------------- #
271+
272+
ret_code=0
273+
274+
echo "Starting check for file: '${PARAMS_ENV_PATH}'"
275+
echo "---------------------------------------------"
276+
277+
check_variables_uniq "${PARAMS_ENV_PATH}" || {
278+
echo "ERROR: Variable names in the file failed validation!"
279+
echo "----------------------------------------------------"
280+
ret_code=1
281+
}
282+
283+
while IFS= read -r LINE; do
284+
echo "Checking format of: '${LINE}'"
285+
[[ "${LINE}" = *[[:space:]]* ]] && {
286+
echo "ERROR: Line contains white-space and it shouldn't!"
287+
echo "--------------------------------------------------"
288+
ret_code=1
289+
continue
290+
}
291+
[[ "${LINE}" != *=* ]] && {
292+
echo "ERROR: Line doesn't contain '=' and it should!"
293+
echo "----------------------------------------------"
294+
ret_code=1
295+
continue
296+
}
297+
298+
IMAGE_VARIABLE=$(echo "${LINE}" | cut --delimiter '=' --field 1)
299+
IMAGE_URL=$(echo "${LINE}" | cut --delimiter '=' --field 2)
300+
301+
test -n "${IMAGE_VARIABLE}" || {
302+
echo "ERROR: Couldn't parse image variable - got empty value!"
303+
echo "-------------------------------------------------------"
304+
ret_code=1
305+
continue
306+
}
307+
308+
test -n "${IMAGE_URL}" || {
309+
echo "ERROR: Couldn't parse image URL - got empty value!"
310+
echo "--------------------------------------------------"
311+
ret_code=1
312+
continue
313+
}
314+
315+
check_image "${IMAGE_VARIABLE}" "${IMAGE_URL}" || {
316+
echo "ERROR: Image definition for '${IMAGE_VARIABLE}' isn't okay!"
317+
echo "------------------------"
318+
ret_code=1
319+
continue
320+
}
321+
done < "${PARAMS_ENV_PATH}"
322+
323+
echo ""
324+
if test "${ret_code}" -eq 0; then
325+
echo "Validation of '${PARAMS_ENV_PATH}' was successful! Congrats :)"
326+
else
327+
echo "The '${PARAMS_ENV_PATH}' file isn't valid, please check above!"
328+
fi
329+
330+
exit "${ret_code}"

0 commit comments

Comments
 (0)