diff --git a/.gitea/workflows/ci-cd.yaml b/.gitea/workflows/ci-cd.yaml index 649a7ec..a8c830a 100644 --- a/.gitea/workflows/ci-cd.yaml +++ b/.gitea/workflows/ci-cd.yaml @@ -65,64 +65,18 @@ jobs: - name: Redeploy stack on Portainer if: github.event_name == 'workflow_dispatch' && inputs.deploy == true env: + PORTAINER_URL: ${{ secrets.PORTAINER_URL }} PORTAINER_TOKEN: ${{ secrets.PORTAINER_TOKEN }} PORTAINER_ENDPOINT_ID: ${{ secrets.PORTAINER_ENDPOINT_ID }} PORTAINER_STACK_ID: ${{ secrets.PORTAINER_STACK_ID }} run: | - # NOTE: no `set -e` here on purpose — the auto-discovery loop below - # needs to try every candidate even if some probes fail, and some - # diagnostic commands (ip route, hostname -I) might return empty - # in unusual container network setups without aborting the job. - echo "hostname: $(hostname)" - echo "hostname -I:" - hostname -I 2>/dev/null || echo "(none)" - echo "ip -4 addr show (eth* only):" - ip -4 addr show 2>/dev/null | grep -E "^[0-9]+:|inet " | head -20 - echo "ip route:" - ip route 2>/dev/null - echo "ip route show default:" - ip -4 route show default 2>/dev/null - echo "curl to 192.168.1.30:9000 (5s timeout):" - curl -sS -o /dev/null -w ' HTTP=%{http_code} time=%{time_total}s\n' --max-time 5 "http://192.168.1.30:9000/api/status" 2>&1 || echo " (curl failed)" - echo "---" - - echo "--- Step 0: auto-discover a reachable Portainer URL ---" - # The runner creates an ephemeral docker network per job, so the - # canonical PORTAINER_URL (e.g. http://192.168.1.30:9000) often isn't - # reachable from inside the job container. Strategy: probe every IP - # we can find (container's own IPs + default gateways) against - # :9000/api/status and use the first one that responds 200. - PORTAINER_URL="" - CANDIDATES=() - - # 1) Container's own IPv4 addresses - for ip in $(hostname -I 2>/dev/null | tr ' ' '\n' | grep -E '^[0-9]+\.'); do - CANDIDATES+=("http://${ip}:9000") - done - - # 2) Default gateways of every default route - while IFS= read -r gw; do - [ -n "$gw" ] && CANDIDATES+=("http://${gw}:9000") - done < <(ip -4 route show default 2>/dev/null | awk '{print $3}' | sort -u) - - # 3) Fallback: secret value (in case everything else fails) - CANDIDATES+=("${{ secrets.PORTAINER_URL }}") - - echo "Candidates: ${CANDIDATES[@]}" - for url in "${CANDIDATES[@]}"; do - code=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 3 "${url}/api/status" 2>/dev/null || echo "000") - echo " probe ${url}/api/status -> ${code}" - if [ "$code" = "200" ]; then - PORTAINER_URL="$url" - echo " -> using ${PORTAINER_URL}" - break - fi - done - - if [ -z "$PORTAINER_URL" ]; then - echo "ERROR: no candidate URL reached Portainer. Tried: ${CANDIDATES[@]}" >&2 - echo "ERROR: container hostname=$(hostname) IP=$(hostname -I)" >&2 - echo "ERROR: ip route=$(ip route 2>&1 | tr '\n' ';')" >&2 + # Portainer, Gitea and the runners all share the `portainer_default` + # Docker network on the NAS, so the service name "portainer" resolves + # directly from the job container. No need for IP auto-discovery. + echo "Using PORTAINER_URL=$PORTAINER_URL" + if ! curl -sS -o /dev/null -w '%{http_code}' --max-time 5 \ + "${PORTAINER_URL}/api/status" | grep -q '^200$'; then + echo "ERROR: Portainer not reachable at $PORTAINER_URL" >&2 exit 1 fi