Skip to content

fix(adapters): support macOS hosts in port-listening probe and prevent edge container termination - #647

Open
chbndrhnns wants to merge 2 commits into
oblien:mainfrom
chbndrhnns:fix/edge-controller-port-listen-macos
Open

fix(adapters): support macOS hosts in port-listening probe and prevent edge container termination#647
chbndrhnns wants to merge 2 commits into
oblien:mainfrom
chbndrhnns:fix/edge-controller-port-listen-macos

Conversation

@chbndrhnns

Copy link
Copy Markdown
Contributor

Closes #646

Summary

On macOS / Darwin hosts (such as local self-hosted Openship servers or developer machines), the edge controller container (openship-edge) was repeatedly terminated with SIGKILL (docker rm -f) during deploys, routing retries, and reconcile passes.

The root cause was in packages/adapters/src/system/port-listen.ts:

  • The port probe command used cat /proc/net/tcp 2>/dev/null; cat /proc/net/tcp6 2>/dev/null; true.
  • On macOS hosts, /proc does not exist. The command exited 0 with an empty string "".
  • parseListeningPorts("") returned an empty set, causing probePortListeningOnce to return false (instead of null for inconclusive).
  • waitForPortListening interpreted this as a conclusive negative ({ listening: false, checked: true }).
  • ensureContainerEdge's post-start verification (verifyEdgeServing) concluded port 80 failed to bind and executed docker rm -f openship-edge in its catch block.

Changes

  • packages/adapters/src/system/port-listen.ts:
    • Replaced the hardcoded procfs command with a tiered buildPortProbeCommand(port):
      1. /proc/net/tcp{,6} on Linux / runtime containers.
      2. lsof -ti tcp:PORT -sTCP:LISTEN / lsof -ti :PORT -sTCP:LISTEN on macOS / Darwin / BSD hosts.
      3. ss -tln sport = :PORT fallback on Linux when procfs is unmounted.
      4. Explicit __UNAVAILABLE__ sentinel when no probe mechanism exists on the target.
    • Added parsePortProbeOutput(out, port):
      • Evaluates procfs headers / rows.
      • Evaluates lsof PIDs and __LISTEN__ / __FREE__ sentinels.
      • Returns null (inconclusive / checked: false) for __UNAVAILABLE__, empty output, or command errors, preventing false-negative container deletions on unmeasurable hosts.
    • Kept PROC_NET_TCP_CMD export for backwards compatibility with tests and callers.
  • packages/adapters/src/system/port-listen.test.ts:
    • Added unit tests for buildPortProbeCommand.
    • Added unit tests for parsePortProbeOutput across procfs, lsof single/multi PIDs, __FREE__, __LISTEN__, __UNAVAILABLE__, and empty output.
    • Added test cases in waitForPortListening and waitForPortFree for macOS lsof PIDs, __FREE__, and inconclusive probe handling.

Verification

  • Unit tests for port-listen.ts verified across all cases (procfs, macOS lsof, ss sentinels, inconclusive output).
  • Verified against live host executor on macOS:
    • Port 80 free: { listening: false, checked: true }
    • Port 80 with running docker container: { listening: true, checked: true }
    • Post-shutdown free verification (waitForPortFree): { free: true, checked: true }

…robe

On macOS hosts (such as local self-hosted servers or developer workstations),
/proc/net/tcp does not exist. The previous probe command executed `cat /proc/net/tcp 2>/dev/null; ...; true`,
which produced an empty string with exit code 0.

parseListeningPorts evaluated this as an empty socket table, returning false (instead of null),
causing waitForPortListening to conclude { listening: false, checked: true }.
Consequently, ensureContainerEdge concluded newly started edge containers failed to listen on :80,
threw an error, and executed docker rm -f openship-edge (killing the container with SIGKILL).

- Introduce buildPortProbeCommand and parsePortProbeOutput in port-listen.ts with tiered support:
  1. /proc/net/tcp{,6} (Linux / containers)
  2. lsof -ti tcp:PORT / lsof -ti :PORT (macOS / BSD)
  3. ss -tln sport = :PORT (Linux procfs fallback)
  4. __UNAVAILABLE__ emission yielding null (checked: false) when no probe tool exists
- Add unit tests covering parsePortProbeOutput across procfs, lsof, ss, sentinels, and waitForPortFree/waitForPortListening.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(adapters): edge controller container repeatedly killed on macOS hosts due to /proc/net/tcp port probe failure

1 participant