diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index f3d3a67..e6aaa01 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -185,132 +185,97 @@ jobs: - name: Deploy to production (Local Test) run: | + set -euo pipefail echo "πŸš€ Testing ${{ needs.create-release.outputs.version }} deployment locally..." - + + # Create a dedicated network so we can resolve by container name + docker network create ci_net || true + # Pull the built image docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }} - - # Stop any existing containers - docker stop ping-river-monitor-test || true - docker rm ping-river-monitor-test || true - - # Start the container for testing + + # Stop & remove any existing container + docker rm -f ping-river-monitor-test 2>/dev/null || true + + # Start the container on the user-defined network docker run -d \ --name ping-river-monitor-test \ + --network ci_net \ -p 8080:8000 \ -e LOG_LEVEL=INFO \ -e DB_TYPE=sqlite \ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }} - + echo "βœ… Container started for testing" - name: Health check after deployment run: | + set -euo pipefail echo "⏳ Waiting for application to start..." - sleep 30 - - echo "πŸ” Running health checks against local container..." - - # Check if container is running - docker ps | grep ping-river-monitor-test || echo "⚠️ Container not found in docker ps" - - # Check container logs for any startup issues - echo "πŸ“‹ Recent container logs:" - docker logs --tail 10 ping-river-monitor-test || true - - # Wait for the application to be ready with more robust checking - echo "πŸ” Testing application readiness..." + + # Pull a curl-only image for probing (keeps your app image slim) + docker pull curlimages/curl:8.10.1 + + # Helper: curl via a sibling container on the SAME Docker network + probe() { + local url="$1" + docker run --rm --network ci_net curlimages/curl:8.10.1 \ + -sS --max-time 5 --connect-timeout 3 -w "HTTP_CODE:%{http_code}" "$url" || true + } + + # Wait for /health (up to ~3m 45s) for i in {1..15}; do - echo "⏳ Attempt $i/15: Testing health endpoint..." + echo "πŸ” Attempt $i/15: checking http://ping-river-monitor-test:8000/health" + resp="$(probe http://ping-river-monitor-test:8000/health)" + code="$(echo "$resp" | sed -n 's/.*HTTP_CODE:\([0-9]\+\).*/\1/p')" + body="$(echo "$resp" | sed 's/HTTP_CODE:[0-9]*$//')" - # Test health endpoint with container networking - echo "Testing health endpoint..." + echo "HTTP: ${code:-} | Body: ${body:-}" - # Get the container's IP address for direct communication - CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ping-river-monitor-test) - echo "Container IP: $CONTAINER_IP" - - # Try multiple connection methods - response="" - - # Method 1: Try container IP directly - if [ -n "$CONTAINER_IP" ]; then - echo "Trying container IP: $CONTAINER_IP:8000" - response=$(curl -s --max-time 5 --connect-timeout 3 -w "HTTP_CODE:%{http_code}" http://$CONTAINER_IP:8000/health 2>/dev/null || echo "TIMEOUT") - fi - - # Method 2: If container IP fails, try docker exec - if [[ "$response" == "TIMEOUT" ]] || [ -z "$response" ]; then - echo "Container IP failed, trying docker exec..." - response=$(docker exec ping-river-monitor-test curl -s --max-time 5 -w "HTTP_CODE:%{http_code}" http://127.0.0.1:8000/health 2>/dev/null || echo "EXEC_FAILED") - fi - - # Method 3: If exec fails, try host networking - if [[ "$response" == "EXEC_FAILED" ]] || [ -z "$response" ]; then - echo "Docker exec failed, trying host networking..." - response=$(curl -s --max-time 5 --connect-timeout 3 -w "HTTP_CODE:%{http_code}" http://127.0.0.1:8080/health 2>/dev/null || echo "HOST_FAILED") - fi - - http_code=$(echo "$response" | grep -o "HTTP_CODE:[0-9]*" | cut -d: -f2) - response_body=$(echo "$response" | sed 's/HTTP_CODE:[0-9]*$//') - - echo "HTTP Code: $http_code" - echo "Response Body: $response_body" - - if [ "$http_code" = "200" ] && [ -n "$response_body" ]; then - echo "βœ… Health endpoint responding successfully!" + if [ "${code:-}" = "200" ] && [ -n "${body:-}" ]; then + echo "βœ… Health endpoint responding successfully" break - else - echo "❌ Health check failed (HTTP: $http_code), waiting 15 seconds..." - # Show what's happening with the container - echo "Container status:" - docker ps | grep ping-river-monitor-test || echo "Container not found" - echo "Recent container logs:" - docker logs --tail 5 ping-river-monitor-test || true - sleep 15 - fi - done - - # Test API endpoints with container networking - echo "πŸ§ͺ Testing API endpoints..." - - # Get container IP for direct communication - CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ping-river-monitor-test) - echo "Using container IP: $CONTAINER_IP" - - endpoints=("health" "docs" "stations" "metrics") - for endpoint in "${endpoints[@]}"; do - echo "Testing /$endpoint..." - - # Try multiple connection methods for reliability - response="" - - # Try docker exec first (most reliable in containerized CI) - response=$(docker exec ping-river-monitor-test curl -s --max-time 5 -w "HTTP_CODE:%{http_code}" http://127.0.0.1:8000/$endpoint 2>/dev/null || echo "EXEC_FAILED") - - # Fallback to container IP if exec fails - if [[ "$response" == "EXEC_FAILED" ]] && [ -n "$CONTAINER_IP" ]; then - response=$(curl -s --max-time 5 --connect-timeout 3 -w "HTTP_CODE:%{http_code}" http://$CONTAINER_IP:8000/$endpoint 2>/dev/null || echo "IP_FAILED") fi - # Final fallback to host networking - if [[ "$response" == "IP_FAILED" ]] || [[ "$response" == "EXEC_FAILED" ]]; then - response=$(curl -s --max-time 5 --connect-timeout 3 -w "HTTP_CODE:%{http_code}" http://127.0.0.1:8080/$endpoint 2>/dev/null || echo "ALL_FAILED") - fi + echo "❌ Not ready yet. Showing recent logs…" + docker logs --tail 20 ping-river-monitor-test || true + sleep 15 - http_code=$(echo "$response" | grep -o "HTTP_CODE:[0-9]*" | cut -d: -f2) - - if [ "$http_code" = "200" ]; then - echo "βœ… /$endpoint: OK (HTTP $http_code)" - else - echo "❌ /$endpoint: FAILED (HTTP $http_code)" - echo "Response: $(echo "$response" | sed 's/HTTP_CODE:[0-9]*$//')" + if [ "$i" -eq 15 ]; then + echo "❌ Health never reached 200. Failing." exit 1 fi done - + + echo "πŸ§ͺ Testing API endpoints…" + endpoints=("health" "docs" "stations" "metrics") + for ep in "${endpoints[@]}"; do + url="http://ping-river-monitor-test:8000/$ep" + resp="$(probe "$url")" + code="$(echo "$resp" | sed -n 's/.*HTTP_CODE:\([0-9]\+\).*/\1/p')" + + if [ "${code:-}" = "200" ]; then + echo "βœ… /$ep: OK" + else + echo "❌ /$ep: FAILED (HTTP ${code:-})" + echo "Response: $(echo "$resp" | sed 's/HTTP_CODE:[0-9]*$//')" + exit 1 + fi + done + echo "βœ… All health checks passed!" + - name: (Fallback) Probe via host-published port + if: always() + run: | + set -euo pipefail + # In case you also want to verify the host-published port from inside the job container: + HOST_GATEWAY="$(ip route | awk '/default/ {print $3}')" + echo "πŸ”Ž Host gateway is $HOST_GATEWAY β€” probing http://$HOST_GATEWAY:8080/health" + docker run --rm curlimages/curl:8.10.1 \ + -sS --max-time 5 --connect-timeout 3 -w "HTTP_CODE:%{http_code}\n" \ + "http://$HOST_GATEWAY:8080/health" || true + - name: Container logs and cleanup if: always() run: |