From 71feab50b126512295d1dc7831879dceb3d71958 Mon Sep 17 00:00:00 2001 From: Morten Olsen Date: Sat, 3 Jan 2026 12:29:44 +0100 Subject: [PATCH] add database to immich --- apps/charts/immich/templates/database.yaml | 107 +----------------- .../immich/templates/db-config-job.yaml | 87 -------------- apps/charts/immich/templates/deployment.yaml | 8 +- apps/charts/immich/values.yaml | 11 +- scripts/fix_immich_complete.sh | 100 ++++++++++++++++ scripts/fix_immich_db_config.sh | 79 +++++++++++++ scripts/fix_immich_password.sh | 88 ++++++++++++++ scripts/trigger_db_config_job.sh | 58 ++++++++++ scripts/update_immich_postgres_password.sh | 61 ++++++++++ 9 files changed, 394 insertions(+), 205 deletions(-) delete mode 100644 apps/charts/immich/templates/db-config-job.yaml create mode 100644 scripts/fix_immich_complete.sh create mode 100644 scripts/fix_immich_db_config.sh create mode 100644 scripts/fix_immich_password.sh create mode 100644 scripts/trigger_db_config_job.sh create mode 100644 scripts/update_immich_postgres_password.sh diff --git a/apps/charts/immich/templates/database.yaml b/apps/charts/immich/templates/database.yaml index 67839cd..8a7fad4 100644 --- a/apps/charts/immich/templates/database.yaml +++ b/apps/charts/immich/templates/database.yaml @@ -1,106 +1 @@ -{{ include "common.externalSecrets.passwordGenerators" . }} -{{ include "common.externalSecrets.externalSecrets" . }} - ---- -apiVersion: v1 -kind: Secret -metadata: - name: "{{ .Release.Name }}-postgres" -type: Opaque -stringData: - POSTGRES_DB: immich - POSTGRES_USER: immich - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: "{{ .Release.Name }}-postgres" -spec: - strategy: - type: Recreate - replicas: 1 - selector: - matchLabels: - app: "{{ .Release.Name }}-postgres" - template: - metadata: - labels: - app: "{{ .Release.Name }}-postgres" - spec: - containers: - - name: postgres - image: "{{ .Values.postgres.image.repository }}:{{ .Values.postgres.image.tag }}" - imagePullPolicy: "{{ .Values.postgres.image.pullPolicy }}" - env: - - name: POSTGRES_DB - valueFrom: - secretKeyRef: - name: "{{ .Release.Name }}-postgres" - key: POSTGRES_DB - - name: POSTGRES_USER - valueFrom: - secretKeyRef: - name: "{{ .Release.Name }}-postgres" - key: POSTGRES_USER - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: "{{ .Release.Name }}-postgres-secret" - key: password - - name: PGDATA - value: /var/lib/postgresql/data/pgdata - ports: - - name: postgres - containerPort: 5432 - protocol: TCP - volumeMounts: - - mountPath: /var/lib/postgresql/data - name: postgres-data - livenessProbe: - exec: - command: - - /bin/sh - - -c - - pg_isready -U immich - readinessProbe: - exec: - command: - - /bin/sh - - -c - - pg_isready -U immich - volumes: - - name: postgres-data - persistentVolumeClaim: - claimName: "{{ .Release.Name }}-postgres-data" - ---- -apiVersion: v1 -kind: Service -metadata: - name: "{{ .Release.Name }}-postgres" - labels: - app: "{{ .Release.Name }}-postgres" -spec: - type: ClusterIP - ports: - - port: 5432 - targetPort: 5432 - protocol: TCP - name: postgres - selector: - app: "{{ .Release.Name }}-postgres" - ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: "{{ .Release.Name }}-postgres-data" -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Gi - storageClassName: "{{ .Values.globals.environment }}" - +{{ include "common.database" . }} diff --git a/apps/charts/immich/templates/db-config-job.yaml b/apps/charts/immich/templates/db-config-job.yaml deleted file mode 100644 index 5bde1b1..0000000 --- a/apps/charts/immich/templates/db-config-job.yaml +++ /dev/null @@ -1,87 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: "{{ .Release.Name }}-db-config-generator" - annotations: - "helm.sh/hook": pre-install,pre-upgrade - "helm.sh/hook-weight": "5" - "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded -spec: - template: - metadata: - annotations: - sidecar.istio.io/inject: "false" - spec: - restartPolicy: OnFailure - serviceAccountName: "{{ .Release.Name }}-db-config-sa" - containers: - - name: generator - image: python:3.11-slim - command: - - /bin/bash - - -c - - | - set -e - # Install kubectl - apt-get update -qq && apt-get install -y -qq curl > /dev/null 2>&1 && \ - curl -sSL "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" -o /tmp/kubectl && \ - chmod +x /tmp/kubectl && mv /tmp/kubectl /usr/local/bin/kubectl - - PASSWORD_B64=$(cat /secrets/password) - # Decode the password (secret is double base64-encoded, Kubernetes auto-decodes first level) - # Then URL encode the password to handle special characters using Python - PASSWORD=$(python3 -c "import base64; import sys; print(base64.b64decode(sys.stdin.read().strip()).decode('utf-8'))" <<< "$PASSWORD_B64") - ENCODED_PASSWORD=$(python3 -c "import urllib.parse; import sys; print(urllib.parse.quote(sys.stdin.read().strip(), safe=''))" <<< "$PASSWORD") - DB_URL="postgresql://immich:${ENCODED_PASSWORD}@{{ .Release.Name }}-postgres.{{ .Release.Namespace }}.svc.cluster.local:5432/immich" - # Create or update the ConfigMap - kubectl create configmap {{ .Release.Name }}-db-config --from-literal=url="${DB_URL}" --dry-run=client -o yaml | kubectl apply -f - - echo "ConfigMap {{ .Release.Name }}-db-config created/updated successfully" - volumeMounts: - - name: postgres-secret - mountPath: /secrets - readOnly: true - volumes: - - name: postgres-secret - secret: - secretName: "{{ .Release.Name }}-postgres-secret" - ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: "{{ .Release.Name }}-db-config-sa" - annotations: - "helm.sh/hook": pre-install,pre-upgrade - "helm.sh/hook-weight": "-10" - "helm.sh/hook-delete-policy": before-hook-creation - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: "{{ .Release.Name }}-db-config-role" - annotations: - "helm.sh/hook": pre-install,pre-upgrade - "helm.sh/hook-weight": "-9" - "helm.sh/hook-delete-policy": before-hook-creation -rules: - - apiGroups: [""] - resources: ["configmaps"] - verbs: ["get", "create", "update", "patch", "delete"] - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: "{{ .Release.Name }}-db-config-rolebinding" - annotations: - "helm.sh/hook": pre-install,pre-upgrade - "helm.sh/hook-weight": "-8" - "helm.sh/hook-delete-policy": before-hook-creation -subjects: - - kind: ServiceAccount - name: "{{ .Release.Name }}-db-config-sa" -roleRef: - kind: Role - name: "{{ .Release.Name }}-db-config-role" - apiGroup: rbac.authorization.k8s.io diff --git a/apps/charts/immich/templates/deployment.yaml b/apps/charts/immich/templates/deployment.yaml index c648773..7892074 100644 --- a/apps/charts/immich/templates/deployment.yaml +++ b/apps/charts/immich/templates/deployment.yaml @@ -21,8 +21,8 @@ spec: env: - name: DB_URL valueFrom: - configMapKeyRef: - name: "{{ .Release.Name }}-db-config" + secretKeyRef: + name: "{{ .Release.Name }}-connection" key: url - name: DB_VECTOR_EXTENSION value: pgvector @@ -124,8 +124,8 @@ spec: env: - name: DB_URL valueFrom: - configMapKeyRef: - name: "{{ .Release.Name }}-db-config" + secretKeyRef: + name: "{{ .Release.Name }}-connection" key: url - name: DB_VECTOR_EXTENSION value: pgvector diff --git a/apps/charts/immich/values.yaml b/apps/charts/immich/values.yaml index d3333fb..3899ab2 100644 --- a/apps/charts/immich/values.yaml +++ b/apps/charts/immich/values.yaml @@ -20,11 +20,6 @@ postgres: tag: pg16@sha256:0a07c4114ba6d1d04effcce3385e9f5ce305eb02e56a3d35948a415a52f193ec pullPolicy: IfNotPresent -# External secrets configuration -externalSecrets: - - name: "{release}-postgres-secret" - passwords: - - name: password - length: 64 - encoding: base64 - allowRepeat: true +# Database configuration +database: + enabled: true diff --git a/scripts/fix_immich_complete.sh b/scripts/fix_immich_complete.sh new file mode 100644 index 0000000..078cd86 --- /dev/null +++ b/scripts/fix_immich_complete.sh @@ -0,0 +1,100 @@ +#!/bin/bash +set -e + +NAMESPACE="shared" +RELEASE_NAME="immich" + +echo "=== Complete immich database password fix ===" +echo "" + +# Step 1: Get PostgreSQL pod name +echo "Step 1: Finding PostgreSQL pod..." +POSTGRES_POD=$(kubectl get pods -n "$NAMESPACE" -l app="${RELEASE_NAME}-postgres" -o jsonpath='{.items[0].metadata.name}' 2>&1) +if [ -z "$POSTGRES_POD" ] || [[ "$POSTGRES_POD" == *"Error"* ]]; then + echo "ERROR: Could not find PostgreSQL pod" + echo "Output: $POSTGRES_POD" + exit 1 +fi +echo "✓ Found PostgreSQL pod: $POSTGRES_POD" + +# Step 2: Get the password from secret +echo "Step 2: Getting password from secret..." +SECRET_B64=$(kubectl get secret "${RELEASE_NAME}-postgres-secret" -n "$NAMESPACE" -o jsonpath='{.data.password}' 2>&1) +if [ -z "$SECRET_B64" ] || [[ "$SECRET_B64" == *"Error"* ]] || [[ "$SECRET_B64" == *"NotFound"* ]]; then + echo "ERROR: Could not find secret ${RELEASE_NAME}-postgres-secret" + echo "Output: $SECRET_B64" + exit 1 +fi + +# Decode password (double base64 decode) +EXTERNAL_SECRETS_B64=$(echo "$SECRET_B64" | base64 -d 2>&1) +PASSWORD=$(echo "$EXTERNAL_SECRETS_B64" | base64 -d 2>&1) +if [ -z "$PASSWORD" ]; then + echo "ERROR: Failed to decode password" + exit 1 +fi +echo "✓ Password retrieved and decoded" + +# Step 3: Update PostgreSQL database password +echo "Step 3: Updating PostgreSQL password in database..." +# Escape single quotes in password for SQL +ESCAPED_PASSWORD=$(echo "$PASSWORD" | sed "s/'/''/g") +kubectl exec "$POSTGRES_POD" -n "$NAMESPACE" -- psql -U immich -d immich -c "ALTER USER immich WITH PASSWORD '${ESCAPED_PASSWORD}';" 2>&1 +if [ $? -eq 0 ]; then + echo "✓ PostgreSQL password updated" +else + echo "WARNING: Failed to update PostgreSQL password (might already be correct)" +fi + +# Step 4: URL encode the password for ConfigMap +echo "Step 4: URL encoding password for ConfigMap..." +ENCODED_PASSWORD=$(python3 -c "import urllib.parse; import sys; print(urllib.parse.quote(sys.stdin.read().strip(), safe=''))" <<< "$PASSWORD" 2>&1) +if [ $? -ne 0 ] || [ -z "$ENCODED_PASSWORD" ]; then + echo "ERROR: Failed to URL encode password" + exit 1 +fi +echo "✓ Password URL encoded" + +# Step 5: Create DB URL and update ConfigMap +echo "Step 5: Updating ConfigMap..." +DB_URL="postgresql://immich:${ENCODED_PASSWORD}@${RELEASE_NAME}-postgres.${NAMESPACE}.svc.cluster.local:5432/immich" +kubectl create configmap "${RELEASE_NAME}-db-config" \ + --from-literal=url="${DB_URL}" \ + --namespace="$NAMESPACE" \ + --dry-run=client -o yaml 2>&1 | kubectl apply -f - 2>&1 + +if [ $? -eq 0 ]; then + echo "✓ ConfigMap updated successfully" +else + echo "ERROR: Failed to update ConfigMap" + exit 1 +fi + +# Step 6: Verify ConfigMap +echo "Step 6: Verifying ConfigMap..." +CM_URL=$(kubectl get configmap "${RELEASE_NAME}-db-config" -n "$NAMESPACE" -o jsonpath='{.data.url}' 2>&1) +if [[ "$CM_URL" == postgresql://immich:* ]]; then + echo "✓ ConfigMap verified: URL starts with postgresql://immich:" +else + echo "WARNING: ConfigMap URL doesn't look correct: $CM_URL" +fi + +# Step 7: Restart deployment +echo "Step 7: Restarting immich-server deployment..." +kubectl rollout restart deployment "${RELEASE_NAME}-server" -n "$NAMESPACE" 2>&1 +if [ $? -eq 0 ]; then + echo "✓ Deployment restart initiated" +else + echo "ERROR: Failed to restart deployment" + exit 1 +fi + +echo "" +echo "=== Fix completed ===" +echo "Waiting for pod to restart..." +sleep 5 +echo "" +echo "Current pod status:" +kubectl get pods -n "$NAMESPACE" | grep "${RELEASE_NAME}-server" || true +echo "" +echo "Check logs with: kubectl logs -n $NAMESPACE -l app=${RELEASE_NAME}-server --tail=50" diff --git a/scripts/fix_immich_db_config.sh b/scripts/fix_immich_db_config.sh new file mode 100644 index 0000000..1645c1b --- /dev/null +++ b/scripts/fix_immich_db_config.sh @@ -0,0 +1,79 @@ +#!/bin/bash +set -e + +RELEASE_NAME="immich" +NAMESPACE="" + +# Try to find the namespace +for ns in immich default apps; do + if kubectl get configmap "${RELEASE_NAME}-db-config" -n "$ns" &>/dev/null; then + NAMESPACE="$ns" + break + fi +done + +if [ -z "$NAMESPACE" ]; then + # Try to find from pod + POD_NAME="immich-server-6759ddb46c-c2cmq" + for ns in immich default apps; do + if kubectl get pod "$POD_NAME" -n "$ns" &>/dev/null; then + NAMESPACE="$ns" + break + fi + done +fi + +if [ -z "$NAMESPACE" ]; then + echo "Error: Could not find immich resources. Please specify namespace manually." + echo "Usage: $0 " + exit 1 +fi + +# Allow manual namespace override +if [ -n "$1" ]; then + NAMESPACE="$1" +fi + +echo "Using namespace: $NAMESPACE" + +# Get the password from the secret (double base64 decode) +echo "Getting password from secret..." +SECRET_B64=$(kubectl get secret "${RELEASE_NAME}-postgres-secret" -n "$NAMESPACE" -o jsonpath='{.data.password}') + +if [ -z "$SECRET_B64" ]; then + echo "Error: Could not find secret ${RELEASE_NAME}-postgres-secret in namespace $NAMESPACE" + exit 1 +fi + +# Decode twice: Kubernetes base64 -> External Secrets base64 -> actual password +EXTERNAL_SECRETS_B64=$(echo "$SECRET_B64" | base64 -d) +PASSWORD=$(echo "$EXTERNAL_SECRETS_B64" | base64 -d) + +if [ -z "$PASSWORD" ]; then + echo "Error: Failed to decode password" + exit 1 +fi + +echo "Password retrieved successfully" + +# URL encode the password using Python (same as the Helm hook job does) +ENCODED_PASSWORD=$(python3 -c "import urllib.parse; import sys; print(urllib.parse.quote(sys.stdin.read().strip(), safe=''))" <<< "$PASSWORD") + +# Construct the DB URL +DB_URL="postgresql://immich:${ENCODED_PASSWORD}@${RELEASE_NAME}-postgres.${NAMESPACE}.svc.cluster.local:5432/immich" + +echo "Updating ConfigMap ${RELEASE_NAME}-db-config..." + +# Update the ConfigMap +kubectl create configmap "${RELEASE_NAME}-db-config" \ + --from-literal=url="${DB_URL}" \ + --namespace="$NAMESPACE" \ + --dry-run=client -o yaml | kubectl apply -f - + +echo "ConfigMap updated successfully!" + +# Restart the immich-server deployment to pick up the new ConfigMap +echo "Restarting immich-server deployment..." +kubectl rollout restart deployment "${RELEASE_NAME}-server" -n "$NAMESPACE" + +echo "Done! The immich-server pod will restart with the correct database password." diff --git a/scripts/fix_immich_password.sh b/scripts/fix_immich_password.sh new file mode 100644 index 0000000..cdf58b3 --- /dev/null +++ b/scripts/fix_immich_password.sh @@ -0,0 +1,88 @@ +#!/bin/bash +set -e + +NAMESPACE="shared" +RELEASE_NAME="immich" + +echo "=== Fixing immich database password issue ===" +echo "Namespace: $NAMESPACE" +echo "" + +# Step 1: Get the password from secret +echo "Step 1: Getting password from secret..." +SECRET_B64=$(kubectl get secret "${RELEASE_NAME}-postgres-secret" -n "$NAMESPACE" -o jsonpath='{.data.password}' 2>&1) + +if [ -z "$SECRET_B64" ] || [[ "$SECRET_B64" == *"Error"* ]] || [[ "$SECRET_B64" == *"NotFound"* ]]; then + echo "ERROR: Could not find secret ${RELEASE_NAME}-postgres-secret" + echo "Secret output: $SECRET_B64" + exit 1 +fi + +echo "✓ Secret found" + +# Step 2: Decode password (double base64 decode) +echo "Step 2: Decoding password..." +EXTERNAL_SECRETS_B64=$(echo "$SECRET_B64" | base64 -d 2>&1) +if [ $? -ne 0 ]; then + echo "ERROR: Failed to decode secret (first level)" + exit 1 +fi + +PASSWORD=$(echo "$EXTERNAL_SECRETS_B64" | base64 -d 2>&1) +if [ $? -ne 0 ]; then + echo "ERROR: Failed to decode secret (second level)" + exit 1 +fi + +if [ -z "$PASSWORD" ]; then + echo "ERROR: Password is empty after decoding" + exit 1 +fi + +echo "✓ Password decoded successfully" + +# Step 3: URL encode the password +echo "Step 3: URL encoding password..." +ENCODED_PASSWORD=$(python3 -c "import urllib.parse; import sys; print(urllib.parse.quote(sys.stdin.read().strip(), safe=''))" <<< "$PASSWORD" 2>&1) +if [ $? -ne 0 ] || [ -z "$ENCODED_PASSWORD" ]; then + echo "ERROR: Failed to URL encode password" + echo "Python output: $ENCODED_PASSWORD" + exit 1 +fi + +echo "✓ Password URL encoded" + +# Step 4: Create DB URL +echo "Step 4: Creating database URL..." +DB_URL="postgresql://immich:${ENCODED_PASSWORD}@${RELEASE_NAME}-postgres.${NAMESPACE}.svc.cluster.local:5432/immich" +echo "✓ Database URL created" + +# Step 5: Update ConfigMap +echo "Step 5: Updating ConfigMap..." +kubectl create configmap "${RELEASE_NAME}-db-config" \ + --from-literal=url="${DB_URL}" \ + --namespace="$NAMESPACE" \ + --dry-run=client -o yaml 2>&1 | kubectl apply -f - 2>&1 + +if [ $? -eq 0 ]; then + echo "✓ ConfigMap updated successfully" +else + echo "ERROR: Failed to update ConfigMap" + exit 1 +fi + +# Step 6: Restart deployment +echo "Step 6: Restarting immich-server deployment..." +kubectl rollout restart deployment "${RELEASE_NAME}-server" -n "$NAMESPACE" 2>&1 + +if [ $? -eq 0 ]; then + echo "✓ Deployment restart initiated" +else + echo "ERROR: Failed to restart deployment" + exit 1 +fi + +echo "" +echo "=== Done ===" +echo "The immich-server pod should restart with the correct database password." +echo "Check status with: kubectl get pods -n $NAMESPACE | grep immich-server" diff --git a/scripts/trigger_db_config_job.sh b/scripts/trigger_db_config_job.sh new file mode 100644 index 0000000..16ee051 --- /dev/null +++ b/scripts/trigger_db_config_job.sh @@ -0,0 +1,58 @@ +#!/bin/bash +set -e + +RELEASE_NAME="immich" +NAMESPACE="${1:-immich}" # Default to immich namespace, or pass as first argument + +echo "Triggering db-config job in namespace: $NAMESPACE" + +# Create a temporary job based on the Helm hook job +kubectl create job --from=cronjob/immich-db-config-generator "${RELEASE_NAME}-db-config-manual-$(date +%s)" -n "$NAMESPACE" 2>/dev/null || \ +kubectl create job "${RELEASE_NAME}-db-config-manual-$(date +%s)" \ + --image=python:3.11-slim \ + -n "$NAMESPACE" \ + -- /bin/bash -c " + set -e + apt-get update -qq && apt-get install -y -qq curl > /dev/null 2>&1 && \ + curl -sSL \"https://dl.k8s.io/release/\$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl\" -o /tmp/kubectl && \ + chmod +x /tmp/kubectl && mv /tmp/kubectl /usr/local/bin/kubectl + + PASSWORD_B64=\$(cat /secrets/password) + PASSWORD=\$(python3 -c \"import base64; import sys; print(base64.b64decode(sys.stdin.read().strip()).decode('utf-8'))\" <<< \"\$PASSWORD_B64\") + ENCODED_PASSWORD=\$(python3 -c \"import urllib.parse; import sys; print(urllib.parse.quote(sys.stdin.read().strip(), safe=''))\" <<< \"\$PASSWORD\") + DB_URL=\"postgresql://immich:\${ENCODED_PASSWORD}@${RELEASE_NAME}-postgres.${NAMESPACE}.svc.cluster.local:5432/immich\" + kubectl create configmap ${RELEASE_NAME}-db-config --from-literal=url=\"\${DB_URL}\" --dry-run=client -o yaml | kubectl apply -f - + echo \"ConfigMap ${RELEASE_NAME}-db-config updated successfully\" + " \ + --overrides=' +{ + "spec": { + "serviceAccountName": "'"${RELEASE_NAME}"'-db-config-sa", + "volumes": [ + { + "name": "postgres-secret", + "secret": { + "secretName": "'"${RELEASE_NAME}"'-postgres-secret" + } + } + ], + "containers": [{ + "name": "generator", + "volumeMounts": [ + { + "name": "postgres-secret", + "mountPath": "/secrets", + "readOnly": true + } + ] + }] + } +}' + +echo "Job created. Waiting for completion..." +kubectl wait --for=condition=complete --timeout=60s job -l job-name="${RELEASE_NAME}-db-config-manual" -n "$NAMESPACE" || true + +echo "Restarting immich-server..." +kubectl rollout restart deployment "${RELEASE_NAME}-server" -n "$NAMESPACE" + +echo "Done!" diff --git a/scripts/update_immich_postgres_password.sh b/scripts/update_immich_postgres_password.sh new file mode 100644 index 0000000..3255405 --- /dev/null +++ b/scripts/update_immich_postgres_password.sh @@ -0,0 +1,61 @@ +#!/bin/bash +set -e + +# Find the pod namespace +POD_NAME="immich-postgres-544f467fd8-2k84c" +NAMESPACE="" + +# Try to find the namespace +for ns in immich default apps; do + if kubectl get pod "$POD_NAME" -n "$ns" &>/dev/null; then + NAMESPACE="$ns" + break + fi +done + +if [ -z "$NAMESPACE" ]; then + # Try without namespace specification + if kubectl get pod "$POD_NAME" -A &>/dev/null; then + NAMESPACE=$(kubectl get pod "$POD_NAME" -A -o jsonpath='{.items[0].metadata.namespace}' 2>/dev/null || \ + kubectl get pod "$POD_NAME" -A -o jsonpath='{.metadata.namespace}' 2>/dev/null) + fi +fi + +if [ -z "$NAMESPACE" ]; then + echo "Error: Could not find pod $POD_NAME in any namespace" + exit 1 +fi + +echo "Found pod in namespace: $NAMESPACE" + +# Get the password from the secret +# The secret is stored as base64 in Kubernetes, and External Secrets uses base64 encoding +# So we need to decode twice: Kubernetes base64 -> External Secrets base64 -> actual password +SECRET_B64=$(kubectl get secret "immich-postgres-secret" -n "$NAMESPACE" -o jsonpath='{.data.password}') + +if [ -z "$SECRET_B64" ]; then + echo "Error: Could not find secret immich-postgres-secret in namespace $NAMESPACE" + exit 1 +fi + +# Decode the password (double base64 decode: Kubernetes -> External Secrets -> actual password) +# First decode: Kubernetes base64 to get External Secrets base64 value +EXTERNAL_SECRETS_B64=$(echo "$SECRET_B64" | base64 -d) +# Second decode: External Secrets base64 to get actual password +PASSWORD=$(echo "$EXTERNAL_SECRETS_B64" | base64 -d) + +if [ -z "$PASSWORD" ]; then + echo "Error: Failed to decode password" + exit 1 +fi + +echo "Updating PostgreSQL password for user 'immich'..." + +# Update the password in PostgreSQL +# Escape single quotes in password for SQL by doubling them +ESCAPED_PASSWORD=$(echo "$PASSWORD" | sed "s/'/''/g") + +# Use psql to update the password +kubectl exec "$POD_NAME" -n "$NAMESPACE" -- psql -U immich -d immich -c "ALTER USER immich WITH PASSWORD '${ESCAPED_PASSWORD}';" + +echo "Password updated successfully!"