forked from jobtome-labs/ci-templates
-
Notifications
You must be signed in to change notification settings - Fork 0
/
helm-branches.yml
347 lines (295 loc) · 12.4 KB
/
helm-branches.yml
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
deploy:quality:helm:branches:
image: jobtomelabs/helm-sops-mysql:3.2.0
stage: deploy
environment:
name: review/$CI_BUILD_REF_NAME
url: https://${CI_COMMIT_REF_SLUG}.${DOMAIN_QUALITY}
on_stop: stop:quality
variables:
GOOGLE_KEY: ${GOOGLE_KEY_QUALITY}
CLUSTER_NAME: ${CLUSTER_NAME_QUALITY}
CLUSTER_ZONE: ${CLUSTER_ZONE_QUALITY}
NAMESPACE: ${NAMESPACE_QUALITY}
ENVIRONMENT: feature
CI_COMMIT_TAG: ${CI_COMMIT_SHORT_SHA}
script:
###
# customisable params:
# APP_NAME_BRANCH (pilots APP_NAME; default CI_COMMIT_SHORT_SHA)
# DOMAIN_BRANCH (pilots DOMAIN; default ${CI_COMMIT_REF_SLUG}.${DOMAIN_QUALITY}
# SECRET_BRANCH (pilots SECRET_YAML; default SECRET_YAML_FEATURE)
# SECRET_BRANCH_SOPS (pilots SECRET_FILE; default ${HELM_DIR}/${ENVIRONMENT}/secrets.yaml)
# DATABASE_NAME_BRANCH (pilots DB_NAME_FEAT; default DB_HOST which comes from SECRET_YAML_QUALITY
# \_____________ OR in case of no DB_HOST, default *comes from* URL_BRANCH 'disassembled', which comes from SECRET_YAML)
###
- &dbcheckvars |
# CHECK VARIABLES PHASE
for var in "GOOGLE_KEY_QUALITY" "CLUSTER_NAME_QUALITY" "CLUSTER_ZONE_QUALITY" "NAMESPACE_QUALITY"; do
if [ -z "${!var}" ]; then
echo "Missing '${var}' variable!"
exit 1
fi
done
- &dbactivate |
# ACTIVATION PHASE
echo "${GOOGLE_KEY}" > /tmp/key.json
gcloud auth activate-service-account --key-file /tmp/key.json
gcloud config set project "${GOOGLE_PROJECT}"
echo
echo "-> Google project '${GOOGLE_PROJECT}' configured!"
echo
- &dbclusterconnect |
# CLUSTER CONNECTION PHASE
gcloud container clusters get-credentials --zone "${CLUSTER_ZONE}" "${CLUSTER_NAME}"
kubectl config set-context $(kubectl config current-context) --namespace="${NAMESPACE}"
echo
echo "-> Namespace '$(kubectl config view --minify --output jsonpath={..namespace})' configured!"
echo
kubectl cluster-info
echo
- |
# DOMAIN OPERATIONS
# use a specific domain if DOMAIN_BRANCH is specified in gitlab-ci
if [ -n "${DOMAIN_BRANCH}" ]; then
export DOMAIN=${CI_COMMIT_REF_SLUG}.${DOMAIN_BRANCH}
# otherwise, use default DOMAIN_QUALITY
else
export DOMAIN=${CI_COMMIT_REF_SLUG}.${DOMAIN_QUALITY}
fi
- &dbfindname |
# use a specific app name if APP_NAME_BRANCH is specified in gitlab-ci
if [ -n "${APP_NAME_BRANCH}" ]; then
export APP_NAME=${APP_NAME_BRANCH}
# otherwise, use default APP_NAME (i.e. COMMIT_REF_SLUG)
else
export APP_NAME=${CI_COMMIT_REF_SLUG}
fi
- &dbhelmdir |
# CHECK DIRS AND CREATE VALUES
if [ -z "${HELM_DIR}" ]; then
HELM_DIR=helm
fi
HELM_FILES_PATH="${HELM_DIR}/${ENVIRONMENT}"
envsubst < "${HELM_FILES_PATH}"/values.yaml > /tmp/values.yaml
- &dbsecretid |
# SECRETS OPERATIONS: Identification
# we need SECRET_YAML_QUALITY to perform DB cloning
# (it contains quality DB name, whereas SECRET_YAML should
# contain the new name i.e. the name of the feature branch)
# use a specific CI/CD variable if SECRET_BRANCH is specified in gitlab-ci
if [ -n "${SECRET_BRANCH}" ]; then
SECRET_YAML=${!SECRET_BRANCH}
# otherwise, use default SECRET_YAML_FEATURE CI/CD variable
else
SECRET_YAML=${SECRET_YAML_FEATURE}
fi
- |
# Set kubectl command to delete
KUBECTL_COMMAND=( kubectl apply -f /tmp/secrets.yaml )
- &dbkubectlsecret |
# SECRETS OPERATIONS: application
# Priority: file in repo, then SECRET_YAML
if [ -n "${SECRET_BRANCH_SOPS}" ]; then
SECRET_FILE=${!SECRET_BRANCH_SOPS}
# otherwise, use default SECRET_YAML_FEATURE CI/CD variable
else
SECRET_FILE=${HELM_FILES_PATH}/secrets.yaml
fi
if [ ! -f "${SECRET_FILE}" ] && [ -z "${SECRET_YAML}" ]; then
echo
echo "-> [WARN] No secret to apply!"
echo
else
touch /tmp/secrets.yaml
if [ -f "${SECRET_FILE}" ]; then
if [ -z "${SOPS_KEY}" ] || [ -z "${SOPS_CONF}" ]; then
echo "[WARN] Cannot apply secrets: missing sops key or conf"
else
echo "${SOPS_CONF}" > /tmp/.sops.yaml
echo "${SOPS_KEY}" > /tmp/sops.json
GOOGLE_APPLICATION_CREDENTIALS=/tmp/sops.json sops --config /tmp/.sops.yaml -d "${SECRET_FILE}" > /tmp/secrets.yaml
fi
fi
if [ -n "${SECRET_YAML}" ]; then
echo "${SECRET_YAML}" | base64 -d >> /tmp/secrets.yaml
fi
envsubst < /tmp/secrets.yaml > /tmp/secrets.yaml.tmp && mv /tmp/secrets.yaml.tmp /tmp/secrets.yaml
"${KUBECTL_COMMAND[@]}"
echo
echo "-> Secrets deployed!"
echo
fi
- &dbsecretunmangling |
# SECRETS OPERATIONS: unmangling
# We have this from above
set +e
BRANCH_VARS=$( tac /tmp/secrets.yaml | grep -e "DB_USERNAME" -e "DB_PASSWORD" -e "DB_HOST" -e "DB_NAME" -e "DATABASE_URL" | base64)
set -e
# It is assumed that the quality secret cannot be missing in a feature branch
touch /tmp/secrets-qa.yaml
if [ -f "${HELM_DIR}/quality/secrets.yaml" ]; then
if [ -z "${SOPS_KEY}" ] || [ -z "${SOPS_CONF}" ]; then
echo "[WARN] Cannot apply secrets: missing sops key or conf"
else
echo "${SOPS_CONF}" > /tmp/.sops.yaml
echo "${SOPS_KEY}" > /tmp/sops.json
GOOGLE_APPLICATION_CREDENTIALS=/tmp/sops.json sops --config /tmp/.sops.yaml -d "${HELM_DIR}/quality/secrets.yaml" > /tmp/secrets-qa.yaml
fi
fi
if [ -n "${SECRET_YAML_QUALITY}" ]; then
echo "${SECRET_YAML_QUALITY}" | base64 -d >> /tmp/secrets-qa.yaml
fi
envsubst < /tmp/secrets-qa.yaml > /tmp/secrets-qa.yaml.tmp && mv /tmp/secrets-qa.yaml.tmp /tmp/secrets-qa.yaml
set +e
QUALITY_VARS=$( tac /tmp/secrets-qa.yaml | grep -e "DB_USERNAME" -e "DB_PASSWORD" -e "DB_HOST" -e "DB_NAME" -e "DATABASE_URL" | base64)
set -e
- |
# Define db operations (three)
set +e
DB_OP_ONE="mysql -u\$DB_USERNAME -p\$DB_PASSWORD -h\$DB_HOST -e \"USE \$DB_NAME_ORIGIN\""
DB_OP_TWO="mysql -u\$DB_USERNAME -p\$DB_PASSWORD -h\$DB_HOST -e \"CREATE DATABASE IF NOT EXISTS \$DB_NAME_FEAT\""
DB_OP_THREE="mysqldump -u\$DB_USERNAME -p\$DB_PASSWORD -h\$DB_HOST \$DB_NAME_ORIGIN --opt --single-transaction --skip-add-locks"
DB_OP_PIPED="mysql -u\$DB_USERNAME -p\$DB_PASSWORD -h\$DB_HOST --max_allowed_packet=32M \$DB_NAME_FEAT"
OPERATION="Cloning"
set -e
- &dboperations |
# CLONE DB phase
# the db parameters could be in two formats:
# - all parameters stored in different variables (DB_USER, DB_PASS, DB_HOST...)
# - url schema: everything is into a string, stored in a variable DATABASE_URL
# if it's the second case, we turn everything into 'single variables' extracting from the url schema
# url schema MUST be complete: `protocol://user:pass@host:port/name`
echo "-> Finding parameters "
set +e
URL_QA=$( echo $QUALITY_VARS | base64 -d | grep -m1 DATABASE_URL | awk '{ print $2}' | base64 -d )
set -e
if [ -z "${URL_QA}" ]; then
echo "-> empty \$URL_QA, proceeding to get all parameters singularly"
set +e
# Take user, pass, and host from the secret
export DB_USERNAME=$( echo $QUALITY_VARS | base64 -d | grep -m1 DB_USERNAME | awk '{ print $2}' | base64 -d )
export DB_PASSWORD=$( echo $QUALITY_VARS | base64 -d | grep -m1 DB_PASSWORD | awk '{ print $2}' | base64 -d )
export DB_HOST=$( echo $QUALITY_VARS | base64 -d | grep -m1 DB_HOST | awk '{ print $2}' | base64 -d )
export DB_NAME_ORIGIN=$( echo $QUALITY_VARS | base64 -d | grep -m1 DB_NAME | awk '{ print $2}' | base64 -d )
set -e
else
echo "-> Extracting params from \$URL_QA"
set +e
export DB_USERNAME=$( echo $URL_QA | awk -F [\/:@?] '{print $4}')
export DB_PASSWORD=$( echo $URL_QA | awk -F [\/:@?] '{print $5}')
export DB_HOST=$( echo $URL_QA | awk -F [\/:@?] '{print $6}')
export DB_NAME_ORIGIN=$( echo $URL_QA | awk -F [\/:@?] '{print $8}')
set -e
fi
echo "checking if needed params are there!"
for var in "DB_USERNAME" "DB_PASSWORD" "DB_HOST" "DB_NAME_ORIGIN"; do
if [ -z "${!var}" ]; then
echo "-> Missing both '${var}' variable or/and DATABASE_URL! Not proceeding with DB cloning"
no_db=1
fi
done
if [ -z "${no_db}" ]; then
if [ -n "${DATABASE_NAME_BRANCH}" ]; then
export DB_NAME_FEAT=$DATABASE_NAME_BRANCH
else
set +e
export DB_NAME_FEAT=$( echo $BRANCH_VARS | base64 -d | grep -m1 DB_NAME | awk '{ print $2}' | base64 -d )
set -e
if [ -z "${DB_NAME_FEAT}" ]; then
# if the secret does not have DB_NAME, it means we only have the url schema way
URL_BRANCH=$( echo $BRANCH_VARS | base64 -d | grep -m1 DATABASE_URL | awk '{ print $2}' | base64 -d )
export DB_NAME_FEAT=$( echo $URL_BRANCH | awk -F [\/:@?] '{print $8}')
fi
fi
echo
echo "-> ${OPERATION} db "
echo
eval "${DB_OP_ONE[@]}" || { echo 'DB login failed! Please check credentials' ; exit 1; }
eval "${DB_OP_TWO[@]}" || { echo 'DB creation failed! Please check user permission, must have CREATE, REFERENCES and DROP' ; exit 1; }
eval "${DB_OP_THREE[@]}" | eval "${DB_OP_PIPED[@]}" || { echo 'DB cloning failed!' ; exit 1; }
else
echo
echo "-> [Warning] Some variables are missing. Cannot proceed to import db"
echo
fi
- |
# HELM APPLICATION
helm repo add current-repo "${CHARTS_URL}"
helm repo update
echo
helm search repo current-repo/"${CHART_NAME}"
echo
echo "Chart version - ${CHART_VERSION}"
if [ -z "${CHART_VERSION}" ]; then
CHART_VERSION=$(helm search repo current-repo/"${CHART_NAME}" | tail -n 1 | awk '{print $2}')
fi
if [ -z "${TIMEOUT}" ]; then
TIMEOUT=600s
fi
- |
cat << EOF > /tmp/replacer.sh
#!/bin/bash
sed 's/name: "${NAMESPACE}"/name: "${APP_NAME}"/g' | sed 's/-tls/-tls-${APP_NAME}/g' | awk '/deployment.yaml|service.yaml|ingress.yaml|configmap.yaml/,/---/'
EOF
chmod 755 /tmp/replacer.sh
echo
echo "-> App ${APP_NAME} is going to be released! Chart version is ${CHART_VERSION}"
echo "--> This is a feature branch! You can check it at ${DOMAIN}"
echo
helm upgrade --install --atomic "${APP_NAME}" "current-repo/${CHART_NAME}" --wait --timeout "${TIMEOUT}" -f /tmp/values.yaml --namespace "${NAMESPACE}" --version ${CHART_VERSION} --post-renderer /tmp/replacer.sh --set ingress.ignoreTest=true --set service.ignoreTest=true
sleep 5
echo
echo "-> ${APP_NAME} released!"
echo
only:
- merge_requests
except:
variables:
- $CI_COMMIT_REF_NAME !~ /^feat/
stop:quality:
image: jobtomelabs/helm-sops-mysql:3.2.0
allow_failure: true
environment:
name: review/$CI_BUILD_REF_NAME
action: stop
stage: stop
variables:
GOOGLE_KEY: ${GOOGLE_KEY_QUALITY}
CLUSTER_NAME: ${CLUSTER_NAME_QUALITY}
CLUSTER_ZONE: ${CLUSTER_ZONE_QUALITY}
NAMESPACE: ${NAMESPACE_QUALITY}
ENVIRONMENT: feature
CI_COMMIT_TAG: ${CI_COMMIT_SHORT_SHA}
script:
- *dbcheckvars
- *dbactivate
- *dbclusterconnect
- *dbfindname
- *dbhelmdir
- *dbsecretid
- |
# Set kubectl command to delete
KUBECTL_COMMAND=( kubectl delete -f /tmp/secrets.yaml )
- *dbkubectlsecret
- *dbsecretunmangling
- |
# Define db operations (two)
DB_OP_ONE="mysql -u\$DB_USERNAME -p\$DB_PASSWORD -h\$DB_HOST -e \"USE \$DB_NAME_ORIGIN\""
DB_OP_TWO="mysql -u\$DB_USERNAME -p\$DB_PASSWORD -h\$DB_HOST -e \"DROP DATABASE \$DB_NAME_FEAT\""
DB_OP_THREE=""
DB_OP_PIPED=""
OPERATION="Dropping"
- *dboperations
- |
# Uninstall helm release
if [ -z "${TIMEOUT}" ]; then
TIMEOUT=600s
fi
helm uninstall "${APP_NAME}" --timeout "${TIMEOUT}" --namespace "${NAMESPACE}"
- |
echo
echo "-> Uninstall completed successfully"
echo
rules:
- if: $CI_MERGE_REQUEST_ID && $CI_COMMIT_REF_NAME =~ /^feat/
when: manual