|
| 1 | +{{- range $index, $service := .Values.services }} |
| 2 | +{{- $dbName := replace "_" "-" $service.database }} |
| 3 | +{{- $host := include "mongodb.fullname" $ }} |
| 4 | +{{- $generatedUsername := printf "%s_%s_user" (trunc 27 $service.name) (randAlphaNum 4 | lower) }} |
| 5 | +{{- $generatedPassword := printf "%s%s%s" (randAlpha 6) (randNumeric 6) (randAlpha 6 | upper) }} |
| 6 | + |
| 7 | +{{/* Same naming as the other datastore charts, so the service chart can find |
| 8 | + these by datastore/database/release: <release>-<database>-<service>-mongodb-* */}} |
| 9 | +{{- $secretName := printf "%s-%s-%s-mongodb-database-secret" $.Release.Name $dbName $service.name }} |
| 10 | + |
| 11 | +{{/* Keep the credentials of an existing install: the user already exists in |
| 12 | + mongod with this password, and regenerating it would lock the app out. */}} |
| 13 | +{{- $username := $generatedUsername }} |
| 14 | +{{- $password := $generatedPassword }} |
| 15 | +{{- $existingSecret := lookup "v1" "Secret" $.Release.Namespace $secretName }} |
| 16 | +{{- if $existingSecret }} |
| 17 | + {{- with $existingSecret.data }} |
| 18 | + {{- if hasKey . "MONGO_USER" }} |
| 19 | + {{- $username = index . "MONGO_USER" | b64dec }} |
| 20 | + {{- end }} |
| 21 | + {{- if hasKey . "MONGO_PASSWORD" }} |
| 22 | + {{- $password = index . "MONGO_PASSWORD" | b64dec }} |
| 23 | + {{- end }} |
| 24 | + {{- end }} |
| 25 | +{{- end }} |
| 26 | +{{- $uri := printf "mongodb://%s:%s@%s:27017/%s?authSource=%s" $username $password $host $service.database $service.database }} |
| 27 | +--- |
| 28 | +apiVersion: v1 |
| 29 | +kind: ConfigMap |
| 30 | +metadata: |
| 31 | + name: {{ $.Release.Name }}-{{ $dbName }}-{{ $service.name }}-mongodb-configmap |
| 32 | + namespace: {{ $.Release.Namespace }} |
| 33 | +data: |
| 34 | + MONGO_HOST: {{ $host | quote }} |
| 35 | + MONGO_PORT: "27017" |
| 36 | + MONGO_DB: {{ $service.database | quote }} |
| 37 | +--- |
| 38 | +apiVersion: v1 |
| 39 | +kind: Secret |
| 40 | +metadata: |
| 41 | + name: {{ $secretName }} |
| 42 | + namespace: {{ $.Release.Namespace }} |
| 43 | +type: Opaque |
| 44 | +data: |
| 45 | + MONGO_USER: {{ $username | b64enc }} |
| 46 | + MONGO_PASSWORD: {{ $password | b64enc }} |
| 47 | + # The user is created inside its own database, so authSource points there. |
| 48 | + MONGO_URI: {{ $uri | b64enc }} |
| 49 | + MONGODB_URI: {{ $uri | b64enc }} |
| 50 | +--- |
| 51 | +{{/* A Job's spec.template is immutable, so anything that changes the pod must |
| 52 | + change the name too: helm then creates a new Job and prunes the old one |
| 53 | + instead of failing the upgrade with "field is immutable". The password is |
| 54 | + left out of the hash on purpose - Job names are visible to anyone who can |
| 55 | + list jobs - and is read from the Secret at run time instead of being |
| 56 | + templated into the script. */}} |
| 57 | +{{- $sig := printf "%s|%s|%s|%s" $.Chart.Version $.Values.version $username $service.database | sha256sum | trunc 8 }} |
| 58 | +{{- $initName := printf "mongodb-%s-%s-init" $.Release.Name $service.name | trunc 54 | trimSuffix "-" }} |
| 59 | +apiVersion: batch/v1 |
| 60 | +kind: Job |
| 61 | +metadata: |
| 62 | + name: {{ $initName }}-{{ $sig }} |
| 63 | + namespace: {{ $.Release.Namespace }} |
| 64 | + labels: |
| 65 | + app.kubernetes.io/name: mongodb |
| 66 | + app.kubernetes.io/instance: {{ $.Release.Name }} |
| 67 | + app.kubernetes.io/managed-by: {{ $.Release.Service }} |
| 68 | + app.kubernetes.io/component: db-init |
| 69 | + helm.sh/chart: {{ include "mongodb.chart" $ }} |
| 70 | +spec: |
| 71 | + # A Job, not a bare Pod, so `helm --wait` is satisfied once it succeeds. |
| 72 | + # The script itself waits for mongod; activeDeadlineSeconds caps the case |
| 73 | + # where mongod never comes up. |
| 74 | + activeDeadlineSeconds: 1800 |
| 75 | + template: |
| 76 | + metadata: |
| 77 | + labels: |
| 78 | + app.kubernetes.io/name: mongodb |
| 79 | + app.kubernetes.io/instance: {{ $.Release.Name }} |
| 80 | + app.kubernetes.io/component: db-init |
| 81 | + spec: |
| 82 | + {{- with $.Values.nodeSelector }} |
| 83 | + nodeSelector: |
| 84 | + {{- toYaml . | nindent 8 }} |
| 85 | + {{- end }} |
| 86 | + {{- with $.Values.tolerations }} |
| 87 | + tolerations: |
| 88 | + {{- toYaml . | nindent 8 }} |
| 89 | + {{- end }} |
| 90 | + {{- with $.Values.affinity }} |
| 91 | + affinity: |
| 92 | + {{- toYaml . | nindent 8 }} |
| 93 | + {{- end }} |
| 94 | + restartPolicy: OnFailure |
| 95 | + containers: |
| 96 | + - name: mongodb-init-user |
| 97 | + image: "mongo:{{ $.Values.version }}" |
| 98 | + securityContext: |
| 99 | + runAsNonRoot: true |
| 100 | + runAsUser: 999 |
| 101 | + runAsGroup: 999 |
| 102 | + allowPrivilegeEscalation: false |
| 103 | + capabilities: |
| 104 | + drop: |
| 105 | + - ALL |
| 106 | + command: ["/bin/bash", "-c"] |
| 107 | + args: |
| 108 | + - | |
| 109 | + set -euo pipefail |
| 110 | + until mongosh --quiet --norc --host "$MONGO_HOST" --eval "db.adminCommand('ping')" >/dev/null 2>&1; do |
| 111 | + echo "waiting for $MONGO_HOST"; sleep 3 |
| 112 | + done |
| 113 | + # Credentials are read from the environment inside the script rather |
| 114 | + # than passed as -u/-p, so they never appear in the process arguments. |
| 115 | + mongosh --quiet --norc --host "$MONGO_HOST" \ |
| 116 | + --eval ' |
| 117 | + db.getSiblingDB("admin").auth(process.env.ROOT_USER, process.env.ROOT_PASSWORD); |
| 118 | + const d = db.getSiblingDB(process.env.APP_DB); |
| 119 | + const roles = [{ role: "readWrite", db: process.env.APP_DB }, { role: "dbAdmin", db: process.env.APP_DB }]; |
| 120 | + if (d.getUser(process.env.APP_USER)) { |
| 121 | + d.updateUser(process.env.APP_USER, { pwd: process.env.APP_PASSWORD, roles: roles }); |
| 122 | + print("updated user " + process.env.APP_USER); |
| 123 | + } else { |
| 124 | + d.createUser({ user: process.env.APP_USER, pwd: process.env.APP_PASSWORD, roles: roles }); |
| 125 | + print("created user " + process.env.APP_USER); |
| 126 | + } |
| 127 | + ' |
| 128 | + env: |
| 129 | + - name: MONGO_HOST |
| 130 | + value: {{ $host | quote }} |
| 131 | + - name: APP_DB |
| 132 | + value: {{ $service.database | quote }} |
| 133 | + - name: ROOT_USER |
| 134 | + valueFrom: |
| 135 | + secretKeyRef: |
| 136 | + name: {{ include "mongodb.rootSecretName" $ }} |
| 137 | + key: mongodb-root-username |
| 138 | + - name: ROOT_PASSWORD |
| 139 | + valueFrom: |
| 140 | + secretKeyRef: |
| 141 | + name: {{ include "mongodb.rootSecretName" $ }} |
| 142 | + key: mongodb-root-password |
| 143 | + - name: APP_USER |
| 144 | + valueFrom: |
| 145 | + secretKeyRef: |
| 146 | + name: {{ $secretName }} |
| 147 | + key: MONGO_USER |
| 148 | + - name: APP_PASSWORD |
| 149 | + valueFrom: |
| 150 | + secretKeyRef: |
| 151 | + name: {{ $secretName }} |
| 152 | + key: MONGO_PASSWORD |
| 153 | + resources: |
| 154 | + requests: |
| 155 | + cpu: "50m" |
| 156 | + memory: "128Mi" |
| 157 | + limits: |
| 158 | + cpu: "500m" |
| 159 | + # mongosh is a Node process and needs headroom over its idle size. |
| 160 | + memory: "512Mi" |
| 161 | +--- |
| 162 | +{{- end }} |
0 commit comments