Skip to content

vCluster E2E Nightly (Ginkgo) #43

vCluster E2E Nightly (Ginkgo)

vCluster E2E Nightly (Ginkgo) #43

name: vCluster E2E Nightly (Ginkgo)
on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
inputs:
notify:
description: "Send Slack notifications"
type: boolean
default: true
ginkgo-label:
description: 'Ginkgo label filter. Defaults to empty (all tests).'
type: string
default: ""
concurrency:
group: e2e-ginkgo-nightly-${{ github.ref_name }}
cancel-in-progress: false
permissions:
contents: read
pull-requests: read
env:
REPOSITORY_NAME: ghcr.io/loft-sh/vcluster
TAG_NAME: dev-next
jobs:
e2e-tests:
name: Run Ginkgo E2E Tests
if: github.repository_owner == 'loft-sh'
runs-on: large-8_32
timeout-minutes: 180
steps:
- name: Free disk space
uses: jlumbroso/free-disk-space@v1.3.1
with:
tool-cache: false
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- run: git fetch --force --tags
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache: false
- name: Setup GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
install-only: true
version: latest
- name: Setup Helm
uses: azure/setup-helm@v4
with:
version: "v3.19.0"
- name: Build vcluster image and CLI
run: |
set -x
TELEMETRY_PRIVATE_KEY="" goreleaser build \
--single-target --snapshot --id vcluster --clean --output ./vcluster
docker build \
-t "${{ env.REPOSITORY_NAME }}:${{ env.TAG_NAME }}" \
-f Dockerfile.release \
--build-arg TARGETARCH=amd64 \
--build-arg TARGETOS=linux .
docker image ls
TELEMETRY_PRIVATE_KEY="" goreleaser build \
--single-target --snapshot --id vcluster-cli --clean --output ./vcluster
- name: Install Ginkgo CLI
run: |
cd e2e-next
go install github.com/onsi/ginkgo/v2/ginkgo
- name: Set up vCluster CLI in GOBIN
run: |
GOBIN=$(go env GOPATH)/bin
mkdir -p "$GOBIN"
chmod +x vcluster
cp vcluster "$GOBIN/vcluster"
echo "GOBIN=$GOBIN" >> "$GITHUB_ENV"
- name: Ensure bridge netfilter modules are loaded
run: |
if [[ ! -f /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then
sudo modprobe -va bridge br_netfilter
echo "Enabled bridge netfilter modules successfully"
else
echo "Bridge netfilter modules are already enabled"
fi
- name: Run e2e-next tests
run: |
LABEL_FILTER="${{ inputs.ginkgo-label }}"
ginkgo \
-v \
--procs=8 \
--timeout=0 \
--poll-progress-after=20s \
--poll-progress-interval=10s \
--label-filter="${LABEL_FILTER}" \
./e2e-next -- \
--vcluster-image="${{ env.REPOSITORY_NAME }}:${{ env.TAG_NAME }}" \
--teardown=false
- name: Collect debug info on failure
if: failure()
run: |
set +e
echo "=== All pods ==="
kubectl get pods -A
echo ""
echo "=== vCluster instances ==="
for NS in $(kubectl get pods -A -l app=vcluster \
-o jsonpath='{range .items[*]}{.metadata.namespace}{"\n"}{end}' 2>/dev/null | sort -u); do
echo ""
echo "--- vCluster namespace: $NS ---"
NOT_READY=$(kubectl get pods -n "$NS" -l app=vcluster \
-o jsonpath='{range .items[*]}{range .status.conditions[?(@.type=="Ready")]}{.status}{"\n"}{end}{end}' \
2>/dev/null | grep -c "^False$" || true)
if [ "$NOT_READY" -gt 0 ]; then
echo "Pods NOT ready — describing:"
kubectl describe pods -n "$NS" -l app=vcluster || true
echo ""
kubectl get events -n "$NS" --sort-by='.lastTimestamp' || true
echo ""
echo "Syncer logs (current):"
kubectl logs -n "$NS" -l app=vcluster -c syncer --tail=500 2>/dev/null || \
kubectl logs -n "$NS" -l app=vcluster --tail=500 2>/dev/null || true
echo ""
echo "Syncer logs (previous):"
kubectl logs -n "$NS" -l app=vcluster -c syncer --previous --tail=200 2>/dev/null || true
else
echo "Pods ready — collecting syncer logs:"
kubectl logs -n "$NS" -l app=vcluster -c syncer --tail=500 2>/dev/null || \
kubectl logs -n "$NS" -l app=vcluster --tail=500 2>/dev/null || true
fi
done
notify:
name: Send Slack Notifications
if: always() && github.repository_owner == 'loft-sh' && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.notify))
needs: [e2e-tests]
runs-on: ubuntu-22.04
steps:
- name: Determine workflow status
id: status
run: |
if [[ "${{ needs.e2e-tests.result }}" == "failure" ]]; then
{
echo "workflow_failed=true"
echo "status_emoji=❌"
echo "status_text=Failed"
} >> "$GITHUB_OUTPUT"
elif [[ "${{ needs.e2e-tests.result }}" == "success" ]]; then
{
echo "workflow_failed=false"
echo "status_emoji=✅"
echo "status_text=Passed"
} >> "$GITHUB_OUTPUT"
else
{
echo "workflow_failed=true"
echo "status_emoji=⚠️"
echo "status_text=Cancelled or Skipped"
} >> "$GITHUB_OUTPUT"
fi
- name: Notify ci-tests-alerts (Success)
if: steps.status.outputs.workflow_failed == 'false'
uses: slackapi/slack-github-action@v2.1.1
with:
payload: |
{
"text": "${{ steps.status.outputs.status_emoji }} vCluster E2E Nightly ${{ steps.status.outputs.status_text }}",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "${{ steps.status.outputs.status_emoji }} vCluster E2E Nightly ${{ steps.status.outputs.status_text }}"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Build URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n\nE2E Tests: ${{ needs.e2e-tests.result }}"
}
}
]
}
webhook: ${{ secrets.SLACK_WEBHOOK_URL_CI_TESTS_ALERTS }}
webhook-type: incoming-webhook
- name: Notify ci-tests-alerts (Failure)
if: steps.status.outputs.workflow_failed == 'true'
uses: slackapi/slack-github-action@v2.1.1
with:
payload: |
{
"text": "${{ steps.status.outputs.status_emoji }} vCluster E2E Nightly ${{ steps.status.outputs.status_text }}",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "${{ steps.status.outputs.status_emoji }} vCluster E2E Nightly ${{ steps.status.outputs.status_text }}"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Build URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n\nE2E Tests: ${{ needs.e2e-tests.result }}"
}
}
]
}
webhook: ${{ secrets.SLACK_WEBHOOK_URL_CI_TESTS_ALERTS }}
webhook-type: incoming-webhook
- name: Notify dev-vcluster (Failure)
if: steps.status.outputs.workflow_failed == 'true'
uses: slackapi/slack-github-action@v2.1.1
with:
payload: |
{
"text": "${{ steps.status.outputs.status_emoji }} vCluster E2E Nightly ${{ steps.status.outputs.status_text }}",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "${{ steps.status.outputs.status_emoji }} vCluster E2E Nightly ${{ steps.status.outputs.status_text }}"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Build URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n\nE2E Tests: ${{ needs.e2e-tests.result }}"
}
}
]
}
webhook: ${{ secrets.SLACK_WEBHOOK_URL_DEV_VCLUSTER }}
webhook-type: incoming-webhook