#!/usr/bin/env bash set -euo pipefail REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" DIST_DIR="$REPO_ROOT/dist" E2E_NAMESPACE="${E2E_NAMESPACE:-headlamp-dev}" E2E_RELEASE="${E2E_RELEASE:-headlamp-e2e-argocd}" HEADLAMP_VERSION="${HEADLAMP_VERSION:-v0.40.1}" if [ ! -d "$DIST_DIR" ]; then echo "ERROR: dist/ not found. Run 'npm run build' first." >&2 exit 1 fi echo "Checking RBAC permissions in namespace '${E2E_NAMESPACE}'..." REQUIRED_PERMS=( "create configmaps" "delete configmaps" "get configmaps" "create serviceaccounts" "delete serviceaccounts" "get serviceaccounts" "create deployments" "get deployments" "list pods" "get pods" "create services" "get services" "delete services" "create pods/exec" "create token" ) FAILED="" for perm in "${REQUIRED_PERMS[@]}"; do if ! kubectl auth can-i "$perm" -n "$E2E_NAMESPACE" --quiet 2>/dev/null; then echo "ERROR: Missing RBAC — ${perm} in namespace '${E2E_NAMESPACE}'." >&2 FAILED="$perm" break fi done if [ -n "$FAILED" ]; then echo "ERROR: Missing required RBAC permission: ${FAILED}" >&2 echo "Hub operator needs to grant this permission to the workflow's service account in namespace ${E2E_NAMESPACE}." >&2 exit 1 fi echo "RBAC check passed." echo "=== E2E Headlamp Deployment ===" echo " Image: ghcr.io/headlamp-k8s/headlamp:${HEADLAMP_VERSION}" echo " Namespace: $E2E_NAMESPACE" echo " Release: $E2E_RELEASE" echo "" echo "Creating ConfigMap with plugin files..." kubectl delete configmap headlamp-argocd-plugin \ -n "$E2E_NAMESPACE" --ignore-not-found kubectl create configmap headlamp-argocd-plugin \ -n "$E2E_NAMESPACE" \ --from-file="$DIST_DIR" \ --from-file=package.json="$REPO_ROOT/package.json" echo "" echo "Removing any existing E2E deployment (clean-start)..." kubectl delete deployment "${E2E_RELEASE}" -n "$E2E_NAMESPACE" --ignore-not-found --wait kubectl delete service "${E2E_RELEASE}" -n "$E2E_NAMESPACE" --ignore-not-found --wait kubectl delete serviceaccount "${E2E_RELEASE}" -n "$E2E_NAMESPACE" --ignore-not-found --wait echo "" echo "Deploying Headlamp E2E instance..." kubectl apply -f - <&1; then echo "=== Rollout failed. Dumping diagnostics ===" >&2 echo "=== Pods ===" >&2 kubectl get pods -n "$E2E_NAMESPACE" -l "app.kubernetes.io/instance=${E2E_RELEASE}" 2>&1 || true echo "=== Pod events ===" >&2 kubectl describe pods -n "$E2E_NAMESPACE" -l "app.kubernetes.io/instance=${E2E_RELEASE}" 2>&1 | tail -30 || true echo "=== Namespace events ===" >&2 kubectl get events -n "$E2E_NAMESPACE" --sort-by='.lastTimestamp' 2>&1 | tail -20 || true exit 1 fi SVC_URL="http://${E2E_RELEASE}.${E2E_NAMESPACE}.svc.cluster.local" echo "" echo "Waiting for ${SVC_URL} to be reachable..." ATTEMPTS=0 MAX_ATTEMPTS=24 until curl -sf --max-time 5 "${SVC_URL}" -o /dev/null 2>/dev/null; do ATTEMPTS=$((ATTEMPTS + 1)) if [ "$ATTEMPTS" -ge "$MAX_ATTEMPTS" ]; then echo "" echo "=== Service unreachable after $((MAX_ATTEMPTS * 5))s. Dumping diagnostics ===" >&2 echo "=== Pod state ===" >&2 kubectl get pods -n "$E2E_NAMESPACE" -l "app.kubernetes.io/instance=${E2E_RELEASE}" 2>&1 || true echo "=== Pod logs ===" >&2 kubectl logs -n "$E2E_NAMESPACE" -l "app.kubernetes.io/instance=${E2E_RELEASE}" --tail=50 2>&1 || true echo "=== Namespace events ===" >&2 kubectl get events -n "$E2E_NAMESPACE" --sort-by='.lastTimestamp' 2>&1 | tail -20 || true echo "ERROR: ${SVC_URL} not reachable after $((MAX_ATTEMPTS * 5))s" >&2 exit 1 fi echo " [${ATTEMPTS}/${MAX_ATTEMPTS}] not yet reachable, retrying in 5s..." sleep 5 done echo "" echo "E2E Headlamp is ready at: ${SVC_URL}" echo "" echo "Creating service account token for E2E auth..." kubectl create serviceaccount headlamp-e2e-test \ -n "$E2E_NAMESPACE" --dry-run=client -o yaml | kubectl apply -f - TOKEN=$(kubectl create token headlamp-e2e-test -n "$E2E_NAMESPACE" --duration=1h 2>/dev/null || echo "") if [ -n "$TOKEN" ]; then echo "HEADLAMP_URL=${SVC_URL}" > "$REPO_ROOT/.env.e2e" echo "HEADLAMP_TOKEN=${TOKEN}" >> "$REPO_ROOT/.env.e2e" echo "Wrote .env.e2e with HEADLAMP_URL and HEADLAMP_TOKEN" else echo " WARNING: Could not generate token." fi echo "" echo "E2E deployment complete."