-
Notifications
You must be signed in to change notification settings - Fork 1
/
configure.sh
executable file
·402 lines (343 loc) · 16.2 KB
/
configure.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
#!/bin/bash
# This script prepares all the configuration files and install components such as argocd
HELM_ARGOCD=argocd
HELM_PLATFORM=platform-name
PLATFORM_NS=platform
GREEN='\033[0;32m'
NC='\033[0m' # No Color
# Parse arguments
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
--github-token=*)
export TOKEN="${key#*=}" # Extracts value after '='
shift # Removes processed argument
;;
--upgrade)
UPGRADE=true
shift # Removes processed argument
;;
*) # Unknown option
echo "Unknown argument: $key"
exit 1
;;
esac
done
# make sure the environment variables defined before are availble for this script
source ~/.profile
# make sure we have valid access to the cluster
kubectl cluster-info
# Capture the exit status
status=$?
if [ $status -ne 0 ]; then
kops export kubeconfig --admin --state $KOPS_STATE_STORE --name=$CLUSTER_NAME
fi
# Function to check if all applications are healthy
all_apps_healthy() {
# Fetch all applications and their statuses
statuses=$(kubectl get applications.argoproj.io -n argocd -o jsonpath='{.items[*].status.health.status}')
# Check each status
for status in $statuses; do
if [[ $status != "Healthy" ]]; then
return 1
fi
done
return 0
}
function applyLetsEncryptClusterIssuer() {
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-production
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: $LETSENCRYPT_EMAIL
privateKeySecretRef:
name: letsencrypt-production
solvers:
- http01:
ingress:
class: traefik
EOF
}
function encryptGitHubReposSecret() {
file="templates/base/secrets/github-environments.yaml"
# if the file doesn't exist in the helm ignore files
if ! grep -q "^$file$" chart/.helmignore; then
helm template $HELM_PLATFORM chart \
--show-only $file \
--values chart/values.yaml 2>/dev/null \
| kubeseal --controller-name=sealed-secrets \
--controller-namespace=platform \
--format yaml > chart/templates/base/secrets/github-environments-encrypted.yaml
echo "Secret github-environments is now encrypted"
# when the secret is generated, we add the original to the helm ignore
# when we'll apply this chart, only the encrypted will be submited
# the original secret will stay here, inside your personal codespace only
echo "$file" >> chart/.helmignore
fi
# make sure the original secret won't go to git
if git ls-files --error-unmatch $file > /dev/null 2>&1; then
# Remove the file from Git while keeping it locally
git rm --cached $chart/file
# Append the file or pattern to .gitignore if not already present
if ! grep -q "^chart/$file$" .gitignore; then
echo "$file" >> .gitignore
fi
fi
}
function encryptGitHubAdminAuthSecret() {
file="templates/base/secrets/github-admin-auth.yaml"
# if the file doesn't exist in the helm ignore files
if ! grep -q "^$file$" chart/.helmignore; then
helm template $HELM_PLATFORM chart \
--show-only $file \
--values chart/values.yaml 2>/dev/null \
| kubeseal --controller-name=sealed-secrets \
--controller-namespace=platform \
--format yaml > chart/templates/base/secrets/github-admin-auth-encrypted.yaml
echo "Secret github-admin-auth is now encrypted"
# when the secret is generated, we add the original to the helm ignore
# when we'll apply this chart, only the encrypted will be submited
# the original secret will stay here, inside your personal codespace only
echo "$file" >> chart/.helmignore
fi
# make sure the original secret won't go to git
if git ls-files --error-unmatch $file > /dev/null 2>&1; then
# Remove the file from Git while keeping it locally
git rm --cached $file
# Append the file or pattern to .gitignore if not already present
if ! grep -q "^$file$" .gitignore; then
echo "$file" >> .gitignore
fi
fi
}
function encryptAWSEcrSecrets() {
path="templates/secrets"
file="aws-dev.yaml"
# if the file doesn't exist in the helm ignore files
if ! grep -q "^$file$" chart/.helmignore; then
cd chart/templates/each/dependencies || return
helm template dependencies . \
--show-only $path/$file \
--values values.yaml 2>/dev/null \
| kubeseal --controller-name=sealed-secrets \
--controller-namespace=platform \
--scope=cluster-wide \
--format yaml > $path/aws-dev-encrypted.yaml
echo "Secret $file is now encrypted"
# when the secret is generated, we add the original to the helm ignore
# when we'll apply this chart, only the encrypted will be submited
# the original secret will stay here, inside your personal codespace only
cd ../../../../
pwd
# echo "$file" >> chart/.helmignore
yq eval '.metadata.namespace = "{{ .Values.repo }}-development"' chart/templates/each/dependencies/$path/aws-dev-encrypted.yaml -i
## TODO: here to replace the namespace variable
fi
# # make sure the original secret won't go to git
# if git ls-files --error-unmatch $file > /dev/null 2>&1; then
# # Remove the file from Git while keeping it locally
# git rm --cached $file
# # Append the file or pattern to .gitignore if not already present
# if ! grep -q "^$file$" .gitignore; then
# echo "$file" >> .gitignore
# fi
# fi
}
function cleanupSecretsFromValuesYaml() {
yq eval -i '.aws.secret.AWS_ACCESS_KEY_ID = null | .aws.secret.AWS_SECRET_ACCESS_KEY = null' chart/values.yaml
yq eval -i '.github.secrets.admin = null | .github.secrets.repositories = null' chart/values.yaml
cp -f chart/values.yaml chart/templates/gene/values.yaml
cp -f chart/values.yaml chart/templates/each/dependencies/values.yaml
}
# validations
if [ -z "$GITHUB_TOKEN" ]; then
echo "You should run this command inside a GitHub Codespace"
fi
if [ -z "$AWS_ACCOUNT" ] || [ -z "$CLUSTER_NAME" ]; then
echo "Missing environment variables such as AWS_ACCOUNT or CLUSTER_NAME"
fi
if [[ -z "$TOKEN" ]]; then
echo "GitHub Token not provided"
exit 1
fi
# replace the already known values.yaml file using the environment variables
yq eval -i '.org = env(GITHUB_ORG) | .domain = env(CLUSTER_NAME) | .root = env(CLUSTER_DOMAIN)' chart/values.yaml
yq eval -i '.aws.account = env(AWS_ACCOUNT) | .aws.account style="double" | .aws.region = env(AWS_DEFAULT_REGION)' chart/values.yaml
yq eval -i '.aws.secret.AWS_ACCESS_KEY_ID = env(AWS_ACCESS_KEY_ID) | .aws.secret.AWS_SECRET_ACCESS_KEY = env(AWS_SECRET_ACCESS_KEY)' chart/values.yaml
cp -f chart/values.yaml chart/templates/gene/values.yaml
cp -f chart/values.yaml chart/templates/each/dependencies/values.yaml
# some of the variables we do not know yet, such as the github admin secret and the service repositories secret
# so let's replace it here
# trying to use the logged in token from the codespace
yq eval -i '.github.secrets.repositories = env(TOKEN)' chart/values.yaml
# install argocd
if helm list --all-namespaces | grep -q "^$HELM_ARGOCD\s"; then
echo -n ""
else
helm repo add argo https://argoproj.github.io/argo-helm &>/dev/null
helm repo update &>/dev/null
kubectl create namespace argocd &>/dev/null
helm install argocd argo/argo-cd --namespace argocd --set configs.params."server\.insecure"=true &>/dev/null
fi
sleep 5
# attempt to login to argocd
if argocd version --client=false --port-forward --port-forward-namespace argocd &>/dev/null; then
echo -e "${GREEN}You are logged into ArgoCD.${NC}"
else
argocd login localhost:8080 --username admin \
--port-forward --port-forward-namespace argocd --plaintext \
--password $(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d)
fi
# verify if the chart is installed already, if not, then install
STATUS=$(helm status "$HELM_PLATFORM" 2>&1)
if [[ "$STATUS" == "Error: release: not found" ]]; then
helm upgrade $HELM_PLATFORM chart --create-namespace --install
sleep 5
fi
if [[ $UPGRADE == true ]]; then
helm upgrade $HELM_PLATFORM chart --create-namespace --install
fi
# wait for traefik load balancer to be available
# then update the Route53 DNS with traefik load balancer endpoint
END_TIME=$(($(date +%s) + 120))
while true; do
STATUS=$(helm status "$HELM_PLATFORM" --output=json | jq -r .info.status)
if [[ "$STATUS" == "deployed" ]]; then
echo "Helm release $HELM_PLATFORM has been successfully deployed!"
echo "Waiting for traefik deployment to be ready and to have an available replica..."
while true; do
# Get desired and available replicas
AVAILABLE_REPLICAS=$(kubectl get deployment "traefik" -n "$PLATFORM_NS" -o=jsonpath='{.status.availableReplicas}')
if [[ "1" == "$AVAILABLE_REPLICAS" ]]; then
echo -e "${GREEN}Traefik is healthy!${NC}"
### The traefik deployment is healthy
### Now we wait until it creates a load balancer and have a hostname available
while true; do
LB_HOSTNAME=$(kubectl get svc traefik -n platform -o jsonpath='{.status.loadBalancer.ingress[*].hostname}')
if [ -n "$LB_HOSTNAME" ]; then
echo "Traefik is healthy and has a LoadBalancer attached!"
break
else
echo -e "Waiting for traefik to have an available cluster load balancer..."
sleep 15 # wait for 10 seconds before rechecking
fi
done
### Get the zone id from route 53
HOSTED_ZONE_ID=$(aws route53 list-hosted-zones | jq --arg domain "$CLUSTER_DOMAIN." '.HostedZones[] | select(.Name==$domain) | .Id | split("/")[2]' | tr -d '"')
echo "Updating the Route53 DNS records to point to $LB_HOSTNAME (Traefik Load Balancer)"
# Check if the record already exists
RECORD_EXISTS_1=$(aws route53 list-resource-record-sets --hosted-zone-id $HOSTED_ZONE_ID | jq -r ".ResourceRecordSets[] | select(.Name == \"$CLUSTER_NAME.\")")
# verify if the route 53 dns upadte is needed
if [ "$LB_HOSTNAME" != "$(echo $RECORD_EXISTS_1 | jq -c ".ResourceRecords[0].Value" | tr -d '"')" ]; then
echo "Updating DNS records in Route53"
if [[ ! -z $RECORD_EXISTS_1 ]]; then
# Delete the record
echo -e "Route53 DNS record already exists, deleting first..."
aws route53 change-resource-record-sets --hosted-zone-id "${HOSTED_ZONE_ID}" --change-batch "{
\"Comment\": \"Delete record\",
\"Changes\": [{
\"Action\": \"DELETE\",
\"ResourceRecordSet\": {
\"Name\": \"${CLUSTER_NAME}\",
\"Type\": \"CNAME\",
\"TTL\": 1,
\"ResourceRecords\": $(echo "${RECORD_EXISTS_1}" | jq -c ".ResourceRecords")
}
}]
}" >/dev/null 2>&1
echo -e "Also deleting the *.domain"
# Delete the record for the *.domain
aws route53 change-resource-record-sets --hosted-zone-id "${HOSTED_ZONE_ID}" --change-batch "{
\"Comment\": \"Delete record\",
\"Changes\": [{
\"Action\": \"DELETE\",
\"ResourceRecordSet\": {
\"Name\": \"*.${CLUSTER_NAME}\",
\"Type\": \"CNAME\",
\"TTL\": 1,
\"ResourceRecords\": $(echo "${RECORD_EXISTS_1}" | jq -c ".ResourceRecords")
}
}]
}" >/dev/null 2>&1
fi
# Create the record again
aws route53 change-resource-record-sets --hosted-zone-id "${HOSTED_ZONE_ID}" --change-batch "{
\"Comment\": \"Create record\",
\"Changes\": [{
\"Action\": \"CREATE\",
\"ResourceRecordSet\": {
\"Name\": \"${CLUSTER_NAME}\",
\"Type\": \"CNAME\",
\"TTL\": 1,
\"ResourceRecords\": [{
\"Value\": \"${LB_HOSTNAME}\"
}]
}
}]
}" >/dev/null 2>&1
echo "Creating DNS records 2"
# Create the record again for the *.domain
aws route53 change-resource-record-sets --hosted-zone-id "${HOSTED_ZONE_ID}" --change-batch "{
\"Comment\": \"Create record\",
\"Changes\": [{
\"Action\": \"CREATE\",
\"ResourceRecordSet\": {
\"Name\": \"*.${CLUSTER_NAME}\",
\"Type\": \"CNAME\",
\"TTL\": 1,
\"ResourceRecords\": [{
\"Value\": \"${LB_HOSTNAME}\"
}]
}
}]
}" >/dev/null 2>&1
else
echo "Skipping Route53 Hostname update since it's already in sync"
fi
# apply the cluster issuer to generate dynamic ssl certificates
applyLetsEncryptClusterIssuer
echo -e "\n${GREEN}Domain https://argocd.$CLUSTER_NAME should now be available (TTL 60)${NC}"
echo -e "${GREEN}ArgoCD admin password is: $(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d)${NC}"
sleep 2
# Wait loop
# echo -e "\nVerifying ArgoCD applications status.."
# while ! all_apps_healthy; do
# echo "Waiting for all ArgoCD applications to be healthy..."
# sleep 10 # Wait for 10 seconds before rechecking
# done
# echo "All ArgoCD applications are healthy!"
# verify if generators is already deployed or not
kubectl get applications/generators -n argocd &>/dev/null
# $? is a special variable that holds the exit status of the last command executed
if [[ $? -ne 0 ]]; then
echo "Activating the generators..."
# helm upgrade $HELM_PLATFORM chart --set generators=true
else
echo "Generators are active"
fi
#### from here we assume the platform tools are already deployed and healthy and the generators as well
#### almost ready to commit the platform to git to reflect in the cluster
#### just need to encrypt the secrets
encryptGitHubReposSecret
encryptGitHubAdminAuthSecret
encryptAWSEcrSecrets
### here we remove the secrets from the values.yaml we used before
### now they are encrypted and can safely be added to the github repository
cleanupSecretsFromValuesYaml
exit 0
else
sleep 2
fi
done
elif [[ "$(date +%s)" -gt "$END_TIME" ]]; then
echo "Timed out waiting for Helm release $HELM_PLATFORM to be deployed."
helm upgrade $HELM_PLATFORM chart --create-namespace --install
else
sleep 7
fi
done