fix: recreate tunnel uses container IP directly for reliable connectivity
Old instances may have auto-generated Docker Compose container names that don't match instance.name.lower(), causing DNS resolution failures for the tunnel. Also, old instances may not be on the backend network. - apps/api/src/services/docker.py: add get_container_ip_on_network() and is_container_on_network() helpers - apps/api/src/services/tunnel.py: start_tunnel() and recreate_tunnel() now accept an optional target_url parameter to override the default name-based URL - apps/api/src/api/tool_instances.py: recreate_tunnel_endpoint now: 1. Looks up the tool container (by stored container_id or name) 2. Ensures it's connected to the backend network 3. Gets the container's IP on that network 4. Passes the IP as the explicit tunnel target This guarantees the tunnel can reach the tool container regardless of naming or network state. Quality gates: ruff clean
This commit is contained in:
@@ -45,13 +45,16 @@ from src.services.config_profile_resolver import (
|
||||
resolve_profile,
|
||||
)
|
||||
from src.services.docker import (
|
||||
connect_container_to_network,
|
||||
ensure_instance_directory,
|
||||
execute_compose_command,
|
||||
find_free_port,
|
||||
get_backend_network_name,
|
||||
get_container_id,
|
||||
get_container_ip_on_network,
|
||||
get_container_logs,
|
||||
get_container_status,
|
||||
is_container_on_network,
|
||||
render_compose_template,
|
||||
sort_volumes_by_specificity,
|
||||
wait_for_container_running,
|
||||
@@ -2459,10 +2462,56 @@ async def recreate_tunnel_endpoint(
|
||||
detail="Tool type not found for this instance",
|
||||
)
|
||||
|
||||
# Find the tool container — try stored ID first, then fall back to name lookup
|
||||
tool_container_id = instance.container_id
|
||||
if not tool_container_id:
|
||||
tool_container_id = get_container_id(instance.name.lower())
|
||||
|
||||
if not tool_container_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Could not find running container for this instance",
|
||||
)
|
||||
|
||||
# Ensure the tool container is on the backend network so the tunnel can reach it
|
||||
network_name = get_backend_network_name()
|
||||
if not is_container_on_network(tool_container_id, network_name):
|
||||
logger.debug(
|
||||
"Connecting container %s to network %s for tunnel access",
|
||||
tool_container_id,
|
||||
network_name,
|
||||
)
|
||||
connected = connect_container_to_network(tool_container_id, network_name)
|
||||
if not connected:
|
||||
logger.warning(
|
||||
"Failed to connect container %s to network %s",
|
||||
tool_container_id,
|
||||
network_name,
|
||||
)
|
||||
|
||||
# Use the container's IP on the backend network as the tunnel target.
|
||||
# This is more reliable than name-based DNS, especially for old instances
|
||||
# whose container name may differ from instance.name.lower().
|
||||
target_ip = get_container_ip_on_network(tool_container_id, network_name)
|
||||
if target_ip:
|
||||
target_url = f"http://{target_ip}:{tool_type.default_port or 0}"
|
||||
logger.debug(
|
||||
"Using container IP %s as tunnel target for instance %s",
|
||||
target_ip,
|
||||
instance.id,
|
||||
)
|
||||
else:
|
||||
target_url = None
|
||||
logger.warning(
|
||||
"Could not get container IP for %s, falling back to name resolution",
|
||||
tool_container_id,
|
||||
)
|
||||
|
||||
try:
|
||||
tunnel_info = recreate_tunnel(
|
||||
instance_name=instance.name,
|
||||
container_port=tool_type.default_port or 0,
|
||||
target_url=target_url,
|
||||
)
|
||||
instance.tunnel_id = tunnel_info["container_name"]
|
||||
instance.public_url = tunnel_info["url"]
|
||||
|
||||
Reference in New Issue
Block a user