Skip to content

Debulleting Porch Architecture & Components - Engine #2100

Debulleting Porch Architecture & Components - Engine

Debulleting Porch Architecture & Components - Engine #2100

# Copyright 2025-2026 The kpt Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
name: End-to-End Tests
on:
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
IMAGE_REPO: porch-kind
KIND_CONTEXT_NAME: porch-test
PORCH_FUNCTION_RUNNER_IMAGE: porch-function-runner
PORCH_WRAPPER_SERVER_IMAGE: porch-wrapper-server
PORCH_SERVER_IMAGE: porch-server
PORCH_CONTROLLERS_IMAGE: porch-controllers
jobs:
check-changes:
runs-on: ubuntu-latest
outputs:
code: ${{ steps.filter.outputs.code }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
code:
- '!docs/**'
build:
name: Build Dev Images
runs-on: ubuntu-latest
needs: check-changes
if: needs.check-changes.outputs.code == 'true'
timeout-minutes: 15
env:
IMAGE_TAG: ${{ github.sha }}
GOTOOLCHAIN: auto
outputs:
image-tag: ${{ steps.vars.outputs.image-tag }}
steps:
- name: Checkout Porch
uses: actions/checkout@v4
- name: Set up Go
uses: ./.github/actions/setup-go-kpt
with:
install-kpt: "false"
go-cache: "true"
- name: Set variables
id: vars
run: |
echo "image-tag=${IMAGE_TAG:0:8}" >> $GITHUB_OUTPUT
echo "alpine-version=$(make --eval='print: ; @echo $(ALPINE_VERSION)' print)" >> $GITHUB_OUTPUT
echo "golang-bookworm=$(make --eval='print: ; @echo $(GOLANG_BOOKWORM_VERSION)' print)" >> $GITHUB_OUTPUT
echo "golang-alpine=$(make --eval='print: ; @echo $(GOLANG_ALPINE_VERSION)' print)" >> $GITHUB_OUTPUT
- name: Build images in parallel
run: |
set -e
export IMAGE_TAG=${IMAGE_TAG:0:8}
export ALPINE_VERSION=${{ steps.vars.outputs.alpine-version }}
export GOLANG_BOOKWORM_VERSION=${{ steps.vars.outputs.golang-bookworm }}
export GOLANG_ALPINE_VERSION=${{ steps.vars.outputs.golang-alpine }}
IMAGE_NAME=${PORCH_FUNCTION_RUNNER_IMAGE} WRAPPER_SERVER_IMAGE_NAME=${PORCH_WRAPPER_SERVER_IMAGE} make -C func/ build-image &
pid1=$!
IMAGE_NAME=${PORCH_SERVER_IMAGE} make -C build/ build-image &
pid2=$!
IMAGE_NAME=${PORCH_CONTROLLERS_IMAGE} make -C controllers/ build-image &
pid3=$!
wait $pid1 && wait $pid2 && wait $pid3
- name: Verify images exist
run: |
export IMAGE_TAG=${IMAGE_TAG:0:8}
docker images
docker inspect ${IMAGE_REPO}/${PORCH_SERVER_IMAGE}:${IMAGE_TAG}
docker inspect ${IMAGE_REPO}/${PORCH_CONTROLLERS_IMAGE}:${IMAGE_TAG}
docker inspect ${IMAGE_REPO}/${PORCH_FUNCTION_RUNNER_IMAGE}:${IMAGE_TAG}
docker inspect ${IMAGE_REPO}/${PORCH_WRAPPER_SERVER_IMAGE}:${IMAGE_TAG}
- name: Save all images
run: |
export IMAGE_TAG=${IMAGE_TAG:0:8}
docker save \
${IMAGE_REPO}/${PORCH_SERVER_IMAGE}:${IMAGE_TAG} \
${IMAGE_REPO}/${PORCH_CONTROLLERS_IMAGE}:${IMAGE_TAG} \
${IMAGE_REPO}/${PORCH_FUNCTION_RUNNER_IMAGE}:${IMAGE_TAG} \
${IMAGE_REPO}/${PORCH_WRAPPER_SERVER_IMAGE}:${IMAGE_TAG} \
| gzip > porch-images.tar.gz
- name: Upload images
uses: actions/upload-artifact@v4
with:
name: porch-images
path: porch-images.tar.gz
compression-level: 0
retention-days: 1
tests:
name: ${{ matrix.name }}
runs-on: ubuntu-latest
timeout-minutes: 30
needs: [check-changes, build]
if: needs.check-changes.outputs.code == 'true'
env:
IMAGE_TAG: ${{ needs.build.outputs.image-tag }}
strategy:
fail-fast: false
matrix:
include:
- name: "Porch E2E Tests (DB Cache)"
make_target: "run-in-kind-db-cache-push-drafts"
test_path: "${GITHUB_WORKSPACE}/test/e2e/api"
test_env: "E2E=1 DB_CACHE=1"
log_prefix: "porch-e2e-dbcache"
- name: "Porch CLI E2E Tests (DB Cache)"
make_target: "run-in-kind-db-cache-push-drafts"
test_path: "${GITHUB_WORKSPACE}/test/e2e/cli"
test_env: "E2E=1"
log_prefix: "porch-cli-e2e-dbcache"
- name: "Porch CRD E2E Tests (v1alpha2)"
make_target: "run-in-kind-v1alpha2"
test_path: "${GITHUB_WORKSPACE}/test/e2e/crd -ginkgo.v"
test_env: "E2E=1"
log_prefix: "porch-crd-e2e"
- name: "Porch CLI E2E Tests (v1alpha2)"
make_target: "run-in-kind-v1alpha2"
test_path: "${GITHUB_WORKSPACE}/test/e2e/cli-v1alpha2"
test_env: "E2E=1"
log_prefix: "porch-cli-v1alpha2-e2e"
steps:
- name: Checkout Porch
uses: actions/checkout@v4
- name: Set up Go and kpt
uses: ./.github/actions/setup-go-kpt
with:
go-cache: "true"
- name: Install Kind
uses: helm/kind-action@v1
with:
version: v0.32.0
install_only: true
- name: Set up Git config
run: |
git config --global user.name "Porch E2E"
git config --global user.email "porch-e2e@porch.dev"
- name: Setup dev env
run: ${GITHUB_WORKSPACE}/scripts/setup-dev-env.sh
- name: Download image artifacts
uses: actions/download-artifact@v4
with:
name: porch-images
- name: Load images to kind
run: |
gunzip -c porch-images.tar.gz | docker load
kind load docker-image ${IMAGE_REPO}/${PORCH_SERVER_IMAGE}:${{ needs.build.outputs.image-tag }} -n ${KIND_CONTEXT_NAME}
kind load docker-image ${IMAGE_REPO}/${PORCH_CONTROLLERS_IMAGE}:${{ needs.build.outputs.image-tag }} -n ${KIND_CONTEXT_NAME}
kind load docker-image ${IMAGE_REPO}/${PORCH_FUNCTION_RUNNER_IMAGE}:${{ needs.build.outputs.image-tag }} -n ${KIND_CONTEXT_NAME}
kind load docker-image ${IMAGE_REPO}/${PORCH_WRAPPER_SERVER_IMAGE}:${{ needs.build.outputs.image-tag }} -n ${KIND_CONTEXT_NAME}
- name: Deploy porch kpt pkg
timeout-minutes: 10
run: IMAGE_TAG=${{ needs.build.outputs.image-tag }} SKIP_IMG_BUILD=true make ${{ matrix.make_target }}
- name: Dump cluster state on deploy failure
if: failure()
run: |
echo "=== Node Resources ==="
kubectl top nodes 2>/dev/null || kubectl describe nodes | grep -A 5 "Allocated resources" || true
echo ""
echo "=== Pods (all namespaces) ==="
kubectl get pods -A -o wide || true
echo ""
echo "=== Pod Resource Usage ==="
kubectl top pods -A 2>/dev/null || true
echo ""
echo "=== Services (porch-system) ==="
kubectl get svc -n porch-system 2>/dev/null || true
echo ""
echo "=== PVCs (porch-system) ==="
kubectl get pvc -n porch-system 2>/dev/null || true
echo ""
echo "=== ConfigMaps (porch-system) ==="
kubectl get configmaps -n porch-system 2>/dev/null || true
echo ""
echo "=== CRDs ==="
kubectl get crds | grep -E "porch|kpt" || true
echo ""
echo "=== APIServices ==="
kubectl get apiservices | grep -E "porch|kpt" || true
echo ""
echo "=== Events (porch-system, last 60) ==="
kubectl get events -n porch-system --sort-by='.lastTimestamp' 2>/dev/null | tail -60 || true
echo ""
echo "=== Events (kube-system, last 20) ==="
kubectl get events -n kube-system --sort-by='.lastTimestamp' 2>/dev/null | tail -20 || true
echo ""
echo "=== All pods details (porch-system) ==="
for pod in $(kubectl get pods -n porch-system -o jsonpath='{.items[*].metadata.name}' 2>/dev/null); do
echo ""
echo "--- Pod: porch-system/$pod ---"
kubectl describe pod -n porch-system "$pod" 2>/dev/null | grep -A 30 "Conditions:" || true
echo "--- Logs: porch-system/$pod (last 50 lines, all containers) ---"
kubectl logs -n porch-system "$pod" --all-containers --tail=50 2>/dev/null || true
done
echo ""
echo "=== Non-running pods (other namespaces) ==="
for pod in $(kubectl get pods -A -o json 2>/dev/null | jq -r '.items[] | select(.metadata.namespace != "porch-system") | select(.status.phase != "Running" and .status.phase != "Succeeded") | "\(.metadata.namespace)/\(.metadata.name)"'); do
ns=$(echo $pod | cut -d/ -f1)
name=$(echo $pod | cut -d/ -f2)
echo "--- Describe $ns/$name ---"
kubectl describe pod -n "$ns" "$name" 2>/dev/null | tail -20 || true
echo "--- Logs $ns/$name ---"
kubectl logs -n "$ns" "$name" --all-containers --tail=30 2>/dev/null || true
done
- name: Run E2E tests
run: ${{ matrix.test_env }} go test -v -timeout 20m ${{ matrix.test_path }}
- name: Export porch server logs
if: always()
run: |
kubectl -n porch-system logs -l app=porch-server --all-containers --tail=-1 > ${{ matrix.log_prefix }}-server.log 2>/dev/null || true
- name: Export porch controllers logs
if: always()
run: |
kubectl -n porch-system logs -l k8s-app=porch-controllers --all-containers --tail=-1 > ${{ matrix.log_prefix }}-controllers.log 2>/dev/null || true
- name: Archive logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.log_prefix }}-logs
path: "*.log"
compression-level: 0
retention-days: 2
e2e-summary:
name: E2E Tests Summary
if: always()
needs: [check-changes, build, tests]
runs-on: ubuntu-latest
steps:
- run: exit 1
if: |
needs.check-changes.outputs.code == 'true' &&
(contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled'))
- run: echo "All tests passed or skipped"