fix: refactor PR Validation workflow to use Replicated actions #138
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| name: WG-Easy PR Validation - build, release, install | |
| on: | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - 'applications/wg-easy/**' | |
| - '.github/workflows/wg-easy-pr-validation.yaml' | |
| workflow_dispatch: | |
| inputs: | |
| test_mode: | |
| description: 'Run in test mode' | |
| required: false | |
| default: 'true' | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| APP_DIR: applications/wg-easy | |
| REPLICATED_API_TOKEN: ${{ secrets.WG_EASY_REPLICATED_API_TOKEN }} | |
| REPLICATED_APP: ${{ vars.WG_EASY_REPLICATED_APP }} | |
| HELM_VERSION: "3.17.3" | |
| KUBECTL_VERSION: "v1.30.0" | |
| jobs: | |
| setup: | |
| runs-on: ubuntu-22.04 | |
| outputs: | |
| branch-name: ${{ steps.vars.outputs.branch-name }} | |
| channel-name: ${{ steps.vars.outputs.channel-name }} | |
| customer-name: ${{ steps.vars.outputs.customer-name }} | |
| steps: | |
| - name: Set branch and channel variables | |
| id: vars | |
| run: | | |
| # Branch name preserves original case for resource naming (clusters, customers) | |
| BRANCH_NAME="${{ github.head_ref || github.ref_name }}" | |
| # Channel name is normalized to lowercase with hyphens for Replicated channels | |
| CHANNEL_NAME=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | tr '/' '-') | |
| # Customer name includes run number to ensure uniqueness across workflow runs | |
| CUSTOMER_NAME="${CHANNEL_NAME}-${{ github.run_number }}" | |
| echo "branch-name=$BRANCH_NAME" >> $GITHUB_OUTPUT | |
| echo "channel-name=$CHANNEL_NAME" >> $GITHUB_OUTPUT | |
| echo "customer-name=$CUSTOMER_NAME" >> $GITHUB_OUTPUT | |
| echo "Branch: $BRANCH_NAME, Channel: $CHANNEL_NAME, Customer: $CUSTOMER_NAME" | |
| validate-charts: | |
| runs-on: ubuntu-22.04 | |
| needs: setup | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Validate charts | |
| uses: ./.github/actions/chart-validate | |
| with: | |
| app-dir: ${{ env.APP_DIR }} | |
| helm-version: ${{ env.HELM_VERSION }} | |
| - name: Validate Taskfile syntax | |
| run: task --list-all | |
| working-directory: ${{ env.APP_DIR }} | |
| build-and-package: | |
| runs-on: ubuntu-22.04 | |
| needs: [setup, validate-charts] | |
| outputs: | |
| release-path: ${{ steps.package.outputs.release-path }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Package charts | |
| id: package | |
| uses: ./.github/actions/chart-package | |
| with: | |
| app-dir: ${{ env.APP_DIR }} | |
| helm-version: ${{ env.HELM_VERSION }} | |
| - name: Upload release artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: wg-easy-release-${{ github.run_number }} | |
| path: ${{ steps.package.outputs.release-path }} | |
| retention-days: 7 | |
| create-release: | |
| runs-on: ubuntu-22.04 | |
| needs: [setup, build-and-package] | |
| outputs: | |
| channel-slug: ${{ steps.set-release-outputs.outputs.channel-slug }} | |
| release-sequence: ${{ steps.set-release-outputs.outputs.release-sequence }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Download release artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: wg-easy-release-${{ github.run_number }} | |
| path: ${{ env.APP_DIR }}/release | |
| - name: Check if channel exists | |
| id: check-channel | |
| run: | | |
| set -e | |
| echo "Checking for existing channel: ${{ needs.setup.outputs.channel-name }}" | |
| # Get channels with error handling | |
| RESPONSE=$(curl -s -w "\n%{http_code}" -H "Authorization: ${{ env.REPLICATED_API_TOKEN }}" \ | |
| "https://api.replicated.com/vendor/v3/apps/${{ env.REPLICATED_APP }}/channels") | |
| HTTP_CODE=$(echo "$RESPONSE" | tail -n1) | |
| BODY=$(echo "$RESPONSE" | sed '$d') | |
| if [ "$HTTP_CODE" != "200" ]; then | |
| echo "API request failed with HTTP $HTTP_CODE" | |
| echo "Response: $BODY" | |
| echo "channel-exists=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Parse JSON response safely | |
| CHANNEL_ID=$(echo "$BODY" | jq -r --arg name "${{ needs.setup.outputs.channel-name }}" \ | |
| 'if .channels then .channels[] | select(.name == $name) | .id else empty end' 2>/dev/null | head -1) | |
| if [ -n "$CHANNEL_ID" ] && [ "$CHANNEL_ID" != "null" ]; then | |
| echo "Found existing channel: $CHANNEL_ID" | |
| echo "channel-exists=true" >> $GITHUB_OUTPUT | |
| echo "channel-id=$CHANNEL_ID" >> $GITHUB_OUTPUT | |
| echo "channel-slug=${{ needs.setup.outputs.channel-name }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "Channel does not exist" | |
| echo "channel-exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create Replicated release | |
| id: release | |
| uses: replicatedhq/replicated-actions/[email protected] | |
| with: | |
| app-slug: ${{ env.REPLICATED_APP }} | |
| api-token: ${{ env.REPLICATED_API_TOKEN }} | |
| yaml-dir: ${{ env.APP_DIR }}/release | |
| promote-channel: ${{ needs.setup.outputs.channel-name }} | |
| - name: Set release outputs | |
| id: set-release-outputs | |
| run: | | |
| if [ "${{ steps.check-channel.outputs.channel-exists }}" == "true" ]; then | |
| echo "channel-slug=${{ steps.check-channel.outputs.channel-slug }}" >> $GITHUB_OUTPUT | |
| echo "release-sequence=${{ steps.release.outputs.release-sequence }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "channel-slug=${{ steps.release.outputs.channel-slug }}" >> $GITHUB_OUTPUT | |
| echo "release-sequence=${{ steps.release.outputs.release-sequence }}" >> $GITHUB_OUTPUT | |
| fi | |
| test-deployment: | |
| runs-on: ubuntu-22.04 | |
| needs: [setup, create-release] | |
| strategy: | |
| matrix: | |
| include: | |
| # k3s single-node configurations (latest patch versions) | |
| - k8s-version: "v1.31.10" | |
| distribution: "k3s" | |
| nodes: 1 | |
| instance-type: "r1.small" | |
| timeout-minutes: 15 | |
| - k8s-version: "v1.32.6" | |
| distribution: "k3s" | |
| nodes: 1 | |
| instance-type: "r1.small" | |
| timeout-minutes: 15 | |
| # k3s multi-node configurations | |
| - k8s-version: "v1.32.6" | |
| distribution: "k3s" | |
| nodes: 3 | |
| instance-type: "r1.medium" | |
| timeout-minutes: 20 | |
| # kind configurations (maximum 1 node supported, distribution-specific patch versions) | |
| - k8s-version: "v1.31.9" | |
| distribution: "kind" | |
| nodes: 1 | |
| instance-type: "r1.small" | |
| timeout-minutes: 20 | |
| - k8s-version: "v1.32.5" | |
| distribution: "kind" | |
| nodes: 1 | |
| instance-type: "r1.small" | |
| timeout-minutes: 20 | |
| # EKS configurations (major.minor versions only) | |
| - k8s-version: "v1.31" | |
| distribution: "eks" | |
| nodes: 2 | |
| instance-type: "c5.large" | |
| timeout-minutes: 30 | |
| - k8s-version: "v1.32" | |
| distribution: "eks" | |
| nodes: 2 | |
| instance-type: "c5.large" | |
| timeout-minutes: 30 | |
| exclude: [] | |
| fail-fast: false | |
| max-parallel: 4 | |
| outputs: | |
| customer-id: ${{ steps.set-customer-outputs.outputs.customer-id }} | |
| license-id: ${{ steps.set-customer-outputs.outputs.license-id }} | |
| cluster-id: ${{ steps.set-cluster-outputs.outputs.cluster-id }} | |
| steps: | |
| - name: Set concurrency group | |
| run: | | |
| echo "CONCURRENCY_GROUP=cluster-${{ needs.setup.outputs.channel-name }}-${{ matrix.k8s-version }}-${{ matrix.distribution }}" >> $GITHUB_ENV | |
| echo "Starting matrix job: ${{ matrix.k8s-version }}-${{ matrix.distribution }}-${{ matrix.nodes }}nodes" | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup tools | |
| uses: ./.github/actions/setup-tools | |
| with: | |
| helm-version: ${{ env.HELM_VERSION }} | |
| install-helmfile: 'true' | |
| - name: Configure distribution-specific settings | |
| id: dist-config | |
| run: | | |
| case "${{ matrix.distribution }}" in | |
| "k3s") | |
| echo "cluster-disk-size=20" >> $GITHUB_OUTPUT | |
| echo "cluster-ttl=4h" >> $GITHUB_OUTPUT | |
| echo "resource-priority=high" >> $GITHUB_OUTPUT | |
| ;; | |
| "kind") | |
| echo "cluster-disk-size=30" >> $GITHUB_OUTPUT | |
| echo "cluster-ttl=4h" >> $GITHUB_OUTPUT | |
| echo "resource-priority=medium" >> $GITHUB_OUTPUT | |
| ;; | |
| "eks") | |
| echo "cluster-disk-size=50" >> $GITHUB_OUTPUT | |
| echo "cluster-ttl=6h" >> $GITHUB_OUTPUT | |
| echo "resource-priority=low" >> $GITHUB_OUTPUT | |
| ;; | |
| *) | |
| echo "cluster-disk-size=20" >> $GITHUB_OUTPUT | |
| echo "cluster-ttl=4h" >> $GITHUB_OUTPUT | |
| echo "resource-priority=medium" >> $GITHUB_OUTPUT | |
| ;; | |
| esac | |
| # Set resource limits based on node count and instance type | |
| case "${{ matrix.nodes }}" in | |
| "1") | |
| echo "max-parallel-jobs=3" >> $GITHUB_OUTPUT | |
| ;; | |
| "2") | |
| echo "max-parallel-jobs=2" >> $GITHUB_OUTPUT | |
| ;; | |
| "3") | |
| echo "max-parallel-jobs=1" >> $GITHUB_OUTPUT | |
| ;; | |
| *) | |
| echo "max-parallel-jobs=2" >> $GITHUB_OUTPUT | |
| ;; | |
| esac | |
| echo "Distribution: ${{ matrix.distribution }}, Nodes: ${{ matrix.nodes }}, Instance: ${{ matrix.instance-type }}" | |
| echo "Resource Priority: $(echo '${{ steps.dist-config.outputs.resource-priority }}' || echo 'medium')" | |
| - name: Check if customer exists | |
| id: check-customer | |
| run: | | |
| set -e | |
| CUSTOMER_NAME="${{ needs.setup.outputs.customer-name }}-${{ matrix.k8s-version }}-${{ matrix.distribution }}" | |
| echo "Checking for existing customer: $CUSTOMER_NAME" | |
| # Get customers with error handling | |
| RESPONSE=$(curl -s -w "\n%{http_code}" -H "Authorization: ${{ env.REPLICATED_API_TOKEN }}" \ | |
| "https://api.replicated.com/vendor/v3/customers") | |
| HTTP_CODE=$(echo "$RESPONSE" | tail -n1) | |
| BODY=$(echo "$RESPONSE" | sed '$d') | |
| if [ "$HTTP_CODE" != "200" ]; then | |
| echo "API request failed with HTTP $HTTP_CODE" | |
| echo "Response: $BODY" | |
| echo "customer-exists=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Parse JSON response safely - select most recent customer by creation date | |
| CUSTOMER_DATA=$(echo "$BODY" | jq -r --arg name "$CUSTOMER_NAME" \ | |
| 'if .customers then .customers[] | select(.name == $name) | {id: .id, created: .createdAt} else empty end' 2>/dev/null \ | |
| | jq -s 'sort_by(.created) | reverse | .[0] // empty' 2>/dev/null) | |
| CUSTOMER_ID=$(echo "$CUSTOMER_DATA" | jq -r '.id // empty' 2>/dev/null) | |
| if [ -n "$CUSTOMER_DATA" ] && [ "$CUSTOMER_DATA" != "null" ] && [ "$CUSTOMER_DATA" != "{}" ]; then | |
| CUSTOMER_COUNT=$(echo "$BODY" | jq -r --arg name "$CUSTOMER_NAME" \ | |
| 'if .customers then [.customers[] | select(.name == $name)] | length else 0 end' 2>/dev/null) | |
| echo "Found $CUSTOMER_COUNT customer(s) with name '$CUSTOMER_NAME', using most recent: $CUSTOMER_ID" | |
| fi | |
| if [ -n "$CUSTOMER_ID" ] && [ "$CUSTOMER_ID" != "null" ]; then | |
| echo "Found existing customer: $CUSTOMER_ID" | |
| echo "customer-exists=true" >> $GITHUB_OUTPUT | |
| echo "customer-id=$CUSTOMER_ID" >> $GITHUB_OUTPUT | |
| # Get license ID for existing customer with error handling | |
| LICENSE_RESPONSE=$(curl -s -w "\n%{http_code}" -H "Authorization: ${{ env.REPLICATED_API_TOKEN }}" \ | |
| "https://api.replicated.com/vendor/v3/customer/$CUSTOMER_ID") | |
| LICENSE_HTTP_CODE=$(echo "$LICENSE_RESPONSE" | tail -n1) | |
| LICENSE_BODY=$(echo "$LICENSE_RESPONSE" | sed '$d') | |
| if [ "$LICENSE_HTTP_CODE" = "200" ]; then | |
| LICENSE_ID=$(echo "$LICENSE_BODY" | jq -r '.customer.installationId // empty' 2>/dev/null) | |
| echo "license-id=$LICENSE_ID" >> $GITHUB_OUTPUT | |
| else | |
| echo "Failed to get license ID for customer $CUSTOMER_ID" | |
| echo "customer-exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| echo "Customer does not exist" | |
| echo "customer-exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create customer | |
| id: create-customer | |
| if: steps.check-customer.outputs.customer-exists == 'false' | |
| uses: replicatedhq/replicated-actions/[email protected] | |
| with: | |
| app-slug: ${{ env.REPLICATED_APP }} | |
| api-token: ${{ env.REPLICATED_API_TOKEN }} | |
| customer-name: ${{ needs.setup.outputs.customer-name }}-${{ matrix.k8s-version }}-${{ matrix.distribution }} | |
| channel-slug: ${{ needs.create-release.outputs.channel-slug }} | |
| license-type: dev | |
| - name: Set customer outputs | |
| id: set-customer-outputs | |
| run: | | |
| if [ "${{ steps.check-customer.outputs.customer-exists }}" == "true" ]; then | |
| echo "customer-id=${{ steps.check-customer.outputs.customer-id }}" >> $GITHUB_OUTPUT | |
| echo "license-id=${{ steps.check-customer.outputs.license-id }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "customer-id=${{ steps.create-customer.outputs.customer-id }}" >> $GITHUB_OUTPUT | |
| echo "license-id=${{ steps.create-customer.outputs.license-id }}" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Check if cluster exists | |
| id: check-cluster | |
| run: | | |
| set -e | |
| CLUSTER_NAME="${{ needs.setup.outputs.channel-name }}-${{ matrix.k8s-version }}-${{ matrix.distribution }}" | |
| echo "Checking for existing cluster: $CLUSTER_NAME" | |
| # Get clusters with error handling | |
| RESPONSE=$(curl -s -w "\n%{http_code}" -H "Authorization: ${{ env.REPLICATED_API_TOKEN }}" \ | |
| "https://api.replicated.com/vendor/v3/clusters") | |
| HTTP_CODE=$(echo "$RESPONSE" | tail -n1) | |
| BODY=$(echo "$RESPONSE" | sed '$d') | |
| if [ "$HTTP_CODE" != "200" ]; then | |
| echo "API request failed with HTTP $HTTP_CODE" | |
| echo "Response: $BODY" | |
| echo "cluster-exists=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Parse JSON response safely | |
| CLUSTER_ID=$(echo "$BODY" | jq -r --arg name "$CLUSTER_NAME" \ | |
| 'if .clusters then .clusters[] | select(.name == $name and .status != "terminated") | .id else empty end' 2>/dev/null | head -1) | |
| if [ -n "$CLUSTER_ID" ] && [ "$CLUSTER_ID" != "null" ]; then | |
| echo "Found existing cluster: $CLUSTER_ID" | |
| echo "cluster-exists=true" >> $GITHUB_OUTPUT | |
| echo "cluster-id=$CLUSTER_ID" >> $GITHUB_OUTPUT | |
| # Export kubeconfig for existing cluster with error handling | |
| KUBECONFIG_RESPONSE=$(curl -s -w "\n%{http_code}" -H "Authorization: ${{ env.REPLICATED_API_TOKEN }}" \ | |
| "https://api.replicated.com/vendor/v3/cluster/$CLUSTER_ID/kubeconfig") | |
| KUBECONFIG_HTTP_CODE=$(echo "$KUBECONFIG_RESPONSE" | tail -n1) | |
| KUBECONFIG_BODY=$(echo "$KUBECONFIG_RESPONSE" | sed '$d') | |
| if [ "$KUBECONFIG_HTTP_CODE" = "200" ]; then | |
| # Extract and decode the kubeconfig from JSON response | |
| KUBECONFIG_CONTENT=$(echo "$KUBECONFIG_BODY" | jq -r '.kubeconfig // empty' 2>/dev/null) | |
| if [ -n "$KUBECONFIG_CONTENT" ] && [ "$KUBECONFIG_CONTENT" != "null" ] && [ "$KUBECONFIG_CONTENT" != "empty" ]; then | |
| # Write the decoded kubeconfig content to file | |
| echo "$KUBECONFIG_CONTENT" > /tmp/kubeconfig | |
| if [ -s /tmp/kubeconfig ]; then | |
| echo "KUBECONFIG=/tmp/kubeconfig" >> $GITHUB_ENV | |
| echo "Successfully extracted kubeconfig for existing cluster" | |
| else | |
| echo "Failed to write kubeconfig to file" | |
| fi | |
| else | |
| echo "Failed to extract kubeconfig from response - content is empty or null" | |
| fi | |
| else | |
| echo "Failed to get kubeconfig for cluster $CLUSTER_ID" | |
| fi | |
| else | |
| echo "Cluster does not exist" | |
| echo "cluster-exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create cluster | |
| id: create-cluster | |
| if: steps.check-cluster.outputs.cluster-exists == 'false' | |
| uses: replicatedhq/replicated-actions/[email protected] | |
| with: | |
| api-token: ${{ env.REPLICATED_API_TOKEN }} | |
| kubernetes-distribution: ${{ matrix.distribution }} | |
| kubernetes-version: ${{ matrix.k8s-version }} | |
| cluster-name: ${{ needs.setup.outputs.channel-name }}-${{ matrix.k8s-version }}-${{ matrix.distribution }} | |
| ttl: ${{ steps.dist-config.outputs.cluster-ttl }} | |
| nodes: ${{ matrix.nodes }} | |
| instance-type: ${{ matrix.instance-type }} | |
| disk: ${{ steps.dist-config.outputs.cluster-disk-size }} | |
| export-kubeconfig: 'true' | |
| - name: Set cluster outputs | |
| id: set-cluster-outputs | |
| run: | | |
| if [ "${{ steps.check-cluster.outputs.cluster-exists }}" == "true" ]; then | |
| echo "cluster-id=${{ steps.check-cluster.outputs.cluster-id }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "cluster-id=${{ steps.create-cluster.outputs.cluster-id }}" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Setup cluster ports | |
| working-directory: ${{ env.APP_DIR }} | |
| run: | | |
| task cluster-ports-expose CLUSTER_NAME="${{ needs.setup.outputs.channel-name }}-${{ matrix.k8s-version }}-${{ matrix.distribution }}" | |
| - name: Validate cluster readiness | |
| run: | | |
| echo "Validating cluster readiness for ${{ matrix.distribution }} ${{ matrix.k8s-version }}" | |
| # Check if kubeconfig is accessible | |
| if ! kubectl version --client &>/dev/null; then | |
| echo "Warning: kubectl not properly configured, skipping cluster validation" | |
| echo "This may happen with existing cluster kubeconfig extraction" | |
| exit 0 | |
| fi | |
| # Wait for cluster to be ready | |
| kubectl wait --for=condition=Ready nodes --all --timeout=300s | |
| # Validate cluster nodes | |
| echo "Cluster nodes:" | |
| kubectl get nodes -o wide | |
| echo "Cluster info:" | |
| kubectl cluster-info | |
| - name: Deploy application | |
| working-directory: ${{ env.APP_DIR }} | |
| run: | | |
| task customer-helm-install \ | |
| CUSTOMER_NAME="${{ needs.setup.outputs.customer-name }}-${{ matrix.k8s-version }}-${{ matrix.distribution }}" \ | |
| CLUSTER_NAME="${{ needs.setup.outputs.channel-name }}-${{ matrix.k8s-version }}-${{ matrix.distribution }}" \ | |
| CHANNEL_SLUG="${{ needs.create-release.outputs.channel-slug }}" \ | |
| REPLICATED_LICENSE_ID="${{ steps.set-customer-outputs.outputs.license-id }}" | |
| timeout-minutes: ${{ matrix.timeout-minutes }} | |
| - name: Run tests | |
| working-directory: ${{ env.APP_DIR }} | |
| run: task test | |
| timeout-minutes: 10 | |
| - name: Run distribution-specific tests | |
| run: | | |
| echo "Running ${{ matrix.distribution }}-specific tests..." | |
| # Test node configuration based on matrix | |
| EXPECTED_NODES=${{ matrix.nodes }} | |
| ACTUAL_NODES=$(kubectl get nodes --no-headers | wc -l) | |
| if [ "$ACTUAL_NODES" -eq "$EXPECTED_NODES" ]; then | |
| echo "✅ Node count validation passed: $ACTUAL_NODES/$EXPECTED_NODES" | |
| else | |
| echo "❌ Node count validation failed: $ACTUAL_NODES/$EXPECTED_NODES" | |
| exit 1 | |
| fi | |
| # Distribution-specific storage tests | |
| case "${{ matrix.distribution }}" in | |
| "k3s") | |
| echo "Testing k3s local-path storage..." | |
| kubectl get storageclass local-path -o yaml | grep provisioner | grep rancher.io/local-path | |
| ;; | |
| "kind") | |
| echo "Testing kind standard storage..." | |
| kubectl get storageclass standard -o yaml | grep provisioner | grep rancher.io/local-path | |
| ;; | |
| "eks") | |
| echo "Testing EKS GP2 storage..." | |
| kubectl get storageclass gp2 -o yaml | grep provisioner | grep ebs.csi.aws.com || echo "EKS storage validation skipped" | |
| ;; | |
| esac | |
| # Test cluster resources | |
| echo "Cluster resource utilization:" | |
| kubectl top nodes --no-headers 2>/dev/null || echo "Metrics not available" | |
| echo "Pod distribution across nodes:" | |
| kubectl get pods -A -o wide | awk '{print $7}' | sort | uniq -c | |
| # Performance monitoring | |
| echo "=== Performance Metrics ===" | |
| echo "Test Environment: ${{ matrix.distribution }} ${{ matrix.k8s-version }} (${{ matrix.nodes }} nodes)" | |
| echo "Instance Type: ${{ matrix.instance-type }}" | |
| echo "Priority: ${{ steps.dist-config.outputs.resource-priority }}" | |
| echo "Deployment Timeout: ${{ matrix.timeout-minutes }} minutes" | |
| # Resource consumption validation | |
| echo "=== Resource Validation ===" | |
| kubectl describe nodes | grep -E "(Name:|Allocatable:|Allocated resources:)" | head -20 | |
| # Collect performance timings | |
| echo "=== Test Completion Summary ===" | |
| echo "Matrix Job: ${{ matrix.k8s-version }}-${{ matrix.distribution }}-${{ matrix.nodes }}nodes" | |
| echo "Started: $(date -u)" | |
| echo "Status: Complete" | |
| - name: Upload debug logs | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: debug-logs-${{ github.run_number }}-${{ matrix.k8s-version }}-${{ matrix.distribution }} | |
| path: | | |
| /tmp/*.log | |
| ~/.replicated/ |