fix(proxy): use internal container port instead of host port
The proxy was using instance.port which is a dynamically allocated host port (e.g., 10001). But containers communicate on the Docker network using their internal ports (8443 for code-server, 8888 for jupyter). This caused connection failures when opening instances. - Add default_port field to ToolType model (null for terminal-only tools) - Create migration 0010 for default_port column - Update seed data: code-server=8443, jupyter=8888, opencode=null - Update proxy to use tool type's default_port instead of instance.port - Update frontend ToolType interface to include default_port Fixes: Opening instances now routes to correct internal container port
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
"""add default_port to tool_types
|
||||
|
||||
Revision ID: 0010_tool_type_default_port
|
||||
Revises: 0009_tool_configs
|
||||
Create Date: 2026-05-20 10:00:00.000000
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "0010_tool_type_default_port"
|
||||
down_revision: Union[str, None] = "0009_tool_configs"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column(
|
||||
"tool_types",
|
||||
sa.Column("default_port", sa.Integer(), nullable=True)
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("tool_types", "default_port")
|
||||
@@ -10,6 +10,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from src.auth.dependencies import get_current_user_id, get_db_session
|
||||
from src.models.tool_instance import ToolInstance
|
||||
from src.models.tool_type import ToolType
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -43,8 +44,12 @@ async def _proxy_request(
|
||||
detail="instance is not running",
|
||||
)
|
||||
|
||||
# Build target URL
|
||||
target_url = f"http://{instance.container_name}:{instance.port}"
|
||||
# Get the tool type to find the internal port
|
||||
tool_type = await session.get(ToolType, instance.tool_type_id)
|
||||
internal_port = tool_type.default_port if tool_type and tool_type.default_port else instance.port
|
||||
|
||||
# Build target URL using internal port
|
||||
target_url = f"http://{instance.container_name}:{internal_port}"
|
||||
if path:
|
||||
target_url += f"/{path}"
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ class ToolTypeCreate(BaseModel):
|
||||
name: str
|
||||
display_name: str
|
||||
description: str | None = None
|
||||
default_port: int | None = None
|
||||
compose_template: str
|
||||
required_variables: list[str] = []
|
||||
|
||||
@@ -117,6 +118,7 @@ class ToolTypeResponse(BaseModel):
|
||||
description: str | None
|
||||
category: str
|
||||
interfaces: list[str]
|
||||
default_port: int | None
|
||||
compose_template: str
|
||||
required_variables: list[str]
|
||||
is_builtin: bool
|
||||
@@ -159,6 +161,7 @@ async def create_tool_type(
|
||||
name=data.name,
|
||||
display_name=data.display_name,
|
||||
description=data.description,
|
||||
default_port=data.default_port,
|
||||
compose_template=data.compose_template,
|
||||
required_variables=data.required_variables,
|
||||
is_builtin=False,
|
||||
|
||||
@@ -123,6 +123,7 @@ services:
|
||||
ports:
|
||||
- "8443:8443"
|
||||
restart: unless-stopped""",
|
||||
"default_port": 8443,
|
||||
"required_variables": ["REPO_PATH", "TOOL_NAME"],
|
||||
},
|
||||
{
|
||||
@@ -131,6 +132,7 @@ services:
|
||||
"description": "Jupyter Lab for interactive development",
|
||||
"category": "notebook",
|
||||
"interfaces": ["web"],
|
||||
"default_port": 8888,
|
||||
"compose_template": """version: "3.8"
|
||||
services:
|
||||
jupyter:
|
||||
@@ -187,6 +189,7 @@ volumes:
|
||||
interfaces=tool_data["interfaces"],
|
||||
compose_template=tool_data["compose_template"],
|
||||
required_variables=tool_data["required_variables"],
|
||||
default_port=tool_data.get("default_port"),
|
||||
is_builtin=True,
|
||||
)
|
||||
session.add(tool_type)
|
||||
|
||||
@@ -19,6 +19,7 @@ class ToolType(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
||||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
category: Mapped[str] = mapped_column(String(50), nullable=False, default="other")
|
||||
interfaces: Mapped[list[str]] = mapped_column(JSON, default=list, nullable=False)
|
||||
default_port: Mapped[int | None] = mapped_column(nullable=True)
|
||||
compose_template: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
required_variables: Mapped[list[str]] = mapped_column(JSON, default=list, nullable=False)
|
||||
is_builtin: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
||||
|
||||
Reference in New Issue
Block a user