fix: cloudflare tunnel connects to localhost:host_port instead of container_name:container_port
Root cause: start_cloudflared_tunnel was trying to connect to http://{container_name}:{container_port}, but: 1. The host OS cannot resolve Docker container names 2. cloudflared runs on the host, so it needs the host-mapped port Changes: - start_cloudflared_tunnel: changed signature to accept host_port only - Connects cloudflared to localhost:{host_port} via Docker port mapping - Connectivity check uses localhost:{host_port} - recreate_tunnel updated to match new signature - Callers in tool_instances.py pass instance.port (host port) Quality gates: pytest 42 passed
This commit is contained in:
@@ -385,16 +385,15 @@ def find_free_port(start: int = 10000, end: int = 20000) -> int:
|
||||
|
||||
|
||||
def start_cloudflared_tunnel(
|
||||
container_name: str, port: int, timeout: int = 30
|
||||
host_port: int, timeout: int = 30
|
||||
) -> dict[str, str]:
|
||||
"""Start a temporary Cloudflare tunnel for a container.
|
||||
"""Start a temporary Cloudflare tunnel to localhost.
|
||||
|
||||
Uses 'cloudflared tunnel --url' to create a temporary tunnel
|
||||
with a random trycloudflare.com URL.
|
||||
|
||||
Args:
|
||||
container_name: Name of the Docker container to tunnel to
|
||||
port: Port number the container listens on
|
||||
host_port: Host-mapped port number (e.g. from find_free_port)
|
||||
timeout: Maximum seconds to wait for tunnel URL
|
||||
|
||||
Returns:
|
||||
@@ -405,8 +404,8 @@ def start_cloudflared_tunnel(
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# First verify the container is accessible
|
||||
logger.info("Checking connectivity to %s:%d...", container_name, port)
|
||||
# First verify the container is accessible via the host-mapped port
|
||||
logger.info("Checking connectivity to localhost:%d...", host_port)
|
||||
for attempt in range(10):
|
||||
check = subprocess.run(
|
||||
[
|
||||
@@ -416,7 +415,7 @@ def start_cloudflared_tunnel(
|
||||
"/dev/null",
|
||||
"-w",
|
||||
"%{http_code}",
|
||||
f"http://{container_name}:{port}",
|
||||
f"http://localhost:{host_port}",
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
@@ -430,13 +429,13 @@ def start_cloudflared_tunnel(
|
||||
time.sleep(1)
|
||||
else:
|
||||
logger.warning(
|
||||
"Container %s:%d not responding to curl checks", container_name, port
|
||||
"localhost:%d not responding to curl checks", host_port
|
||||
)
|
||||
|
||||
# Run cloudflared in background, capture output
|
||||
logger.info("Starting cloudflared tunnel to http://%s:%d", container_name, port)
|
||||
logger.info("Starting cloudflared tunnel to http://localhost:%d", host_port)
|
||||
proc = subprocess.Popen(
|
||||
["cloudflared", "tunnel", "--url", f"http://{container_name}:{port}"],
|
||||
["cloudflared", "tunnel", "--url", f"http://localhost:{host_port}"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
@@ -491,15 +490,14 @@ def stop_cloudflared_tunnel(pid: str) -> None:
|
||||
|
||||
|
||||
def recreate_tunnel(
|
||||
container_name: str, port: int, old_pid: str | None = None
|
||||
host_port: int, old_pid: str | None = None
|
||||
) -> dict[str, str]:
|
||||
"""Recreate a temporary Cloudflare tunnel.
|
||||
|
||||
Stops the old tunnel (if pid provided) and starts a new one.
|
||||
|
||||
Args:
|
||||
container_name: Name of the Docker container to tunnel to
|
||||
port: Port number the container listens on
|
||||
host_port: Host-mapped port number (e.g. from find_free_port)
|
||||
old_pid: Optional PID of the old tunnel process to stop
|
||||
|
||||
Returns:
|
||||
@@ -508,7 +506,7 @@ def recreate_tunnel(
|
||||
if old_pid:
|
||||
stop_cloudflared_tunnel(old_pid)
|
||||
|
||||
return start_cloudflared_tunnel(container_name, port)
|
||||
return start_cloudflared_tunnel(host_port)
|
||||
|
||||
|
||||
def check_tunnel_health(url: str, timeout: int = 10) -> dict[str, Any]:
|
||||
|
||||
@@ -120,9 +120,9 @@ async def publish_lifecycle_event(
|
||||
# Create notification for instance owner (fire-and-forget)
|
||||
# Skip intermediate "starting" notifications — only notify on terminal states
|
||||
# (failed or successful attempts)
|
||||
_is_starting_intermediate = event_type == "instance.started" and (
|
||||
status or instance.status
|
||||
) == "starting"
|
||||
_is_starting_intermediate = (
|
||||
event_type == "instance.started" and (status or instance.status) == "starting"
|
||||
)
|
||||
if _is_starting_intermediate:
|
||||
return
|
||||
|
||||
|
||||
Reference in New Issue
Block a user