Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions rock-conf/rock-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ warmup:
# - "reg-a.aliyuncs.com/mirror-1"
# - "reg-b.aliyuncs.com/mirror-2"

# Server public configuration (exposed via GET /server/config)
server:
image_registries: []
# - namespace: "rock"
# registry_url: ""
# region: "cn-hangzhou"
builder_image: ""

# Scheduler configuration
scheduler:
enabled: true # Whether to enable the scheduler
Expand Down
8 changes: 8 additions & 0 deletions rock/admin/entrypoints/sandbox_proxy_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,14 @@ async def portforward(websocket: WebSocket, id: str, port: int):
await websocket.close(code=1011, reason=f"Proxy error: {str(e)}")


@sandbox_proxy_router.get("/server-config")
@handle_exceptions(error_message="get server config failed")
async def get_server_config():
"""Return server public configuration."""
result = sandbox_proxy_service.get_server_config()
return RockResponse(result=result)


@sandbox_proxy_router.get("/get_token")
@handle_exceptions(error_message="get oss sts token failed")
async def get_token(account: str = "legacy"):
Expand Down
22 changes: 22 additions & 0 deletions rock/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,25 @@ def __post_init__(self):
self.primary = OssAccountConfig(**self.primary)


@dataclass
class ImageRegistryConfig:
namespace: str = "rock"
registry_url: str | None = None
region: str | None = None


@dataclass
class ServerConfig:
image_registries: list[ImageRegistryConfig] = field(default_factory=list)
builder_image: str = ""

def __post_init__(self):
self.image_registries = [
ImageRegistryConfig(**item) if isinstance(item, dict) else item
for item in self.image_registries
]


@dataclass
class ProxyServiceConfig:
timeout: float = 180.0
Expand Down Expand Up @@ -348,6 +367,7 @@ class RockConfig:
redis: RedisConfig = field(default_factory=RedisConfig)
sandbox_config: SandboxConfig = field(default_factory=SandboxConfig)
oss: OssConfig = field(default_factory=OssConfig)
server: ServerConfig = field(default_factory=ServerConfig)
runtime: RuntimeConfig = field(default_factory=RuntimeConfig)
proxy_service: ProxyServiceConfig = field(default_factory=ProxyServiceConfig)
scheduler: SchedulerConfig = field(default_factory=SchedulerConfig)
Expand Down Expand Up @@ -401,6 +421,8 @@ def from_env(cls, config_path: str | None = None):
kwargs["sandbox_config"] = SandboxConfig(**config["sandbox_config"])
if "oss" in config:
kwargs["oss"] = OssConfig(**config["oss"])
if "server" in config:
kwargs["server"] = ServerConfig(**config["server"])
if "runtime" in config:
kwargs["runtime"] = RuntimeConfig(**config["runtime"])
if "proxy_service" in config:
Expand Down
18 changes: 17 additions & 1 deletion rock/sandbox/service/sandbox_proxy_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from rock.admin.proto.request import SandboxReadFileRequest as ReadFileRequest
from rock.admin.proto.request import SandboxWriteFileRequest as WriteFileRequest
from rock.admin.proto.response import SandboxListResponse, SandboxListStatusResponse, SandboxStatusResponse
from rock.config import OssConfig, ProxyServiceConfig, RockConfig
from rock.config import OssConfig, ProxyServiceConfig, RockConfig, ServerConfig
from rock.deployments.constants import Port
from rock.deployments.status import ServiceStatus
from rock.common.port_validation import validate_port_forward_port
Expand Down Expand Up @@ -91,6 +91,8 @@ def __init__(self, rock_config: RockConfig, meta_store: SandboxMetaStore):
primary_region,
)

self.server_config: ServerConfig = rock_config.server

self._batch_get_status_max_count = rock_config.proxy_service.batch_get_status_max_count
self._validate_oss_config_or_warn()

Expand Down Expand Up @@ -746,6 +748,20 @@ def gen_oss_sts_token(
"Prefix": prefix, # transfer-object key prefix, scoped per account
}

def get_server_config(self) -> dict:
"""Return server public configuration."""
return {
"ImageRegistries": [
{
"Namespace": r.namespace,
"RegistryUrl": r.registry_url,
"Region": r.region,
}
for r in self.server_config.image_registries
],
"BuilderImage": self.server_config.builder_image,
}

async def get_sandbox_websocket_url(
self, sandbox_id: str, target_path: str | None = None, port: int | None = None
) -> str:
Expand Down
35 changes: 34 additions & 1 deletion tests/unit/sandbox/test_sandbox_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pytest

from rock.actions.sandbox.response import State
from rock.config import OssConfig
from rock.config import ImageRegistryConfig, OssConfig, ServerConfig
from rock.deployments.config import DockerDeploymentConfig
from rock.sandbox.sandbox_manager import SandboxManager
from rock.sandbox.service.sandbox_proxy_service import SandboxProxyService
Expand Down Expand Up @@ -208,3 +208,36 @@ def test_yaml_used_when_env_var_empty(self, sandbox_proxy_service):
assert result["Endpoint"] == "yaml.endpoint" # YAML fallback
assert result["Bucket"] == "yaml-bucket"
assert result["Region"] == "rg" # env


class TestGetServerConfig:
@pytest.fixture
def proxy_service(self):
service = SandboxProxyService.__new__(SandboxProxyService)
service.server_config = ServerConfig(
image_registries=[
ImageRegistryConfig(namespace="ns-1", registry_url="reg1.example.com", region="cn-hangzhou"),
ImageRegistryConfig(namespace="ns-2", registry_url="reg2.example.com", region="ap-southeast-1"),
],
builder_image="builder:latest",
)
return service

def test_returns_public_config(self, proxy_service):
result = proxy_service.get_server_config()

assert len(result["ImageRegistries"]) == 2
assert result["ImageRegistries"][0]["Namespace"] == "ns-1"
assert result["ImageRegistries"][0]["RegistryUrl"] == "reg1.example.com"
assert result["ImageRegistries"][1]["Namespace"] == "ns-2"
assert result["ImageRegistries"][1]["Region"] == "ap-southeast-1"
assert result["BuilderImage"] == "builder:latest"

def test_empty_registries(self):
service = SandboxProxyService.__new__(SandboxProxyService)
service.server_config = ServerConfig()

result = service.get_server_config()

assert result["ImageRegistries"] == []
assert result["BuilderImage"] == ""
Loading