Files
Homelabv4/scripts/teslamate-bootstrap.sh
2026-03-09 20:21:35 -05:00

132 lines
5.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Teslamate Bootstrap - Auto-configure PostgreSQL with ESO
set -euo pipefail
echo "=== Teslamate Bootstrap - Fully Automated ==="
# Change to the apps directory for relative paths
cd "$(dirname "$0")/../apps" || exit 1
NS=teslamate
CLUSTER=pg-teslamate
# 1) Ensure namespace
kubectl get ns "${NS}" >/dev/null 2>&1 || kubectl create ns "${NS}"
# 2) Apply CNPG cluster (auto-generates DB password)
echo "Applying Teslamate PostgreSQL cluster..."
kubectl apply -f teslamate/cnpg-cluster.yaml
# 3) Wait for CNPG cluster
echo "Waiting for CNPG cluster ${CLUSTER}..."
kubectl -n "${NS}" wait --for=condition=Ready "cluster/${CLUSTER}" --timeout=300s
# 3.5) Set up PostgreSQL extensions and grant superuser
echo "Setting up PostgreSQL extensions for Teslamate..."
PRIMARY_POD=$(kubectl get pod -n "${NS}" -l cnpg.io/cluster="${CLUSTER}",role=primary -o jsonpath='{.items[0].metadata.name}')
if [ -n "$PRIMARY_POD" ]; then
echo "Granting superuser to teslamate user..."
kubectl exec -n "${NS}" "$PRIMARY_POD" -- psql -U postgres -c "ALTER USER teslamate WITH SUPERUSER;" 2>/dev/null || echo " (user may already have superuser)"
echo "Creating required PostgreSQL extensions..."
kubectl exec -n "${NS}" "$PRIMARY_POD" -- psql -U postgres -d teslamate -c "CREATE EXTENSION IF NOT EXISTS cube;" 2>/dev/null || echo " (cube extension may already exist)"
kubectl exec -n "${NS}" "$PRIMARY_POD" -- psql -U postgres -d teslamate -c "CREATE EXTENSION IF NOT EXISTS earthdistance;" 2>/dev/null || echo " (earthdistance extension may already exist)"
echo "✅ PostgreSQL extensions configured"
else
echo "⚠️ Warning: Could not find primary pod, skipping extension setup"
fi
# 4) Apply ESO secrets (auto-rotate DB passwords)
echo "Applying Teslamate ESO secrets (auto-generates passwords)..."
kubectl apply -f teslamate/cnpg-secrets.yaml
# 5) Wait for password to be generated
echo "Waiting for ESO to generate database password..."
for i in {1..30}; do
if kubectl -n "${NS}" get secret pg-teslamate-app >/dev/null 2>&1; then
echo "✅ Database password generated"
break
fi
echo " waiting for secret... (attempt $i/30)"
sleep 2
done
# 6) Initialize encryption key in Vault if it doesn't exist
echo "Initializing encryption key in Vault..."
# Get Vault root token from secret
VAULT_ROOT_TOKEN=$(kubectl -n vault get secret vault-init-keys -o jsonpath='{.data.VAULT_ROOT_TOKEN}' 2>/dev/null | base64 -d || echo "")
if [ -z "$VAULT_ROOT_TOKEN" ]; then
echo "⚠️ Warning: Could not retrieve Vault root token from secret vault-init-keys"
echo "Skipping encryption key creation. You'll need to create it manually."
echo ""
echo "To create the encryption key manually:"
echo " ENCRYPTION_KEY=\$(openssl rand -base64 32)"
echo " kubectl exec -n vault vault-0 -- vault kv put secret/teslamate/config encryption_key=\"\${ENCRYPTION_KEY}\""
echo ""
# Continue anyway - the ExternalSecret will show an error if the key doesn't exist
else
# Check if the secret already exists in Vault
if kubectl exec -n vault vault-0 -- env VAULT_TOKEN="${VAULT_ROOT_TOKEN}" vault kv get secret/teslamate/config >/dev/null 2>&1; then
echo "✅ Encryption key already exists in Vault"
else
echo "Generating new encryption key..."
ENCRYPTION_KEY=$(openssl rand -base64 32)
# Write to Vault using root token
if kubectl exec -n vault vault-0 -- env VAULT_TOKEN="${VAULT_ROOT_TOKEN}" vault kv put secret/teslamate/config encryption_key="${ENCRYPTION_KEY}"; then
echo "✅ Encryption key stored in Vault"
else
echo "❌ Failed to write to Vault"
echo "Please create the encryption key manually:"
echo " kubectl exec -n vault vault-0 -- env VAULT_TOKEN=\"${VAULT_ROOT_TOKEN}\" vault kv put secret/teslamate/config encryption_key=\"${ENCRYPTION_KEY}\""
exit 1
fi
fi
fi
# 7) Apply Teslamate config ExternalSecret
echo "Applying Teslamate config ExternalSecret..."
kubectl apply -f teslamate/external-secret.yaml
# 8) Wait for teslamate-config-secret to be created
echo "Waiting for teslamate-config-secret to be synced from Vault..."
SECRET_SYNCED=false
for i in {1..30}; do
if kubectl -n "${NS}" get secret teslamate-config-secret >/dev/null 2>&1; then
echo "✅ teslamate-config-secret synced successfully"
SECRET_SYNCED=true
break
fi
echo " waiting for secret... (attempt $i/30)"
sleep 2
done
# 9) If ESO failed to sync, create secret manually as fallback
if [ "$SECRET_SYNCED" = "false" ]; then
echo "⚠️ ExternalSecret failed to sync (ClusterSecretStore issue)"
echo "Creating teslamate-config-secret manually from Vault..."
if [ -n "$VAULT_ROOT_TOKEN" ]; then
ENCRYPTION_KEY=$(kubectl exec -n vault vault-0 -- env VAULT_TOKEN="${VAULT_ROOT_TOKEN}" vault kv get -field=encryption_key secret/teslamate/config 2>/dev/null || echo "")
if [ -n "$ENCRYPTION_KEY" ]; then
kubectl create secret generic teslamate-config-secret -n "${NS}" \
--from-literal=encryption-key="${ENCRYPTION_KEY}" \
--dry-run=client -o yaml | kubectl apply -f -
echo "✅ Created teslamate-config-secret manually"
else
echo "❌ Failed to retrieve encryption key from Vault"
exit 1
fi
else
echo "❌ Cannot create secret manually - no Vault token"
exit 1
fi
fi
echo "✅ Teslamate bootstrap complete - fully automated!"