diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 008b0cc..b86ecf0 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -47,36 +47,80 @@ jobs: run: | docker build --no-cache \ -t "${IMAGE}:${{ steps.sha.outputs.short_sha }}" \ - -t "${IMAGE}:latest" \ -f Dockerfile . + echo "Built image: ${IMAGE}:${{ steps.sha.outputs.short_sha }}" - - name: Push Docker image + - name: Push test image (SHA tag only, not latest yet) run: | docker push "${IMAGE}:${{ steps.sha.outputs.short_sha }}" + echo "✓ Pushed test image: ${IMAGE}:${{ steps.sha.outputs.short_sha }}" + + - name: Detect in-cluster Kubernetes authentication + run: | + # When running inside K8s cluster, kubectl auto-detects service account + # Mounted at: /var/run/secrets/kubernetes.io/serviceaccount/ + if [ -f /var/run/secrets/kubernetes.io/serviceaccount/token ]; then + echo "✓ In-cluster authentication detected" + export KUBECONFIG=/dev/null # kubectl will auto-use in-cluster auth + else + echo "⚠ Not running in-cluster, kubectl may fail" + fi + + - name: Run integration tests via Kubernetes Job + run: | + echo "Running integration tests via Kubernetes Job..." + echo "Test image: ${IMAGE}:${{ steps.sha.outputs.short_sha }}" + + # Apply job template from repo (uses in-cluster auth automatically) + kubectl apply -f k8s/integration-test-job.yaml + + # Update job to use new image + kubectl set image job/api-gateway-integration-test \ + integration-tester="${IMAGE}:${{ steps.sha.outputs.short_sha }}" \ + -n api --record + + # Wait for job to complete (max 10 minutes) + echo "Waiting for job to complete (this may take a few minutes)..." + kubectl wait --for=condition=complete job/api-gateway-integration-test \ + -n api --timeout=10m 2>/dev/null || true + + # Stream logs + echo "" + echo "=== Job Logs ===" + kubectl logs -n api job/api-gateway-integration-test --all-containers=true --timestamps=true || echo "No logs available" + echo "================" + echo "" + + # Check if job succeeded + SUCCEEDED=$(kubectl get job api-gateway-integration-test -n api -o jsonpath='{.status.succeeded}' 2>/dev/null || echo "0") + FAILED=$(kubectl get job api-gateway-integration-test -n api -o jsonpath='{.status.failed}' 2>/dev/null || echo "0") + + echo "Job Status: Succeeded=$SUCCEEDED, Failed=$FAILED" + + if [ "$SUCCEEDED" = "1" ]; then + echo "✓ Integration tests PASSED" + exit 0 + else + echo "✗ Integration tests FAILED" + exit 1 + fi + continue-on-error: false + + - name: Promote image to latest (only if tests passed) + if: success() + run: | + docker pull "${IMAGE}:${{ steps.sha.outputs.short_sha }}" + docker tag "${IMAGE}:${{ steps.sha.outputs.short_sha }}" "${IMAGE}:latest" docker push "${IMAGE}:latest" - echo "✓ Pushed: ${IMAGE}:${{ steps.sha.outputs.short_sha }}" + echo "✓ Promoted ${IMAGE}:${{ steps.sha.outputs.short_sha }} to latest" - - name: Prune unused images + - name: Cleanup integration test job + if: always() + run: | + echo "Cleaning up test job..." + kubectl delete job api-gateway-integration-test -n api --ignore-not-found=true + continue-on-error: true + + - name: Cleanup docker + if: always() run: docker image prune -a --force 2>&1 | tail -3 || true - - - name: Setup kubeconfig - run: | - mkdir -p ~/.kube - echo "${KUBECONFIG_B64}" | base64 -d > ~/.kube/config - env: - KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }} - continue-on-error: true - - - name: Install kubectl - run: | - curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x kubectl - sudo mv kubectl /usr/local/bin/ - - - name: Run integration tests against cluster - run: | - echo "Running integration tests against production cluster..." - go test -v -tags=integration ./internal/integration/... || true - env: - GATEWAY_URL: http://api-gateway.api.svc.cluster.local:8080 - continue-on-error: true diff --git a/internal/integration/integration_test.go b/internal/integration/integration_test.go index cf0d7d9..9e851f8 100644 --- a/internal/integration/integration_test.go +++ b/internal/integration/integration_test.go @@ -247,7 +247,7 @@ func TestIntegrationIAMService(t *testing.T) { } defer resp.Body.Close() - body, _ := io.ReadAll(resp.Body) + _, _ = io.ReadAll(resp.Body) t.Logf("IAM list users response: %d", resp.StatusCode) // IAM (Authentik) should respond - 200, 404, or auth error all prove routing works diff --git a/k8s/integration-test-job.yaml b/k8s/integration-test-job.yaml index d6f8243..1dd8307 100644 --- a/k8s/integration-test-job.yaml +++ b/k8s/integration-test-job.yaml @@ -5,32 +5,35 @@ metadata: namespace: api spec: template: + metadata: + labels: + app: api-gateway + managed-by: test + role: integration-test spec: serviceAccountName: api-gateway restartPolicy: Never containers: - name: integration-tester - image: golang:1.26-bookworm - imagePullPolicy: IfNotPresent - workingDir: /workspace + image: forgejo.riotpiao.com/rock/api-gateway:latest + imagePullPolicy: Always + workingDir: /app command: - - /bin/bash + - /bin/sh - -c - | set -e echo "Starting integration tests..." + echo "Gateway URL: http://api-gateway:8080" - # Clone the repo - git clone https://forgejo.riotpiao.com/riotpiao-poimen/homelab-frontend.git . - - # Wait for gateway to be ready + # Wait for gateway service to be ready echo "Waiting for gateway service to be ready..." - for i in {1..30}; do - if curl -s http://api-gateway:8080/healthz | grep -q "alive"; then + for i in $(seq 1 30); do + if curl -s http://api-gateway:8080/healthz > /dev/null 2>&1; then echo "✓ Gateway is ready" break fi - echo "Attempting to reach gateway ($i/30)..." + echo "Waiting for gateway... ($i/30)" sleep 2 done @@ -42,6 +45,8 @@ spec: env: - name: GATEWAY_URL value: "http://api-gateway:8080" + - name: CI + value: "true" resources: requests: cpu: 250m @@ -67,4 +72,6 @@ spec: emptyDir: {} - name: home emptyDir: {} + imagePullSecrets: + - name: regcred backoffLimit: 1