refactor: replace Dockerfile.e2e with ConfigMap volume mount for E2E plugin loading

Delete custom Docker image approach per board directive. Plugin is now
loaded into stock Headlamp via a ConfigMap volume mount:

- Delete Dockerfile.e2e
- deploy-e2e-headlamp.sh creates a ConfigMap from dist/ and mounts it
  into the stock ghcr.io/headlamp-k8s/headlamp image
- Helm values use extraVolumes/extraVolumeMounts for the ConfigMap
- No custom images, no PVCs, no kubectl exec/cp

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Gandalf the Greybeard
2026-03-20 01:01:28 +00:00
parent 8ac890a1c6
commit 4344d33349
5 changed files with 53 additions and 64 deletions
-16
View File
@@ -1,16 +0,0 @@
# Dockerfile.e2e
#
# Builds a Headlamp image with the polaris plugin pre-installed.
# Used by E2E tests — not for production distribution (use ArtifactHub).
#
# Usage:
# npm run build
# docker build -f Dockerfile.e2e -t ghcr.io/privilegedescalation/headlamp-polaris-e2e:sha-abc123 .
#
# The plugin dist/ must be built before running docker build.
ARG HEADLAMP_VERSION=latest
FROM ghcr.io/headlamp-k8s/headlamp:${HEADLAMP_VERSION}
COPY dist/ /headlamp/plugins/headlamp-polaris/
COPY package.json /headlamp/plugins/headlamp-polaris/
+1 -1
View File
@@ -6,7 +6,7 @@
# namespace to deploy and tear down a dedicated Headlamp instance via Helm. # namespace to deploy and tear down a dedicated Headlamp instance via Helm.
# #
# No kube-system access needed — E2E tests use a separate namespace. # No kube-system access needed — E2E tests use a separate namespace.
# No PVC management — plugin is baked into the Docker image. # Plugin is loaded via ConfigMap volume mount — no custom Docker images.
# #
# Prerequisites: # Prerequisites:
# kubectl create namespace headlamp-e2e # kubectl create namespace headlamp-e2e
+15 -7
View File
@@ -1,19 +1,17 @@
--- ---
# Headlamp Helm values for E2E testing. # Headlamp Helm values for E2E testing.
# #
# Uses a custom Docker image (built from Dockerfile.e2e) with the plugin # Uses the stock Headlamp image with the plugin loaded via a ConfigMap
# pre-installed. No PVCs, no volume mounts, no deployment patching. # volume mount. No custom Docker images — the plugin dist/ is packaged
# # as a ConfigMap by deploy-e2e-headlamp.sh.
# The E2E workflow builds the image, pushes to ghcr.io, and deploys this
# Helm release in the headlamp-e2e namespace.
# #
# Usage: # Usage:
# helm install headlamp-e2e headlamp/headlamp \ # helm install headlamp-e2e headlamp/headlamp \
# -n headlamp-e2e --create-namespace \ # -n headlamp-e2e --create-namespace \
# -f deployment/headlamp-e2e-values.yaml \ # -f deployment/headlamp-e2e-values.yaml \
# --set image.registry=ghcr.io \ # --set image.registry=ghcr.io \
# --set image.repository=privilegedescalation/headlamp-polaris-e2e \ # --set image.repository=headlamp-k8s/headlamp \
# --set image.tag=<sha> # --set image.tag=latest
config: config:
pluginsDir: /headlamp/plugins pluginsDir: /headlamp/plugins
@@ -21,3 +19,13 @@ config:
service: service:
type: ClusterIP type: ClusterIP
extraVolumes:
- name: polaris-plugin
configMap:
name: headlamp-polaris-plugin
extraVolumeMounts:
- name: polaris-plugin
mountPath: /headlamp/plugins/headlamp-polaris
readOnly: true
+13 -12
View File
@@ -6,15 +6,14 @@ Playwright-based smoke tests that validate the Polaris plugin against a live Hea
E2E tests run automatically in GitHub Actions on pushes to `main` and pull requests. The workflow (`.github/workflows/e2e.yaml`): E2E tests run automatically in GitHub Actions on pushes to `main` and pull requests. The workflow (`.github/workflows/e2e.yaml`):
1. Builds the plugin 1. Builds the plugin (`npm run build`)
2. Builds a custom Headlamp Docker image with the plugin pre-installed (`Dockerfile.e2e`) 2. Creates a ConfigMap from the built `dist/` output
3. Pushes the image to `ghcr.io/privilegedescalation/headlamp-polaris-e2e:<sha>` 3. Deploys a stock Headlamp instance via Helm with the plugin mounted as a ConfigMap volume
4. Deploys a dedicated Headlamp instance in the `headlamp-e2e` namespace via Helm 4. Generates a ServiceAccount token for test auth
5. Generates a ServiceAccount token for test auth 5. Runs Playwright tests against the E2E instance
6. Runs Playwright tests against the E2E instance 6. Tears down the E2E instance
7. Tears down the E2E instance
This approach avoids PVCs, kubectl exec/cp, and deployment patching. The plugin is part of the container image. This approach uses the stock `ghcr.io/headlamp-k8s/headlamp` image with no custom Docker builds. The plugin is loaded via `HEADLAMP_PLUGINS_DIR` volume mount.
### Required GitHub Secrets ### Required GitHub Secrets
@@ -27,6 +26,8 @@ Configure these in GitHub repository settings (Settings → Secrets and variable
Token-based auth is auto-generated by the deploy script. OIDC secrets are only needed if testing against the shared Headlamp instance. Token-based auth is auto-generated by the deploy script. OIDC secrets are only needed if testing against the shared Headlamp instance.
No `GHCR_TOKEN` or Docker registry secrets are needed — the stock Headlamp image is public.
## Running Locally ## Running Locally
### Option 1: OIDC via Authentik (same as CI) ### Option 1: OIDC via Authentik (same as CI)
@@ -261,13 +262,13 @@ Tests run automatically in GitHub Actions on pushes to `main` and pull requests.
The E2E workflow deploys a **dedicated Headlamp instance** for each test run: The E2E workflow deploys a **dedicated Headlamp instance** for each test run:
1. Build plugin and Docker image (`Dockerfile.e2e`) 1. Build plugin (`npm run build`)
2. Push image to `ghcr.io/privilegedescalation/headlamp-polaris-e2e:<sha>` 2. Create ConfigMap from `dist/` output (`scripts/deploy-e2e-headlamp.sh`)
3. Deploy via Helm in the `headlamp-e2e` namespace (`scripts/deploy-e2e-headlamp.sh`) 3. Deploy stock Headlamp via Helm with ConfigMap volume mount
4. Run Playwright tests against the E2E instance 4. Run Playwright tests against the E2E instance
5. Tear down (`scripts/teardown-e2e-headlamp.sh`) 5. Tear down (`scripts/teardown-e2e-headlamp.sh`)
No PVCs, no kubectl exec/cp, no patching of existing deployments. The plugin is baked into the Docker image. No custom Docker images, no PVCs, no kubectl exec/cp, no patching of existing deployments. The plugin is mounted from a ConfigMap into the stock Headlamp image.
### Cluster Prerequisites ### Cluster Prerequisites
+24 -28
View File
@@ -1,25 +1,19 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# deploy-e2e-headlamp.sh # deploy-e2e-headlamp.sh
# #
# Builds a custom Headlamp image with the polaris plugin pre-installed, # Deploys a stock Headlamp instance with the polaris plugin loaded via
# pushes it to ghcr.io, and deploys a dedicated E2E Headlamp instance. # a ConfigMap volume mount. No custom Docker images — the plugin is built
# # in CI and injected as a ConfigMap.
# This replaces the old PVC + kubectl-patch approach. The plugin is part
# of the container image — no PVCs, no kubectl exec/cp, no deployment
# patching required.
# #
# Prerequisites: # Prerequisites:
# - Plugin built (dist/ exists) # - Plugin built (dist/ exists with plugin-main.js + package.json)
# - Docker or buildx available
# - GHCR_TOKEN set (or GH_TOKEN with packages:write)
# - kubectl configured with cluster access # - kubectl configured with cluster access
# - Helm 3 installed # - Helm 3 installed
# #
# Environment: # Environment:
# E2E_NAMESPACE — namespace for E2E Headlamp (default: headlamp-e2e) # E2E_NAMESPACE — namespace for E2E Headlamp (default: headlamp-e2e)
# E2E_RELEASE — Helm release name (default: headlamp-e2e) # E2E_RELEASE — Helm release name (default: headlamp-e2e)
# HEADLAMP_VERSION — base Headlamp image tag (default: latest) # HEADLAMP_VERSION — Headlamp image tag (default: latest)
# IMAGE_TAG — tag for the E2E image (default: git SHA)
set -euo pipefail set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
@@ -28,9 +22,6 @@ DIST_DIR="$REPO_ROOT/dist"
E2E_NAMESPACE="${E2E_NAMESPACE:-headlamp-e2e}" E2E_NAMESPACE="${E2E_NAMESPACE:-headlamp-e2e}"
E2E_RELEASE="${E2E_RELEASE:-headlamp-e2e}" E2E_RELEASE="${E2E_RELEASE:-headlamp-e2e}"
HEADLAMP_VERSION="${HEADLAMP_VERSION:-latest}" HEADLAMP_VERSION="${HEADLAMP_VERSION:-latest}"
IMAGE_REPO="ghcr.io/privilegedescalation/headlamp-polaris-e2e"
IMAGE_TAG="${IMAGE_TAG:-$(git -C "$REPO_ROOT" rev-parse --short HEAD)}"
IMAGE="${IMAGE_REPO}:${IMAGE_TAG}"
if [ ! -d "$DIST_DIR" ]; then if [ ! -d "$DIST_DIR" ]; then
echo "ERROR: dist/ not found. Run 'npm run build' first." >&2 echo "ERROR: dist/ not found. Run 'npm run build' first." >&2
@@ -38,20 +29,28 @@ if [ ! -d "$DIST_DIR" ]; then
fi fi
echo "=== E2E Headlamp Deployment ===" echo "=== E2E Headlamp Deployment ==="
echo " Image: $IMAGE" echo " Image: ghcr.io/headlamp-k8s/headlamp:${HEADLAMP_VERSION}"
echo " Namespace: $E2E_NAMESPACE" echo " Namespace: $E2E_NAMESPACE"
echo " Release: $E2E_RELEASE" echo " Release: $E2E_RELEASE"
# --- Build and push the custom image --- # --- Create namespace ---
echo "" echo ""
echo "Building E2E Headlamp image..." echo "Creating namespace ${E2E_NAMESPACE} (if needed)..."
docker build -f "$REPO_ROOT/Dockerfile.e2e" \ kubectl create namespace "$E2E_NAMESPACE" --dry-run=client -o yaml | kubectl apply -f -
--build-arg "HEADLAMP_VERSION=${HEADLAMP_VERSION}" \
-t "$IMAGE" \
"$REPO_ROOT"
echo "Pushing image to ghcr.io..." # --- Create ConfigMap from built plugin ---
docker push "$IMAGE" echo ""
echo "Creating ConfigMap with plugin files..."
# Delete existing ConfigMap if present (idempotent redeploy)
kubectl delete configmap headlamp-polaris-plugin \
-n "$E2E_NAMESPACE" --ignore-not-found
# Create ConfigMap from dist/ contents and package.json
kubectl create configmap headlamp-polaris-plugin \
-n "$E2E_NAMESPACE" \
--from-file="$DIST_DIR" \
--from-file=package.json="$REPO_ROOT/package.json"
# --- Deploy with Helm --- # --- Deploy with Helm ---
echo "" echo ""
@@ -59,16 +58,13 @@ echo "Adding Headlamp Helm repo..."
helm repo add headlamp https://headlamp-k8s.github.io/headlamp/ --force-update helm repo add headlamp https://headlamp-k8s.github.io/headlamp/ --force-update
helm repo update helm repo update
echo "Creating namespace ${E2E_NAMESPACE} (if needed)..."
kubectl create namespace "$E2E_NAMESPACE" --dry-run=client -o yaml | kubectl apply -f -
echo "Installing/upgrading Headlamp E2E instance..." echo "Installing/upgrading Headlamp E2E instance..."
helm upgrade --install "$E2E_RELEASE" headlamp/headlamp \ helm upgrade --install "$E2E_RELEASE" headlamp/headlamp \
-n "$E2E_NAMESPACE" \ -n "$E2E_NAMESPACE" \
-f "$REPO_ROOT/deployment/headlamp-e2e-values.yaml" \ -f "$REPO_ROOT/deployment/headlamp-e2e-values.yaml" \
--set "image.registry=ghcr.io" \ --set "image.registry=ghcr.io" \
--set "image.repository=privilegedescalation/headlamp-polaris-e2e" \ --set "image.repository=headlamp-k8s/headlamp" \
--set "image.tag=${IMAGE_TAG}" \ --set "image.tag=${HEADLAMP_VERSION}" \
--wait \ --wait \
--timeout 120s --timeout 120s