-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhelmrepo.sh
executable file
·430 lines (349 loc) · 13.5 KB
/
helmrepo.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
#!/usr/bin/env bash
# Copyright 2018-2024 Open Networking Foundation (ONF) and the ONF Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# helmrepo.sh
# creates or updates a helm repo for publishing on the guide website
# Reference: https://github.com/helm/charts/blob/master/test/repo-sync.sh
set -eu -o pipefail
##-------------------##
##---] GLOBALS [---##
##-------------------##
# when not running under Jenkins, use current dir as workspace
WORKSPACE=${WORKSPACE:-.}
# directory to compare against, doesn't need to be present
OLD_REPO_DIR="${OLD_REPO_DIR:-cord-charts-repo}"
NEW_REPO_DIR="${NEW_REPO_DIR:-chart_repo}"
PUBLISH_URL="${PUBLISH_URL:-charts.opencord.org}"
## -----------------------------------------------------------------------
## Intent: Dispay called function with given output
## -----------------------------------------------------------------------
function func_echo()
{
echo "** ${FUNCNAME[1]}: $*"
return
}
## -----------------------------------------------------------------------
## Intent: Display given text and exit with shell error status.
## -----------------------------------------------------------------------
function error()
{
echo -e "** ${BASH_SOURCE[0]##*/}::${FUNCNAME[1]} ERROR: $*"
exit 1
}
## -----------------------------------------------------------------------
## Intent: Detect pre-existing versioned packages.
## -----------------------------------------------------------------------
function check_packages()
{
local dir="$1"; shift
readarray -t package_paths < <(find "${dir}" -name '*.tgz' -print)
declare -p package_paths
# ---------------------------------------------
# Check for versioned package collision.
# ---------------------------------------------
for package_path in "${package_paths[@]}";
do
package="${package_path##*/}" # basename
if [ -f "${OLD_REPO_DIR}/${package}" ]; then
echo
echo "PACKAGE: $package"
/bin/ls -l "$package_path"
/bin/ls -l "${OLD_REPO_DIR}/${package}"
error "Package: ${package} with same version already exists in ${OLD_REPO_DIR}"
fi
done
return
}
## -----------------------------------------------------------------------
## Intent: Gather a list of Chart.yaml files from the filesystem.
## -----------------------------------------------------------------------
function get_chart_yaml()
{
local dir="$1" ; shift
declare -n ref=$1 ; shift
readarray -t _charts < <(find "$dir" -name Chart.yaml -print | sort)
ref=("${_charts[@]}")
return
}
## -----------------------------------------------------------------------
## Intent: Given a helm chart line extract and return *version.
## -----------------------------------------------------------------------
function getVersion()
{
# shellcheck disable=SC2178
local -n ref=$1; shift # declare -A
local line="$1"; shift
[[ -v debug ]] && func_echo "LINE: $line"
# version : x.y.z
readarray -d':' -t _fields < <(printf '%s' "$line")
local key="${_fields[0]}"
local val="${_fields[1]}"
# shellcheck disable=SC2004
ref[$key]="$val"
return
}
## -----------------------------------------------------------------------
## Intent: Update helm package dependencies
## -----------------------------------------------------------------------
function helm_deps_update()
{
local dest="$1"; shift # helm --destination
if [[ -v dry_run ]]; then
func_echo "helm package --dependency-update --destination $dest $chartdir"
else
helm package --dependency-update --destination "$dest" "$chartdir"
fi
return
}
## -----------------------------------------------------------------------
## Intent: Update helm package index
## -----------------------------------------------------------------------
function helm_index_publish()
{
local repo_dir="$1"; shift # helm --destination
if [[ -v dry_run ]]; then
func_echo "helm repo index $repo_dir --url https://${PUBLISH_URL}"
elif [[ -v no_publish ]]; then
func_echo "[SKIP] helm publishing due to --no-publish"
else
## ------------------------------------------------
## Helm updates are guarded by jenkins
## Revision control should reinforce that assertion
## ------------------------------------------------
case "$USER" in
jenkins)
helm repo index "$repo_dir" --url https://"${PUBLISH_URL}"
;;
*)
func_echo "[SKIP] helm publishing due to ($USER != jenkins)"
;;
esac
fi
return
}
## -----------------------------------------------------------------------
## Intent: Update helm package index
## -----------------------------------------------------------------------
function helm_index_merge()
{
local old_repo="$1" ; shift
local new_repo="$1" ; shift
declare -a cmd=()
cmd+=('helm' 'repo' 'index')
cmd+=('--url' "https://${PUBLISH_URL}")
cmd+=('--merge' "${old_repo}/index.yaml" "$new_repo")
if [[ -v dry_run ]]; then
func_echo "${cmd[@]}"
else
"${cmd[@]}"
fi
return
}
## -----------------------------------------------------------------------
## Intent: Given a Chart.yaml file path return test directory where stored
## -----------------------------------------------------------------------
function chart_path_to_test_dir()
{
local val="$1" ; shift
# shellcheck disable=SC2178
declare -n ref=$1 ; shift # indirect var
val="${val%/Chart.yaml}" # dirname: prune /Chart.yaml
val="${val##*/}" # basename: test directory
# shellcheck disable=SC2034,SC2178
ref="$val" # Return value to caller
return
}
## -----------------------------------------------------------------------
## Intent: Given Chart.yaml files create a new indexed chart repository
## -----------------------------------------------------------------------
function create_helm_repo_new()
{
local repo_dir="$1"; shift # NEW_REPO_DIR
local work_dir="$1"; shift # WORKSPACE
echo "Creating new helm repo: ${repo_dir}"
declare -a charts=()
get_chart_yaml "$work_dir" charts
local chart
for chart in "${charts[@]}";
do
echo
func_echo "Chart.yaml: $chart"
chartdir=''
chart_path_to_test_dir "$chart" chartdir
func_echo " Chart.dir: $chartdir"
helm_deps_update "${repo_dir}"
done
helm_index_publish "${repo_dir}"
return
}
## -----------------------------------------------------------------------
## Intent: Compare version stings extracted from Chart.yaml delta.
## o attribute version:x.y.z must be changed to enable change
## detection and chart loading.
## -----------------------------------------------------------------------
function validate_changes()
{
local chart="$1"; shift
# shellcheck disable=SC2178
local -n ref=$1; shift
local msg
## -------------------------------------------
## Validation logic: all keys collected exist
## Chart version must change to enable loading
## -------------------------------------------
local key0
for key0 in "${!ref[@]}";
do
local key="${key0:1}"
# shellcheck disable=SC2034
local old="-${key}"
local new="+${key}"
## Key/val paris are diff deltas:
## -version : 1.2.3
## +version : 4.5.6
if [[ ! -v ref['-version'] ]]; then
msg='Modify version to publish chart changes'
elif [[ ! -v ref["$new"] ]]; then
msg="Failed to detect +${key} change in attributes"
else
continue
fi
local -i failed=1
cat <<ERR
** -----------------------------------------------------------------------
** Chart dir: $chartdir
** Chart.yml: $chart
** Error: $msg
** -----------------------------------------------------------------------
ERR
func_echo "$(declare -p versions | sed -e 's/\[/\n\[/g')"
done
if [[ -v failed ]]; then
false
else
true
fi
return
}
##----------------##
##---] MAIN [---##
##----------------##
while [ $# -gt 0 ]; do
arg="$1"; shift
case "$arg" in
-*debug) declare -g -i debug=1 ;;
-*dry*) declare -g -i dry_run=1 ;;
-*no-publish) declare -g -i no_publish=1 ;;
-*help)
cat <<EOH
Usage: $0
--debug Enable debug mode
--dry-run Simulate helm calls
EOH
;;
-*) echo "[SKIP] unknown switch [$arg]" ;;
*) echo "[SKIP] unknown argument [$arg]" ;;
esac
done
echo "# helmrepo.sh, using helm: $(helm version -c) #"
# create and clean NEW_REPO_DIR
mkdir -p "${NEW_REPO_DIR}"
rm -f "${NEW_REPO_DIR}"/*
# if OLD_REPO_DIR doesn't exist, generate packages and index in NEW_REPO_DIR
if [ ! -d "${OLD_REPO_DIR}" ]
then
create_helm_repo_new "$NEW_REPO_DIR" "$WORKSPACE"
echo
echo "# helmrepo.sh Success! Generated new repo index in ${NEW_REPO_DIR}"
else
# OLD_REPO_DIR exists, check for new charts and update only with changes
echo "Found existing helm repo: ${OLD_REPO_DIR}, attempting update"
# Loop and create chart packages, only if changed
declare -a charts=()
get_chart_yaml "$WORKSPACE" charts
for chart in "${charts[@]}";
do
echo
func_echo "Chart.yaml: $chart"
chartdir=''
chart_path_to_test_dir "$chart" chartdir
func_echo " Chart.dir: $chartdir"
# See if chart version changed from previous HEAD commit
readarray -t chart_yaml_diff < <(git diff -p HEAD^ -- "$chart")
if [[ ! -v chart_yaml_diff ]]; then
echo "Chart unchanged, not packaging: '${chartdir}'"
# -------------------------------------------------------------------
# Assumes that helmlint.sh and chart_version_check.sh have been run
# pre-merge, which ensures that all charts are valid and have their
# version updated in Chart.yaml
# -------------------------------------------------------------------
elif [ ${#chart_yaml_diff} -gt 0 ]; then
declare -A versions=()
for line in "${chart_yaml_diff[@]}";
do
[[ -v debug ]] && func_echo "$line"
# foo=${string#"$prefix"}
line="${line%\#*}" # Snip comments
line="${line//[[:blank:]]}" # Prune whitespace
case "$line" in
# appVersion: "1.0.3"
# version: 1.2.3
[-+]*[vV]ersion:*) getVersion versions "$line" ;;
esac
done
# ---------------------------------------------------------------
# [TODO] -- versions['-version']='version string change required'
# ---------------------------------------------------------------
# version: string change initiates a delta forcing helm to update.
# Should it be required by every checkin ? For ex: release may
# accumulate several version edits then publish all when finished.
#
# Danger would be chart changes are not published/tested when
# a dev forgets to update the chart version string.
# ---------------------------------------------------------------
## ---------------------------------------------------------------
## Check for required version change and stray attribute deletions
## We are comparing diff output [-+]verison : x.y
## +{key} indicates a required attribute exists and was modified
## ---------------------------------------------------------------
if ! validate_changes "$chart" versions; then
declare -g -i failed=1
continue
fi
# Always query, version string may not have changed
readarray -t ver < <(grep -oP '(?<= version: )\S+' "$chart")
declare -p ver
echo "Detected new version of chart ${chartdir}, creating package: ${ver[*]}"
helm_deps_update "${NEW_REPO_DIR}"
else
echo "Chart unchanged, not packaging: '${chartdir}'"
fi
done
check_packages "$NEW_REPO_DIR"
## -----------------------------------------------------------------------
## -----------------------------------------------------------------------
# only update index when new charts are added
if [ ${#package_paths[@]} -gt 0 ]; then
# Create updated index.yaml (new version created in NEW_REPO_DIR)
helm_index_merge "${OLD_REPO_DIR}" "${NEW_REPO_DIR}"
# move over packages and index.yaml
mv "${NEW_REPO_DIR}"/*.tgz "${OLD_REPO_DIR}/"
mv "${NEW_REPO_DIR}/index.yaml" "${OLD_REPO_DIR}/index.yaml"
echo "# helmrepo.sh Success! Updated existing repo index in ${OLD_REPO_DIR}"
else
echo "# helmrepo.sh Success! No new charts added."
fi
fi
exit 0
# [EOF]