chart: add bootstrap job (v0.2.0)
Post-install/post-upgrade Job that calls /api/bootstrap on first deploy and stores the admin API key in a Secret (<release>-admin-key by default). Exits cleanly on subsequent upgrades when bootstrap is already complete. Adds ServiceAccount, Role (secrets:create), and RoleBinding as hook resources.
This commit is contained in:
@@ -2,5 +2,5 @@ apiVersion: v2
|
||||
name: terdut-server
|
||||
description: A Helm chart for Terminal Duty — on-call alert management server
|
||||
type: application
|
||||
version: 0.1.0
|
||||
version: 0.2.0
|
||||
appVersion: "latest"
|
||||
|
||||
@@ -32,3 +32,7 @@ app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-server.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "terdut-server.bootstrapSecretName" -}}
|
||||
{{- .Values.bootstrap.secretName | default (printf "%s-admin-key" (include "terdut-server.fullname" .)) }}
|
||||
{{- end }}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
{{- if .Values.bootstrap.enabled }}
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ include "terdut-server.fullname" . }}-bootstrap
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "terdut-server.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
helm.sh/hook: post-install,post-upgrade
|
||||
helm.sh/hook-weight: "0"
|
||||
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
||||
spec:
|
||||
backoffLimit: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "terdut-server.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: bootstrap
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
serviceAccountName: {{ include "terdut-server.fullname" . }}-bootstrap
|
||||
containers:
|
||||
- name: bootstrap
|
||||
image: alpine:3
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
apk add --no-cache curl > /dev/null 2>&1
|
||||
|
||||
SERVICE_URL="http://{{ include "terdut-server.fullname" . }}:{{ .Values.service.port }}"
|
||||
SECRET_NAME="{{ include "terdut-server.bootstrapSecretName" . }}"
|
||||
K8S_API="https://kubernetes.default.svc"
|
||||
SA_TOKEN="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
|
||||
CA_CERT="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
|
||||
NAMESPACE="$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)"
|
||||
|
||||
echo "Waiting for terdut-server to be ready..."
|
||||
RETRIES=60
|
||||
while [ "$RETRIES" -gt 0 ]; do
|
||||
curl -sf "$SERVICE_URL/healthz" > /dev/null 2>&1 && break
|
||||
RETRIES=$((RETRIES - 1))
|
||||
sleep 2
|
||||
done
|
||||
if [ "$RETRIES" -eq 0 ]; then
|
||||
echo "Timed out waiting for server to be ready."
|
||||
exit 1
|
||||
fi
|
||||
echo "Server is ready."
|
||||
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$SERVICE_URL/api/bootstrap" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"{{ .Values.bootstrap.username }}","email":"{{ .Values.bootstrap.email }}"}')
|
||||
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
|
||||
BODY=$(echo "$RESPONSE" | head -1)
|
||||
|
||||
if [ "$HTTP_CODE" = "403" ]; then
|
||||
echo "Server already bootstrapped, nothing to do."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$HTTP_CODE" != "201" ]; then
|
||||
echo "Bootstrap failed (HTTP $HTTP_CODE): $BODY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
API_KEY=$(echo "$BODY" | grep -o '"key":"[^"]*"' | cut -d'"' -f4)
|
||||
if [ -z "$API_KEY" ]; then
|
||||
echo "Failed to extract API key from response."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Bootstrap succeeded. Storing API key in secret '$SECRET_NAME'."
|
||||
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X POST "$K8S_API/api/v1/namespaces/$NAMESPACE/secrets" \
|
||||
--cacert "$CA_CERT" \
|
||||
-H "Authorization: Bearer $SA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$(printf '{"apiVersion":"v1","kind":"Secret","metadata":{"name":"%s"},"stringData":{"api-key":"%s"}}' "$SECRET_NAME" "$API_KEY")")
|
||||
|
||||
if [ "$HTTP_CODE" != "201" ]; then
|
||||
echo "Failed to create secret (HTTP $HTTP_CODE)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Secret '$SECRET_NAME' created successfully."
|
||||
{{- end }}
|
||||
@@ -0,0 +1,50 @@
|
||||
{{- if .Values.bootstrap.enabled }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "terdut-server.fullname" . }}-bootstrap
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "terdut-server.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
helm.sh/hook: post-install,post-upgrade
|
||||
helm.sh/hook-weight: "-1"
|
||||
helm.sh/hook-delete-policy: before-hook-creation
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ include "terdut-server.fullname" . }}-bootstrap
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "terdut-server.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
helm.sh/hook: post-install,post-upgrade
|
||||
helm.sh/hook-weight: "-1"
|
||||
helm.sh/hook-delete-policy: before-hook-creation
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["create"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ include "terdut-server.fullname" . }}-bootstrap
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "terdut-server.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
helm.sh/hook: post-install,post-upgrade
|
||||
helm.sh/hook-weight: "-1"
|
||||
helm.sh/hook-delete-policy: before-hook-creation
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: {{ include "terdut-server.fullname" . }}-bootstrap
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "terdut-server.fullname" . }}-bootstrap
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
@@ -14,3 +14,10 @@ storage:
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
|
||||
bootstrap:
|
||||
enabled: true
|
||||
username: admin
|
||||
email: admin@example.com
|
||||
# secretName overrides the default of <fullname>-admin-key
|
||||
secretName: ""
|
||||
|
||||
Reference in New Issue
Block a user