-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathbootstrap_local_kind.sh
executable file
·322 lines (287 loc) · 16.1 KB
/
bootstrap_local_kind.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
#!/bin/bash
# Copyright (c) 2024 Activa Digital.
#
# 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.
# Import utility functions
for function in ./func/*; do
. $function
done
for graph in ./graph/*; do
. $graph
done
echo -e "$HEADER"
# Check prerequisites
required_commands=("date" "cut" "jq" "tr" "base64" "kind" "yq" "envsubst" "helm" "kubectl" "curl" "sed" "clusterctl")
missing_commands=()
for cmd in "${required_commands[@]}"; do
check_command "$cmd"
done
if [ ${#missing_commands[@]} -ne 0 ]; then # Check if the array of missing commands is not empty
echo "$(r_echo NAVARCOS:ERROR:) Prerequisites failed! Missing the following applications"
for cmd in "${missing_commands[@]}"; do
echo " - $cmd"
done
exit 1 # if there are missing commands
else
echo "$(g_echo NAVARCOS:INFO:) All required commands are installed. Proceeding"
fi
# Check for existing values file or use test one
if [ ! -f "values.yaml" ]
then
echo "$(y_echo NAVARCOS:WARN:) File 'values.yaml' does not exist"
echo "$(y_echo NAVARCOS:WARN:) Using test values (in ./test/values.yaml)"
export NAVARCOS_VALUES_FILE="./test/values.yaml"
else
echo "$(g_echo NAVARCOS:INFO:) Using 'values.yaml'"
export NAVARCOS_VALUES_FILE="./values.yaml"
fi
# Check for sysctls values needed by docker clusters
check_sysctl
# ENV variables in commons.env are generated from NAVARCOS_VALUES_FILE
source ./commons.env
# Execute the command and store the output as an array
mapfile -t CLUSTERS_ARRAY < <(kind get clusters)
# Check if Navarcos cluster is present in the array
CLUSTER_EXISTS=false
for CLUSTER in "${CLUSTERS_ARRAY[@]}"; do
if [[ "${CLUSTER}" == "${NAVARCOS_KIND_CLUSTERNAME}" ]]; then
CLUSTER_EXISTS=true
break
fi
done
if [ "${CLUSTER_EXISTS}" = true ]; then
echo "$(y_echo NAVARCOS:WARN:) The cluster '${NAVARCOS_KIND_CLUSTERNAME}' already exists"
# Ask the user for deletion or to stop the script
read -p "$(y_echo NAVARCOS:) (d)elete/(r)euse '${NAVARCOS_KIND_CLUSTERNAME}' cluster [this will continue the installation] or E(x)it? (d/r/x): " ANSWER
if [ "${ANSWER}" == "d" ]; then
# Execute the command to delete the cluster
kind delete cluster --name ${NAVARCOS_KIND_CLUSTERNAME}
echo "$(y_echo NAVARCOS:WARN:) Cluster '${NAVARCOS_KIND_CLUSTERNAME}' has been deleted"
elif [ "${ANSWER}" == "r" ]; then
NAVARCOS_KIND_REUSE=true
echo "$(g_echo NAVARCOS:INFO:) Reusing '${NAVARCOS_KIND_CLUSTERNAME}' cluster"
else
NAVARCOS_KIND_UPDATE=true
echo "$(g_echo NAVARCOS:INFO:) Updating values then exit"
fi
else
echo "$(g_echo NAVARCOS:INFO:) Cluster '${NAVARCOS_KIND_CLUSTERNAME}' does not exist"
fi
# Create kind cluster
if [ "${NAVARCOS_KIND_UPDATE}" != true ]; then
echo "$(g_echo NAVARCOS:INFO:) Create kind '${NAVARCOS_KIND_CLUSTERNAME}' cluster"
if [ "${NAVARCOS_KIND_REUSE}" != true ]; then
kind create cluster --config ${LOCALKINDCONFIG} --name ${NAVARCOS_KIND_CLUSTERNAME}
fi
if [ $? != 0 ] ; then
echo "$(r_echo NAVARCOS:ERROR: Failed to deploy Kind Cluster, check logs)"
exit 1
fi
fi
# Get Navarcos Kind Ingress IP address to access services
export NAVARCOS_DOMAIN_SUFFIX=".$(kubectl get node navarcos-control-plane -o jsonpath='{.status.addresses[0].address}').nip.io"
echo "$(g_echo NAVARCOS:INFO:) Kind Navarcos domain: $(g_echo ${NAVARCOS_DOMAIN_SUFFIX})"
# Refresh ENV variables to account for Kind Navarcos Ingress IP
source ./commons.env
# Files to be rendered in ./bootstrap_out/
declare -A YAML_FILES
YAML_FILES[./bootstrap_local_kind_yaml/keycloak.values.TEMPLATE.yaml]="keycloak.values.yaml"
YAML_FILES[./bootstrap_local_kind_yaml/plancia.configmaps.TEMPLATE.yaml]="plancia.configmaps.yaml"
# Check for already rendered out files and backup them
for ORPHAN in ${BOOTSTRAP_OUT}/*
do
[ -f "${ORPHAN}" ] || continue
if [ "${ORPHAN##*/}" != "DoNotRemove.md" ]; then
mkdir ${PARKINGFOLDER} > /dev/null 2>&1
mv "${ORPHAN}" "${PARKINGFOLDER}"
echo "$(g_echo NAVARCOS:INFO:) File $(g_echo ${ORPHAN}) PARKED in ${PARKINGFOLDER}"
fi
done
# Render files in ./bootstrap_out/
for i in "${!YAML_FILES[@]}"
do
echo "$(g_echo NAVARCOS:INFO:) Rendering ${YAML_FILES[$i]} from $i"
envsubst < "$i" > "${BOOTSTRAP_OUT}/${YAML_FILES[$i]}"
yq "${YAML_FILES[$i]}" > /dev/null
if [ $? != 0 ] ; then
echo "$(r_echo NAVARCOS:ERROR:) Invalid YAML in ${YAML_FILES[$i]}"
exit 1
fi
done
if [ "${NAVARCOS_KIND_UPDATE}" == true ]; then
echo "$(g_echo NAVARCOS:INFO:) Values updated. Exiting"
exit 0
fi
# Wait for kube-scheduler
echo "$(g_echo NAVARCOS:INFO:) Waiting for kube scheduler"
kubectl wait --timeout 300s --for=condition=ready pod -n kube-system -l component=kube-scheduler
if [ $? != 0 ];then
echo "$(r_echo NAVARCOS:ERROR:) Error waiting for Kind kube-scheduler to be ready"
exit 1
fi
echo "$(g_echo NAVARCOS:INFO:) Install Tigera/Calico Operator"
helm upgrade calico-crds tigera-crds-navarcos --install --wait --create-namespace --namespace tigera-operator \
--version $(yq '.clusterapi.tigera.targetRevision' < values.providers.yaml) \
--repo https://navarcos.github.io/navarcos-charts
if [ $? != 0 ];then
echo "$(r_echo NAVARCOS:ERROR:) Error installing Tigera/Calico Operator CRDs"
exit 1
fi
helm upgrade calico tigera-operator-navarcos --install --wait --namespace tigera-operator \
--version $(yq '.clusterapi.tigera.targetRevision' < values.providers.yaml) \
--repo https://navarcos.github.io/navarcos-charts
if [ $? != 0 ];then
echo "$(r_echo NAVARCOS:ERROR:) Error installing Tigera/Calico Operator"
exit 1
fi
echo "$(g_echo NAVARCOS:INFO:) Install metrics-server"
helm upgrade metrics-server metrics-server-navarcos --install --wait --namespace kube-system \
--version $(yq '.navarcos.metricsServer.targetRevision' < values.providers.yaml) \
--repo https://navarcos.github.io/navarcos-charts \
--values ./bootstrap_yaml/metrics-server.values.yaml
if [ $? != 0 ];then
echo "$(r_echo NAVARCOS:ERROR:) Error installing metrics-server"
exit 1
fi
echo "$(g_echo NAVARCOS:INFO:) Install cert-manager"
helm upgrade cert-manager cert-manager --install --wait --create-namespace --namespace cert-manager \
--version $(yq '.clusterapi.certManager.targetRevision' < values.providers.yaml) \
--repo https://charts.jetstack.io \
--values ./bootstrap_yaml/cert-manager.values.yaml
if [ $? != 0 ];then
echo "$(r_echo NAVARCOS:ERROR:) Error installing cert-manager"
exit 1
fi
echo "$(g_echo NAVARCOS:INFO:) Create self-signed cert-manager ClusterIssuer"
kubectl apply -f ./bootstrap_yaml/cert-manager_self-signed.yaml
kubectl wait --for=condition=ready certificate -n cert-manager navarcos-ca
NAVARCOS_CA=$(kubectl get secret navarcos-ca-secret -n cert-manager -o jsonpath='{.data.ca\.crt}'|base64 -d)
echo "$(g_echo NAVARCOS:INFO:) Kind Navarcos CA certificate"
echo "${NAVARCOS_CA}"
echo "$(g_echo NAVARCOS:INFO:) Install ClusterAPI"
clusterctl init --wait-providers \
--core cluster-api:$(yq '.clusterapi.capi.targetRevision' < values.providers.yaml) \
--bootstrap kubeadm:$(yq '.clusterapi.capi.targetRevision' < values.providers.yaml) \
--control-plane kubeadm:$(yq '.clusterapi.capi.targetRevision' < values.providers.yaml) \
--infrastructure docker:$(yq '.clusterapi.capi.targetRevision' < values.providers.yaml) \
--infrastructure vsphere:$(yq '.clusterapi.vsphere.targetRevision' < values.providers.yaml) \
--ipam incluster:$(yq '.clusterapi.ipam.targetRevision' < values.providers.yaml) \
--config ./bootstrap_yaml/clusterctl-IPAM.config.yaml
if [ $? != 0 ];then
echo "$(r_echo NAVARCOS:ERROR:) Error installing ClusterAPI"
exit 1
fi
echo "$(g_echo NAVARCOS:INFO:) Install Ingress NGINX"
helm upgrade ingress-nginx ingress-nginx --install --wait --create-namespace --namespace ingress-nginx \
--version $(yq '.navarcos.ingressNginx.targetRevision' < values.providers.yaml) \
--repo https://kubernetes.github.io/ingress-nginx \
--values https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/hack/manifest-templates/provider/kind/values.yaml \
--values ./bootstrap_yaml/ingress-nginx.values.yaml
if [ $? != 0 ];then
echo "$(r_echo NAVARCOS:ERROR:) Error installing Ingress NGINX"
exit 1
fi
echo "$(g_echo NAVARCOS:INFO:) Waiting for NGINX to be ready"
kubectl wait --timeout 180s --for=condition=ready pod -n ingress-nginx \
-l app.kubernetes.io/component=controller \
-l app.kubernetes.io/name=ingress-nginx
echo "$(g_echo NAVARCOS:INFO:) Install Keycloak"
helm upgrade keycloak keycloak --install --wait --create-namespace --namespace keycloak \
--version $(yq '.navarcos.keycloak.targetRevision' < values.providers.yaml) \
--repo https://charts.bitnami.com/bitnami \
--values ${BOOTSTRAP_OUT}/keycloak.values.yaml
if [ $? != 0 ];then
echo "$(r_echo NAVARCOS:ERROR:) Error installing Keycloak"
exit 1
fi
echo "$(g_echo NAVARCOS:INFO:) Keycloak reachable at https://$(yq '.ingress.hostname' < ${BOOTSTRAP_OUT}/keycloak.values.yaml)"
echo "$(g_echo NAVARCOS:INFO:) Waiting for Keycloak to be ready"
kubectl wait --timeout 300s --for=condition=ready pod -n keycloak \
-l app.kubernetes.io/component=keycloak \
-l app.kubernetes.io/name=keycloak
if [ $? != 0 ];then
echo "$(r_echo NAVARCOS:ERROR:) Error on waiting for Keycloak to be ready"
exit 1
fi
echo "$(g_echo NAVARCOS:INFO:) Create plancia environment"
kubectl apply -f ./bootstrap_yaml/plancia.namespace.yaml
kubectl apply -f ${BOOTSTRAP_OUT}/plancia.configmaps.yaml
kubectl create secret generic navarcos-ca --from-literal=ca.crt="${NAVARCOS_CA}" --namespace plancia
echo "$(g_echo NAVARCOS:INFO:) Getting Keycloak token"
# Get Keycloak admin password from K8s
NAVARCOS_KEYCLOAK_PASSWORD=$(kubectl get secret keycloak -n keycloak -o json|jq -r '.data."admin-password"'|base64 -d)
# Get Keycloak token for admin user
NAVARCOS_KEYCLOAK_TOKEN=$(curl -s -k -d "client_id=admin-cli" -d "username=ncadmin" -d "password=${NAVARCOS_KEYCLOAK_PASSWORD}" -d "grant_type=password" "${NAVARCOS_KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" | sed -n 's|.*"access_token":"\([^"]*\)".*|\1|p')
echo "$(g_echo NAVARCOS:INFO:) Create Plancia client in Keycloak master realm"
# Create plancia client in master realm
NAVARCOS_KEYCLOAK_RESULT=$(curl -s -k -X POST -d "$(cat "./bootstrap_data/keycloak_client.json")" -H "Content-Type: application/json" -H "Authorization: bearer ${NAVARCOS_KEYCLOAK_TOKEN}" "${NAVARCOS_KEYCLOAK_URL}/admin/realms/master/clients")
# Get plancia client data
NAVARCOS_KEYCLOAK_RESULT=$(curl -s -k -H "Content-Type: application/json" -H "Authorization: bearer ${NAVARCOS_KEYCLOAK_TOKEN}" "${NAVARCOS_KEYCLOAK_URL}/admin/realms/master/clients")
# Extract plancia client secret
export NAVARCOS_PLANCIA_SECRET=$(echo "${NAVARCOS_KEYCLOAK_RESULT}" | jq -r '.[] | select(.clientId=="plancia") | .secret')
echo "$(g_echo NAVARCOS:INFO:) Plancia master Secret= ${NAVARCOS_PLANCIA_SECRET}"
# Get plancia service account
NAVARCOS_KEYCLOAK_RESULT=$(curl -s -k -H "Content-Type: application/json" -H "Authorization: bearer ${NAVARCOS_KEYCLOAK_TOKEN}" "${NAVARCOS_KEYCLOAK_URL}/admin/realms/master/users?exact=true&username=service-account-plancia")
# Extract plancia service account ID
export NAVARCOS_PLANCIA_SA_ID=$(echo "${NAVARCOS_KEYCLOAK_RESULT}" | jq -r '.[] | .id')
echo "$(g_echo NAVARCOS:INFO:) Plancia master Service Account ID= ${NAVARCOS_PLANCIA_SA_ID}"
# Create K8s secret for plancia service account in master realm
[ -z "${NAVARCOS_PLANCIA_SECRET}" ] || kubectl create secret generic plancia-keycloak-client --namespace plancia \
--from-literal=clientId=plancia \
--from-literal=clientSecret=${NAVARCOS_PLANCIA_SECRET} \
--from-literal=realm=master
echo "$(g_echo NAVARCOS:INFO:) Adding admin roles to Plancia client in master realm"
# Get master realm roles for plancia service account
NAVARCOS_KEYCLOAK_RESULT=$(curl -s -k -H "Content-Type: application/json" -H "Authorization: bearer ${NAVARCOS_KEYCLOAK_TOKEN}" "${NAVARCOS_KEYCLOAK_URL}/admin/realms/master/users/${NAVARCOS_PLANCIA_SA_ID}/role-mappings/realm/available")
# Extract role IDs for admin and create-realm
export NAVARCOS_KEYCLOAK_ROLE_ADMIN_ID=$(echo "${NAVARCOS_KEYCLOAK_RESULT}" | jq -r '.[] | select(.name=="admin") | .id')
export NAVARCOS_KEYCLOAK_ROLE_REALM_ID=$(echo "${NAVARCOS_KEYCLOAK_RESULT}" | jq -r '.[] | select(.name=="create-realm") | .id')
# Add roles to plancia service account
NAVARCOS_KEYCLOAK_RESULT=$(curl -s -k -X POST -d "$(envsubst < "./bootstrap_data/keycloak_serviceaccount.TEMPLATE.json")" -H "Content-Type: application/json" -H "Authorization: bearer ${NAVARCOS_KEYCLOAK_TOKEN}" "${NAVARCOS_KEYCLOAK_URL}/admin/realms/master/users/${NAVARCOS_PLANCIA_SA_ID}/role-mappings/realm")
echo "$(g_echo NAVARCOS:INFO:) Create Keycloak Navarcos realm"
NAVARCOS_KEYCLOAK_RESULT=$(curl -s -k -X POST -d "$(envsubst < "./bootstrap_data/keycloak_realm.TEMPLATE.json")" -H "Content-Type: application/json" -H "Authorization: bearer ${NAVARCOS_KEYCLOAK_TOKEN}" "${NAVARCOS_KEYCLOAK_URL}/admin/realms")
echo "$(g_echo NAVARCOS:INFO:) Create Navarcos ClusterRoleBinding for navarcos_admin role in Navarcos realm"
kubectl apply -f ./bootstrap_yaml/cluster_namespaces_roles.navarcos.yaml
echo "$(g_echo NAVARCOS:INFO:) Create plancia clients secrets"
NAVARCOS_KEYCLOAK_RESULT=$(curl -s -k -H "Content-Type: application/json" -H "Authorization: bearer ${NAVARCOS_KEYCLOAK_TOKEN}" "${NAVARCOS_KEYCLOAK_URL}/admin/realms/Navarcos/clients")
# Extract client secrets
export NAVARCOS_GITLAB_SECRET=$(echo "${NAVARCOS_KEYCLOAK_RESULT}" | jq -r '.[] | select(.clientId=="gitlab-navarcos") | .secret')
export NAVARCOS_HARBOR_SECRET=$(echo "${NAVARCOS_KEYCLOAK_RESULT}" | jq -r '.[] | select(.clientId=="harbor-navarcos") | .secret')
export NAVARCOS_OPENSEARCH_SECRET=$(echo "${NAVARCOS_KEYCLOAK_RESULT}" | jq -r '.[] | select(.clientId=="opensearch-navarcos") | .secret')
export NAVARCOS_OAUTH2PROXY_SECRET=$(echo "${NAVARCOS_KEYCLOAK_RESULT}" | jq -r '.[] | select(.clientId=="oauth2proxy-navarcos") | .secret')
export NAVARCOS_PLANCIA_BE_SECRET=$(echo "${NAVARCOS_KEYCLOAK_RESULT}" | jq -r '.[] | select(.clientId=="plancia-backend") | .secret')
export NAVARCOS_GRAFANA_SECRET=$(echo "${NAVARCOS_KEYCLOAK_RESULT}" | jq -r '.[] | select(.clientId=="grafana-navarcos") | .secret')
# Create K8s secret for plancia-backend service account in Navarcos realm
[ -z "${NAVARCOS_PLANCIA_BE_SECRET}" ] || kubectl create secret generic plancia-backend-client --namespace plancia \
--from-literal=clientId=plancia-backend \
--from-literal=clientSecret=${NAVARCOS_PLANCIA_BE_SECRET} \
--from-literal=realm=Navarcos
# Create K8s secret for plancia-frontend account in Navarcos realm
[ -z "${NAVARCOS_PLANCIA_BE_SECRET}" ] || kubectl create secret generic plancia-frontend-client --namespace plancia \
--from-literal=clientId=plancia \
--from-literal=realm=Navarcos
if [ ! -f "values.yaml" ]
then
touch ${BOOTSTRAP_OUT}/values.yaml
export NAVARCOS_VALUES_FILE="${BOOTSTRAP_OUT}/values.yaml"
else
export NAVARCOS_VALUES_FILE="./values.yaml"
fi
echo "$(g_echo NAVARCOS:INFO:) Storing secrets in ${NAVARCOS_VALUES_FILE}"
# Store client secrets in values for future reference
yq -i ".navarcos.gitlab.oidcSecret = \"${NAVARCOS_GITLAB_SECRET}\"" ${NAVARCOS_VALUES_FILE}
yq -i ".navarcos.opensearch.oidcSecret = \"${NAVARCOS_OPENSEARCH_SECRET}\"" ${NAVARCOS_VALUES_FILE}
yq -i ".navarcos.grafana.oidcSecret = \"${NAVARCOS_GRAFANA_SECRET}\"" ${NAVARCOS_VALUES_FILE}
yq -i ".navarcos.harbor.oidcSecret = \"${NAVARCOS_HARBOR_SECRET}\"" ${NAVARCOS_VALUES_FILE}
yq -i ".navarcos.oauth2Proxy.oidcSecret = \"${NAVARCOS_OAUTH2PROXY_SECRET}\"" ${NAVARCOS_VALUES_FILE}
yq -i ".navarcos.plancia.backend.oidcSecret = \"${NAVARCOS_PLANCIA_BE_SECRET}\"" ${NAVARCOS_VALUES_FILE}