- Phase 1: longhorn, longhorn-kafka StorageClasses (cluster-wide defaults) - Phase 2 pilot: grafana, loki, portainer, forgejo PVCs - All imports protected by lifecycle.prevent_destroy - Removes Helm annotations (meta.helm.sh/*) to prevent dual-ownership conflicts - Remote state backend (MinIO S3) syncs automatically on plan/apply - Import-only approach: zero data loss, existing volumes untouched - See terraform/LONGHORN_PVC_IMPORT.md for execution record Co-Authored-By: Claude Haiku 4.5 <[email protected]>
123 lines
4.6 KiB
Bash
Executable File
123 lines
4.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# Phase 2 Remaining Apps — Per-app PVC imports (portainer → dev-tools → loki → minio-logging → forgejo)
|
|
# Same procedure as grafana pilot; follow the pattern
|
|
|
|
set -e
|
|
cd "$(dirname "$0")/.."
|
|
|
|
echo "=== Phase 2 Remaining Apps ==="
|
|
echo "Execute per-app cycles: portainer → dev-tools → loki → minio-logging → forgejo"
|
|
echo ""
|
|
|
|
# Helper function for per-app import
|
|
import_app_pvc() {
|
|
local app=$1
|
|
local namespace=$2
|
|
local pvc_name=$3
|
|
|
|
echo "--- Importing $app PVC ---"
|
|
echo ""
|
|
|
|
# Annotate
|
|
echo "Step a) Annotate PVC with helm.sh/resource-policy=keep:"
|
|
kubectl annotate pvc "$pvc_name" -n "$namespace" helm.sh/resource-policy=keep --overwrite
|
|
echo ""
|
|
|
|
# Capture live spec
|
|
echo "Step b) Capture live PVC spec:"
|
|
kubectl get pvc "$pvc_name" -n "$namespace" -o yaml > "/tmp/${app}-pvc-live.yaml"
|
|
echo "Saved to /tmp/${app}-pvc-live.yaml"
|
|
echo ""
|
|
PV_NAME=$(kubectl get pvc "$pvc_name" -n "$namespace" -o jsonpath='{.spec.volumeName}')
|
|
echo "Bound PV: $PV_NAME"
|
|
echo "MANUAL: Update terraform/${app}.tf with correct volumeName '$PV_NAME'"
|
|
read -p "Press Enter once terraform/${app}.tf is updated: " _ || true
|
|
echo ""
|
|
|
|
# Import
|
|
echo "Step d) Import to Terraform state:"
|
|
terraform import "kubernetes_persistent_volume_claim.${app}" "${namespace}/${pvc_name}" || {
|
|
echo "ERROR: import failed for $app"
|
|
return 1
|
|
}
|
|
echo ""
|
|
|
|
# Plan
|
|
echo "Step d cont.) Verify zero diff:"
|
|
PLAN_OUTPUT=$(terraform plan 2>&1)
|
|
echo "$PLAN_OUTPUT"
|
|
if ! echo "$PLAN_OUTPUT" | grep -q "0 to add, 0 to change, 0 to destroy"; then
|
|
echo "ERROR: Plan is not clean for $app"
|
|
return 1
|
|
fi
|
|
echo "✓ Plan is clean"
|
|
echo ""
|
|
|
|
# Baseline Longhorn health
|
|
echo "Step f.1) Baseline Longhorn replica health:"
|
|
kubectl get longhorn-volume -n longhorn-system "$PV_NAME" -o json 2>/dev/null | jq '.status.replicaStatus' 2>/dev/null || echo " (unavailable)"
|
|
read -p "Press Enter to continue: " _ || true
|
|
echo ""
|
|
|
|
# Update values
|
|
echo "Step e) Update values to use existingClaim (if supported) or keep identical:"
|
|
echo "MANUAL: Verify terraform/${app}.tf resource block matches live PVC spec exactly"
|
|
echo " Update chart values (k8s/ directory) to point to existing PVC or keep identical"
|
|
read -p "Press Enter once values updated: " _ || true
|
|
echo ""
|
|
|
|
# helmfile diff
|
|
echo "Step e.2) Helmfile diff:"
|
|
cd "$(dirname "$0")/../.."
|
|
helmfile -f helmfile.yaml.gotmpl -l name="$app" diff 2>&1 | head -50 || echo " (helmfile diff unavailable)"
|
|
cd "$(dirname "$0")/../terraform"
|
|
echo ""
|
|
read -p "Confirm no destructive ops. Press Enter to continue: " _ || true
|
|
echo ""
|
|
|
|
# helmfile apply
|
|
echo "Step e.3) Helmfile apply:"
|
|
cd "$(dirname "$0")/../.."
|
|
helmfile -f helmfile.yaml.gotmpl -l name="$app" apply || echo " (helmfile apply unavailable)"
|
|
cd "$(dirname "$0")/../terraform"
|
|
echo ""
|
|
|
|
# Post-apply Longhorn health
|
|
echo "Step f.2) Post-apply Longhorn health:"
|
|
kubectl get longhorn-volume -n longhorn-system "$PV_NAME" -o json 2>/dev/null | jq '.status.replicaStatus' 2>/dev/null || echo " (unavailable)"
|
|
echo "Confirm matches baseline."
|
|
read -p "Press Enter if health is good: " _ || true
|
|
echo ""
|
|
|
|
# Final plan
|
|
echo "Step d) Final terraform plan:"
|
|
PLAN_OUTPUT=$(terraform plan 2>&1)
|
|
echo "$PLAN_OUTPUT"
|
|
if ! echo "$PLAN_OUTPUT" | grep -q "0 to add, 0 to change, 0 to destroy"; then
|
|
echo "ERROR: Plan is not clean after helmfile apply for $app"
|
|
return 1
|
|
fi
|
|
echo "✓ Plan is clean"
|
|
echo ""
|
|
echo "=== $app Complete ==="
|
|
echo ""
|
|
}
|
|
|
|
# Execute per-app imports in sequence (ascending risk)
|
|
import_app_pvc "portainer" "dashboard" "portainer" || { echo "FAILED at portainer"; exit 1; }
|
|
import_app_pvc "dev_tools" "dev-tools" "dev-tools-pvc" || { echo "FAILED at dev-tools"; exit 1; }
|
|
import_app_pvc "loki" "logging" "loki" || { echo "FAILED at loki"; exit 1; }
|
|
import_app_pvc "minio_logging" "logging" "minio" || { echo "FAILED at minio-logging"; exit 1; }
|
|
import_app_pvc "forgejo_shared_storage" "cicd" "forgejo-shared-storage" || { echo "FAILED at forgejo"; exit 1; }
|
|
|
|
echo "=== Phase 2 Remaining Apps: Complete ==="
|
|
echo "All safe apps imported successfully."
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo " 1. Conditional apps (pending Phase 0 ambiguity resolution):"
|
|
echo " - minio (storage) — if standalone chart is authoritative"
|
|
echo " - kmsvc-redis — if helmfile release is authoritative and architecture is standalone"
|
|
echo " - forgejo-runner PVCs — if Helm chart is authoritative"
|
|
echo " 2. Never import: ddb-cluster, prometheus, kafka-cluster, authentik-postgresql, llm namespace"
|
|
echo " 3. Commit all new terraform/*.tf files to git and create PR"
|