Compare commits

..

4 Commits

Author SHA1 Message Date
Chris Farhood 2d9c447467 fix(e2e): keep ServiceAccount across deploy cycles to avoid token fetch race
The deploy script was deleting serviceaccount/headlamp-e2e before recreating
it via kubectl apply. This causes a race: the new deployment pod tries to
mount its service account token before the token is available, resulting in:

    Warning FailedMount: failed to fetch token: serviceaccounts "headlamp-e2e" not found

Fix by removing the kubectl delete serviceaccount line and replacing it with
an idempotent create (--dry-run=client | kubectl apply). This ensures the
ServiceAccount persists across deploy cycles and tokens are available when
pods start.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-05 15:35:48 +00:00
Chris Farhood 191d2edc55 Migrate to reusable plugin-e2e.yaml workflow (PRI-634) 2026-05-05 10:56:47 +00:00
privilegedescalation-engineer[bot] c7920b5b8e fix(e2e): use headlamp-dev namespace in E2E workflow (PRI-550) (#61)
* fix(e2e): use headlamp-dev namespace in E2E workflow (PRI-550)

The infra RBAC in privilegedescalation/infra already covers headlamp-dev
with all needed E2E permissions. Changing the workflow to use headlamp-dev
unblocks E2E since the Arc Runners SA is already authorized there.

Depends on Gandalf's PR #58 for namespace corrections in scripts and RBAC
manifest.

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* chore: re-trigger E2E with headlamp-dev namespace (PRI-550)

* chore: re-run CI/E2E checks (PRI-550)

Co-Authored-By: Paperclip <noreply@paperclip.ing>

---------

Co-authored-by: Chris Farhood <chris@farhood.org>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-05-05 10:18:47 +00:00
privilegedescalation-engineer[bot] c99e235caa fix(e2e): remove Service delete to fix Endpoints UID race causing ERR_NAME_NOT_RESOLVED
Merged via CEO gate after full pipeline approval: CI  E2E  UAT  QA  CTO 
2026-05-05 05:10:33 +00:00
6 changed files with 23 additions and 12059 deletions
+4 -85
View File
@@ -10,94 +10,13 @@ on:
permissions:
contents: read
# Only one E2E run at a time: the shared E2E_RELEASE (headlamp-e2e) in
# privilegedescalation-dev cannot be shared across concurrent runs.
# cancel-in-progress: false (queue, don't cancel) — cancelling in-flight
# runs may skip the if: always() teardown, leaving dangling cluster resources.
concurrency:
group: e2e-${{ github.repository }}
cancel-in-progress: false
env:
E2E_NAMESPACE: privilegedescalation-dev
E2E_RELEASE: headlamp-e2e
# Pin to a known-good Headlamp version. Using :latest is risky because
# the tag can change between CI runs, causing flaky failures when a newer
# image is pulled on some nodes but not others (IfNotPresent pull policy).
# Update this when Headlamp is upgraded in production (kube-system).
HEADLAMP_VERSION: v0.40.1
jobs:
e2e:
runs-on: runners-privilegedescalation
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'
- name: Setup kubectl
uses: azure/setup-kubectl@v4
- name: Install dependencies
run: npm ci
- name: Build plugin
run: npx @kinvolk/headlamp-plugin build
- name: Deploy E2E Headlamp instance
run: scripts/deploy-e2e-headlamp.sh
- name: Load E2E environment
run: |
if [ -f .env.e2e ]; then
cat .env.e2e >> "$GITHUB_ENV"
else
echo "::error::deploy-e2e-headlamp.sh did not produce .env.e2e"
exit 1
fi
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Run E2E tests
run: npm run e2e
env:
HEADLAMP_URL: ${{ env.HEADLAMP_URL }}
HEADLAMP_TOKEN: ${{ env.HEADLAMP_TOKEN }}
- name: Collect deployment diagnostics on failure
if: failure()
run: |
echo "=== Pod state ==="
kubectl get pods -n "$E2E_NAMESPACE" -l "app.kubernetes.io/instance=$E2E_RELEASE" 2>&1 || true
echo "=== Pod describe ==="
kubectl describe pods -n "$E2E_NAMESPACE" -l "app.kubernetes.io/instance=$E2E_RELEASE" 2>&1 || true
echo "=== Recent namespace events ==="
kubectl get events -n "$E2E_NAMESPACE" --sort-by='.lastTimestamp' 2>&1 | tail -20 || true
- name: Teardown E2E instance
if: always()
run: scripts/teardown-e2e-headlamp.sh
- name: Upload Playwright report
uses: actions/upload-artifact@v7
if: failure()
with:
name: playwright-report
path: playwright-report/
retention-days: 7
- name: Upload test results
uses: actions/upload-artifact@v7
if: failure()
with:
name: test-results
path: test-results/
retention-days: 7
uses: privilegedescalation/.github/.github/workflows/plugin-e2e.yaml@main
with:
node-version: "22"
headlamp-version: v0.40.1
-12
View File
@@ -1,12 +0,0 @@
---
# RBAC for the GitHub Actions CI runner to manage E2E Headlamp instances.
# CI-only test fixture — NOT for production use.
#
# This file is a REFERENCE ONLY. The canonical manifest lives in:
# privilegedescalation/infra/base/rbac/e2e-ci-runner-headlamp-rbac.yaml
#
# The infra repo is managed by Flux GitOps and is the source of truth.
# Do not apply this file directly — it is kept here for developer reference only.
#
# E2E resources run in `privilegedescalation-dev` — nothing persists beyond a test run.
# RBAC is managed via Flux from privilegedescalation/infra — do not apply manually.
-3
View File
@@ -36,13 +36,10 @@
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.5.2",
"eslint": "^8.57.1",
"jsdom": "^24.0.0",
"prettier": "^3.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^5.3.0",
"typescript": "^5.6.2",
"vitest": "^3.0.5"
},
"overrides": {
-11945
View File
File diff suppressed because it is too large Load Diff
+17 -9
View File
@@ -5,18 +5,16 @@
# a ConfigMap volume mount. No custom Docker images — the plugin is built
# in CI and injected as a ConfigMap.
#
# E2E resources are deployed to the `headlamp-plugins-e2e` namespace. Nothing
# E2E resources are deployed to the `headlamp-dev` namespace. Nothing
# persists beyond the test run — teardown cleans up all created resources.
#
# Prerequisites:
# - Plugin built (dist/ exists with plugin-main.js + package.json)
# - kubectl configured with cluster access
# RBAC is managed via Flux from privilegedescalation/infra/base/rbac/e2e-ci-runner-headlamp-rbac.yaml.
# The infra repo is the source of truth — do not apply this file directly.
# Apply RBAC first: kubectl apply -f privilegedescalation/infra/base/rbac/e2e-ci-runner-headlamp-rbac.yaml
# - RBAC applied: kubectl apply -f deployment/e2e-ci-runner-rbac.yaml
#
# Environment:
# E2E_NAMESPACE — namespace for E2E Headlamp (default: headlamp-plugins-e2e)
# E2E_NAMESPACE — namespace for E2E Headlamp (default: headlamp-dev)
# E2E_RELEASE — release/resource name prefix (default: headlamp-e2e)
# HEADLAMP_VERSION — Headlamp image tag (default: latest)
set -euo pipefail
@@ -24,7 +22,7 @@ set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
DIST_DIR="$REPO_ROOT/dist"
E2E_NAMESPACE="${E2E_NAMESPACE:-headlamp-plugins-e2e}"
E2E_NAMESPACE="${E2E_NAMESPACE:-headlamp-dev}"
E2E_RELEASE="${E2E_RELEASE:-headlamp-e2e}"
HEADLAMP_VERSION="${HEADLAMP_VERSION:-latest}"
@@ -37,7 +35,7 @@ fi
echo "Checking RBAC permissions in namespace '${E2E_NAMESPACE}'..."
if ! kubectl auth can-i delete configmaps -n "$E2E_NAMESPACE" --quiet 2>/dev/null; then
echo "ERROR: Missing RBAC — cannot delete configmaps in namespace '${E2E_NAMESPACE}'." >&2
echo " Apply RBAC first: kubectl apply -f privilegedescalation/infra/base/rbac/e2e-ci-runner-headlamp-rbac.yaml" >&2
echo " Apply RBAC first: kubectl apply -f deployment/e2e-ci-runner-rbac.yaml" >&2
exit 1
fi
@@ -61,11 +59,21 @@ kubectl create configmap headlamp-intel-gpu-plugin \
--from-file=package.json="$REPO_ROOT/package.json"
# --- Tear down any existing E2E deployment for a clean start ---
# Deleting the Deployment forces a fresh pod (new ReplicaSet) regardless of
# whether the pod spec changed. We do NOT delete the ServiceAccount — keeping
# it avoids a token-race condition where kubelet tries to mount a volume using a
# token that has been deleted but the new one isn't ready yet.
# The Service is NOT deleted — leaving it in place avoids an
# Endpoints UID race (FailedToUpdateEndpoint) that causes DNS resolution
# failures. kubectl apply below upserts the Service in-place, and the new
# pod's IP is added to the existing Endpoints automatically.
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
# ServiceAccount is kept — create it idempotently so the first run works too
kubectl create serviceaccount "${E2E_RELEASE}" \
-n "$E2E_NAMESPACE" \
--dry-run=client -o yaml | kubectl apply -f -
# --- Deploy Headlamp via kubectl apply ---
echo ""
+2 -5
View File
@@ -3,17 +3,14 @@
#
# Tears down the dedicated E2E Headlamp instance deployed by deploy-e2e-headlamp.sh.
#
# RBAC is managed via Flux from privilegedescalation/infra/base/rbac/e2e-ci-runner-headlamp-rbac.yaml.
# The infra repo is the source of truth — do not apply this file directly.
#
# Environment:
# E2E_NAMESPACE — namespace to clean up (default: headlamp-plugins-e2e)
# E2E_NAMESPACE — namespace to clean up (default: headlamp-dev)
# E2E_RELEASE — release/resource name prefix (default: headlamp-e2e)
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
E2E_NAMESPACE="${E2E_NAMESPACE:-headlamp-plugins-e2e}"
E2E_NAMESPACE="${E2E_NAMESPACE:-headlamp-dev}"
E2E_RELEASE="${E2E_RELEASE:-headlamp-e2e}"
echo "=== E2E Headlamp Teardown ==="