diff --git a/apps/api/src/api/tool_instances.py b/apps/api/src/api/tool_instances.py index 1f5df7e..0dbf789 100644 --- a/apps/api/src/api/tool_instances.py +++ b/apps/api/src/api/tool_instances.py @@ -1733,7 +1733,7 @@ async def start_instance( logger.debug( "Connecting container %s to backend network...", expected_container_name ) - connected = connect_container_to_network(expected_container_name, "backend") + connected = connect_container_to_network(expected_container_name) if connected: logger.debug( "Successfully connected %s to backend network", expected_container_name diff --git a/apps/api/src/services/docker.py b/apps/api/src/services/docker.py index f4b67fd..a4d9178 100644 --- a/apps/api/src/services/docker.py +++ b/apps/api/src/services/docker.py @@ -230,18 +230,54 @@ def get_container_name(instance_name: str) -> str | None: return None +def get_backend_network_name() -> str: + """Auto-detect the actual Docker network name for the backend network. + + Docker Compose prefixes network names with the project directory name + (e.g. 'headquarter_backend' instead of 'backend'). We inspect the API + container itself to find the real network name it's connected to. + + Returns: + The actual Docker network name, or 'backend' as fallback. + """ + # Try to find the API container by its known name + api_container = "hq-api" + result = subprocess.run( + [ + "docker", + "inspect", + "-f", + "{{range $k, $v := .NetworkSettings.Networks}}{{$k}} {{end}}", + api_container, + ], + capture_output=True, + text=True, + ) + if result.returncode == 0 and result.stdout.strip(): + networks = result.stdout.strip().split() + for net in networks: + if "backend" in net.lower(): + return net + # API container is on some network — return the first one + return networks[0] + return "backend" + + def connect_container_to_network( - container_name: str, network_name: str = "backend" + container_name: str, network_name: str | None = None ) -> bool: """Connect a Docker container to an existing network. Args: container_name: Name or ID of the container - network_name: Name of the Docker network (default: backend) + network_name: Name of the Docker network. If None, auto-detects + from the API container's own network membership. Returns: True if successful, False otherwise """ + if network_name is None: + network_name = get_backend_network_name() result = subprocess.run( ["docker", "network", "connect", network_name, container_name], capture_output=True, diff --git a/apps/api/src/services/tunnel.py b/apps/api/src/services/tunnel.py index 5432fdc..d021349 100644 --- a/apps/api/src/services/tunnel.py +++ b/apps/api/src/services/tunnel.py @@ -12,10 +12,11 @@ import re import subprocess from typing import Any +from src.services.docker import get_backend_network_name + logger = logging.getLogger(__name__) TUNNEL_IMAGE = "cloudflare/cloudflared:latest" -TUNNEL_NETWORK = "backend" def _tunnel_container_name(instance_name: str) -> str: @@ -105,7 +106,7 @@ def start_tunnel( "run", "-d", "--network", - TUNNEL_NETWORK, + get_backend_network_name(), "--name", tunnel_name, TUNNEL_IMAGE,