mirror of
https://github.com/morten-olsen/homelab-apps.git
synced 2026-02-08 01:36:28 +01:00
add database to immich
This commit is contained in:
@@ -1,106 +1 @@
|
|||||||
{{ include "common.externalSecrets.passwordGenerators" . }}
|
{{ include "common.database" . }}
|
||||||
{{ 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 }}"
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -21,8 +21,8 @@ spec:
|
|||||||
env:
|
env:
|
||||||
- name: DB_URL
|
- name: DB_URL
|
||||||
valueFrom:
|
valueFrom:
|
||||||
configMapKeyRef:
|
secretKeyRef:
|
||||||
name: "{{ .Release.Name }}-db-config"
|
name: "{{ .Release.Name }}-connection"
|
||||||
key: url
|
key: url
|
||||||
- name: DB_VECTOR_EXTENSION
|
- name: DB_VECTOR_EXTENSION
|
||||||
value: pgvector
|
value: pgvector
|
||||||
@@ -124,8 +124,8 @@ spec:
|
|||||||
env:
|
env:
|
||||||
- name: DB_URL
|
- name: DB_URL
|
||||||
valueFrom:
|
valueFrom:
|
||||||
configMapKeyRef:
|
secretKeyRef:
|
||||||
name: "{{ .Release.Name }}-db-config"
|
name: "{{ .Release.Name }}-connection"
|
||||||
key: url
|
key: url
|
||||||
- name: DB_VECTOR_EXTENSION
|
- name: DB_VECTOR_EXTENSION
|
||||||
value: pgvector
|
value: pgvector
|
||||||
|
|||||||
@@ -20,11 +20,6 @@ postgres:
|
|||||||
tag: pg16@sha256:0a07c4114ba6d1d04effcce3385e9f5ce305eb02e56a3d35948a415a52f193ec
|
tag: pg16@sha256:0a07c4114ba6d1d04effcce3385e9f5ce305eb02e56a3d35948a415a52f193ec
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
# External secrets configuration
|
# Database configuration
|
||||||
externalSecrets:
|
database:
|
||||||
- name: "{release}-postgres-secret"
|
enabled: true
|
||||||
passwords:
|
|
||||||
- name: password
|
|
||||||
length: 64
|
|
||||||
encoding: base64
|
|
||||||
allowRepeat: true
|
|
||||||
|
|||||||
100
scripts/fix_immich_complete.sh
Normal file
100
scripts/fix_immich_complete.sh
Normal file
@@ -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"
|
||||||
79
scripts/fix_immich_db_config.sh
Normal file
79
scripts/fix_immich_db_config.sh
Normal file
@@ -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 <namespace>"
|
||||||
|
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."
|
||||||
88
scripts/fix_immich_password.sh
Normal file
88
scripts/fix_immich_password.sh
Normal file
@@ -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"
|
||||||
58
scripts/trigger_db_config_job.sh
Normal file
58
scripts/trigger_db_config_job.sh
Normal file
@@ -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!"
|
||||||
61
scripts/update_immich_postgres_password.sh
Normal file
61
scripts/update_immich_postgres_password.sh
Normal file
@@ -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!"
|
||||||
Reference in New Issue
Block a user