From 8501f06a56075dac65ab400cf192df03039da707 Mon Sep 17 00:00:00 2001 From: Hugh Hackman Date: Mon, 16 Mar 2026 15:15:43 +0000 Subject: [PATCH 1/2] ci: update e2e workflow for shared volume plugin deployment Replace the old preflight-only approach with a build-and-deploy flow that uses a shared volume (hostPath) between the CI runner and the Headlamp pod. The workflow now builds the plugin from source, copies the artifact to a shared volume path, and optionally calls Gandalf's deploy script for Headlamp rollout coordination. Removes kubectl exec/cp references and version-match preflight in favor of deploying the PR's actual build artifact. Refs: PRI-216, PRI-195 Co-Authored-By: Paperclip --- .github/workflows/e2e.yaml | 78 ++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 9685c69..659e50f 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -7,6 +7,11 @@ on: branches: [main] workflow_dispatch: +env: + SHARED_VOLUME_PATH: /shared/headlamp-plugins + HEADLAMP_NAMESPACE: kube-system + HEADLAMP_RELEASE: headlamp + jobs: e2e: runs-on: local-ubuntu-latest @@ -25,46 +30,77 @@ jobs: - name: Install dependencies run: npm ci - - name: Preflight — verify Headlamp and plugin version + - name: Build plugin + run: npm run build + + - name: Deploy plugin via shared volume env: HEADLAMP_URL: ${{ secrets.HEADLAMP_URL || 'http://headlamp.kube-system.svc.cluster.local' }} run: | - EXPECTED=$(node -p "require('./package.json').version") - PLUGIN_NAME=$(node -p "require('./package.json').artifacthub?.name || require('./package.json').name") - echo "Expected: $PLUGIN_NAME@$EXPECTED" + PLUGIN_NAME=$(node -p "require('./package.json').name") + PLUGIN_DIR="$SHARED_VOLUME_PATH/$PLUGIN_NAME" + + echo "Deploying $PLUGIN_NAME to shared volume at $SHARED_VOLUME_PATH" + + # Ensure shared volume directory exists + mkdir -p "$SHARED_VOLUME_PATH" + + # Remove stale plugin if present, then copy fresh build + rm -rf "$PLUGIN_DIR" + cp -r dist "$PLUGIN_DIR" + + # Copy package.json for version identification + cp package.json "$PLUGIN_DIR/package.json" + + echo "Plugin deployed to $PLUGIN_DIR" + ls -la "$PLUGIN_DIR" + + # If Gandalf's deploy script exists, use it for Headlamp rollout + if [ -x scripts/deploy-plugin-via-volume.sh ]; then + echo "Running deploy script..." + scripts/deploy-plugin-via-volume.sh + else + echo "::warning::deploy-plugin-via-volume.sh not found — relying on pre-configured shared volume mount" + fi + + - name: Preflight — verify Headlamp and plugin availability + env: + HEADLAMP_URL: ${{ secrets.HEADLAMP_URL || 'http://headlamp.kube-system.svc.cluster.local' }} + run: | + PLUGIN_NAME=$(node -p "require('./package.json').name") + EXPECTED=$(node -p "require('./package.json').version") + echo "Expecting: $PLUGIN_NAME@$EXPECTED" + + # Wait for Headlamp to be reachable + for i in $(seq 1 30); do + HTTP_CODE=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 5 "$HEADLAMP_URL" || true) + if [ "$HTTP_CODE" != "000" ]; then + echo "Headlamp responded HTTP $HTTP_CODE" + break + fi + echo "Waiting for Headlamp... ($i/30)" + sleep 2 + done - # Check Headlamp connectivity - HTTP_CODE=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 10 "$HEADLAMP_URL" || true) if [ "$HTTP_CODE" = "000" ]; then - echo "::error::Cannot reach Headlamp at $HEADLAMP_URL" + echo "::error::Cannot reach Headlamp at $HEADLAMP_URL after 60s" exit 1 fi - echo "Headlamp responded HTTP $HTTP_CODE" - # Check installed plugins and version match + # Verify plugin is visible PLUGIN_JSON=$(curl -sf --connect-timeout 10 "$HEADLAMP_URL/plugins" 2>/dev/null || echo "[]") node -e " - const expected = '$EXPECTED'; - const pluginName = '$PLUGIN_NAME'; const plugins = JSON.parse(process.argv[1]); console.log('Installed plugins:'); for (const p of plugins) console.log(' ' + p.name + '@' + (p.version||'unknown')); - const ours = plugins.find(p => p.name === pluginName || p.name === 'polaris' || p.name.includes('polaris')); + const ours = plugins.find(p => p.name === '$PLUGIN_NAME' || p.name === 'polaris' || p.name.includes('polaris')); if (!ours) { - console.log('::warning::Plugin ' + pluginName + ' not found in Headlamp — data-dependent tests will fail'); + console.log('::warning::Plugin $PLUGIN_NAME not yet visible — Headlamp may need a restart'); } else { console.log('Found plugin: ' + ours.name + ' at path ' + ours.path); } " "$PLUGIN_JSON" - # Fetch deployed plugin version from package.json - DEPLOYED_VERSION=$(curl -sf --connect-timeout 10 "$HEADLAMP_URL/plugins/$PLUGIN_NAME/package.json" 2>/dev/null \ - | node -p "JSON.parse(require('fs').readFileSync(0,'utf8')).version" 2>/dev/null || echo "unknown") - echo "Deployed version: $DEPLOYED_VERSION" - if [ "$DEPLOYED_VERSION" != "$EXPECTED" ] && [ "$DEPLOYED_VERSION" != "unknown" ]; then - echo "::warning::Version mismatch — repo has $EXPECTED but Headlamp runs $DEPLOYED_VERSION. Tests may fail due to stale plugin." - fi - - name: Install Playwright browsers run: npx playwright install --with-deps chromium -- 2.52.0 From 06386e445b4400913007fbb24a69ea9cfa5ea27a Mon Sep 17 00:00:00 2001 From: Hugh Hackman Date: Mon, 16 Mar 2026 19:21:45 +0000 Subject: [PATCH 2/2] ci: align e2e workflow with Gandalf's deploy script interface Simplify deploy step to call scripts/deploy-plugin-via-volume.sh directly instead of duplicating copy logic. Align env var names (PLUGIN_VOLUME_PATH, HEADLAMP_DEPLOY) with the deploy script's expected interface from PR #59. Co-Authored-By: Paperclip --- .github/workflows/e2e.yaml | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 659e50f..271cd0c 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -8,9 +8,9 @@ on: workflow_dispatch: env: - SHARED_VOLUME_PATH: /shared/headlamp-plugins + PLUGIN_VOLUME_PATH: /mnt/headlamp-plugins HEADLAMP_NAMESPACE: kube-system - HEADLAMP_RELEASE: headlamp + HEADLAMP_DEPLOY: headlamp jobs: e2e: @@ -34,34 +34,7 @@ jobs: run: npm run build - name: Deploy plugin via shared volume - env: - HEADLAMP_URL: ${{ secrets.HEADLAMP_URL || 'http://headlamp.kube-system.svc.cluster.local' }} - run: | - PLUGIN_NAME=$(node -p "require('./package.json').name") - PLUGIN_DIR="$SHARED_VOLUME_PATH/$PLUGIN_NAME" - - echo "Deploying $PLUGIN_NAME to shared volume at $SHARED_VOLUME_PATH" - - # Ensure shared volume directory exists - mkdir -p "$SHARED_VOLUME_PATH" - - # Remove stale plugin if present, then copy fresh build - rm -rf "$PLUGIN_DIR" - cp -r dist "$PLUGIN_DIR" - - # Copy package.json for version identification - cp package.json "$PLUGIN_DIR/package.json" - - echo "Plugin deployed to $PLUGIN_DIR" - ls -la "$PLUGIN_DIR" - - # If Gandalf's deploy script exists, use it for Headlamp rollout - if [ -x scripts/deploy-plugin-via-volume.sh ]; then - echo "Running deploy script..." - scripts/deploy-plugin-via-volume.sh - else - echo "::warning::deploy-plugin-via-volume.sh not found — relying on pre-configured shared volume mount" - fi + run: scripts/deploy-plugin-via-volume.sh - name: Preflight — verify Headlamp and plugin availability env: -- 2.52.0