mirror of
https://gitlab.kube.huskypup.net/Scooby/Homelabv4.git
synced 2026-08-20 23:16:49 +00:00
196 lines
6.8 KiB
YAML
196 lines
6.8 KiB
YAML
---
|
|
# CronJob to sync TeslaMate database password from CNPG secret to Grafana datasource secret
|
|
# This ensures Grafana always has the current password even when CNPG rotates it
|
|
apiVersion: batch/v1
|
|
kind: CronJob
|
|
metadata:
|
|
name: sync-teslamate-password
|
|
namespace: grafana
|
|
spec:
|
|
# Run every 30 minutes to catch password rotations (rotations happen at most daily)
|
|
schedule: "*/30 * * * *"
|
|
successfulJobsHistoryLimit: 3
|
|
failedJobsHistoryLimit: 3
|
|
concurrencyPolicy: Forbid
|
|
jobTemplate:
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: teslamate-password-sync
|
|
spec:
|
|
serviceAccountName: teslamate-password-sync
|
|
restartPolicy: OnFailure
|
|
containers:
|
|
- name: sync
|
|
image: docker.io/alpine/k8s:1.32.13
|
|
securityContext:
|
|
runAsUser: 10000
|
|
runAsGroup: 10000
|
|
runAsNonRoot: true
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: true
|
|
capabilities:
|
|
drop: ["ALL"]
|
|
seccompProfile:
|
|
type: RuntimeDefault
|
|
volumeMounts:
|
|
- name: tmp
|
|
mountPath: /tmp
|
|
env:
|
|
- name: GRAFANA_ADMIN_PASSWORD
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: grafana-admin-secret
|
|
key: admin-password
|
|
optional: true
|
|
command:
|
|
- /bin/bash
|
|
- -c
|
|
- |
|
|
set -e
|
|
|
|
echo "Fetching current password from CNPG secret in teslamate namespace..."
|
|
CURRENT_PASSWORD=$(kubectl get secret -n teslamate pg-teslamate-app -o jsonpath='{.data.password}' | base64 -d)
|
|
|
|
echo "Fetching current password from Grafana datasource secret..."
|
|
GRAFANA_PASSWORD=$(kubectl get secret -n grafana grafana-teslamate-datasource -o jsonpath='{.data.TESLAMATE_DB_PASSWORD}' | base64 -d)
|
|
|
|
if [ "$CURRENT_PASSWORD" != "$GRAFANA_PASSWORD" ]; then
|
|
echo "Passwords differ - updating Grafana secret..."
|
|
kubectl create secret generic grafana-teslamate-datasource \
|
|
--from-literal=TESLAMATE_DB_PASSWORD="$CURRENT_PASSWORD" \
|
|
-n grafana \
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
echo "Password synced to secret"
|
|
else
|
|
echo "Passwords match in secrets"
|
|
fi
|
|
|
|
echo "Finding running Grafana pod..."
|
|
GRAFANA_POD=$(kubectl get pod -n grafana -l app.kubernetes.io/name=grafana --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}')
|
|
|
|
if [ -z "$GRAFANA_POD" ]; then
|
|
echo "No running Grafana pod found, skipping API update"
|
|
exit 0
|
|
fi
|
|
|
|
echo "Using Grafana pod: $GRAFANA_POD"
|
|
echo "Updating Grafana datasource password via API (ensures password works after Grafana restart)..."
|
|
|
|
# Get admin password from Grafana secret (fallback to 'admin' if not found)
|
|
ADMIN_PASS=$(kubectl get secret -n grafana grafana -o jsonpath='{.data.admin-password}' 2>/dev/null | base64 -d || echo "admin")
|
|
|
|
# Update datasource via API with current password
|
|
RESULT=$(kubectl exec -n grafana "$GRAFANA_POD" -c grafana -- curl -s -X PUT \
|
|
-H "Content-Type: application/json" \
|
|
-u "admin:$ADMIN_PASS" \
|
|
http://localhost:3000/api/datasources/uid/TeslaMate \
|
|
-d "{
|
|
\"name\": \"TeslaMate\",
|
|
\"type\": \"grafana-postgresql-datasource\",
|
|
\"uid\": \"TeslaMate\",
|
|
\"url\": \"pg-teslamate-rw.teslamate.svc.cluster.local:5432\",
|
|
\"database\": \"teslamate\",
|
|
\"user\": \"teslamate\",
|
|
\"access\": \"proxy\",
|
|
\"isDefault\": false,
|
|
\"secureJsonData\": {
|
|
\"password\": \"$CURRENT_PASSWORD\"
|
|
},
|
|
\"jsonData\": {
|
|
\"sslmode\": \"disable\",
|
|
\"postgresVersion\": 1600,
|
|
\"timescaledb\": false,
|
|
\"database\": \"teslamate\"
|
|
}
|
|
}")
|
|
|
|
echo "API Response: $RESULT"
|
|
|
|
# Test datasource connection
|
|
echo "Testing datasource connection..."
|
|
TEST_RESULT=$(kubectl exec -n grafana "$GRAFANA_POD" -c grafana -- curl -s -X POST \
|
|
-u "admin:$ADMIN_PASS" \
|
|
http://localhost:3000/api/datasources/uid/TeslaMate/health)
|
|
|
|
echo "Health Check: $TEST_RESULT"
|
|
|
|
if echo "$TEST_RESULT" | grep -q '"status":"OK"'; then
|
|
echo "✅ Datasource password updated and verified successfully!"
|
|
else
|
|
echo "⚠️ Datasource updated but connection test failed"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Done!"
|
|
volumes:
|
|
- name: tmp
|
|
emptyDir: {}
|
|
---
|
|
# ServiceAccount for the CronJob
|
|
apiVersion: v1
|
|
kind: ServiceAccount
|
|
metadata:
|
|
name: teslamate-password-sync
|
|
namespace: grafana
|
|
---
|
|
# Role with permissions to read CNPG secret and update Grafana secret
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: Role
|
|
metadata:
|
|
name: teslamate-password-sync
|
|
namespace: grafana
|
|
rules:
|
|
- apiGroups: [""]
|
|
resources: ["secrets"]
|
|
verbs: ["get", "create", "patch", "update"]
|
|
- apiGroups: [""]
|
|
resources: ["pods", "pods/exec"]
|
|
verbs: ["get", "list", "watch", "create"]
|
|
- apiGroups: ["apps"]
|
|
resources: ["deployments"]
|
|
verbs: ["get", "patch"]
|
|
---
|
|
# Role to read secret from teslamate namespace
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: Role
|
|
metadata:
|
|
name: teslamate-password-sync
|
|
namespace: teslamate
|
|
rules:
|
|
- apiGroups: [""]
|
|
resources: ["secrets"]
|
|
resourceNames: ["pg-teslamate-app"]
|
|
verbs: ["get"]
|
|
---
|
|
# RoleBinding in grafana namespace
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: teslamate-password-sync
|
|
namespace: grafana
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: teslamate-password-sync
|
|
namespace: grafana
|
|
roleRef:
|
|
kind: Role
|
|
name: teslamate-password-sync
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
# RoleBinding in teslamate namespace
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: teslamate-password-sync-grafana
|
|
namespace: teslamate
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: teslamate-password-sync
|
|
namespace: grafana
|
|
roleRef:
|
|
kind: Role
|
|
name: teslamate-password-sync
|
|
apiGroup: rbac.authorization.k8s.io
|