From 6565f5d94686ecfc40948cbdcaa049fabbc69f8d Mon Sep 17 00:00:00 2001 From: Jvst Me Date: Fri, 27 Sep 2024 15:07:36 +0200 Subject: [PATCH] dstack-proxy naming tweaks - Rename the new software component responsible for proxying to dstack-proxy and drop the terms "gateway-in-server" and "remote gateway". Once this component is ready to run both in-server and on a gateway instance, the word "gateway" will only refer to gateway instances. - Move the in-server service proxy router from /gateway/services to /services - Add a few docstrings and missing __init__ files --- src/dstack/_internal/gateway/deps.py | 35 ----------- .../_internal/gateway/routers/__init__.py | 0 .../_internal/gateway/services/__init__.py | 0 src/dstack/_internal/proxy/__init__.py | 8 +++ src/dstack/_internal/proxy/deps.py | 36 ++++++++++++ src/dstack/_internal/proxy/repos/__init__.py | 1 + .../{gateway => proxy}/repos/base.py | 2 +- .../{gateway => proxy}/repos/memory.py | 4 +- .../_internal/proxy/routers/__init__.py | 1 + .../routers/service_proxy.py | 8 +-- .../_internal/proxy/services/__init__.py | 1 + .../services/service_connection.py | 2 +- .../services/service_proxy.py | 8 +-- src/dstack/_internal/server/app.py | 30 +++++----- .../services/gateway_in_server/__init__.py | 0 .../server/services/gateway_in_server/deps.py | 12 ---- .../server/services/proxy/__init__.py | 3 + .../_internal/server/services/proxy/deps.py | 12 ++++ .../{gateway_in_server => proxy}/repo.py | 11 ++-- src/dstack/_internal/settings.py | 2 +- .../_internal/proxy}/__init__.py | 0 .../routers/test_service_proxy.py | 58 +++++++++---------- 22 files changed, 124 insertions(+), 110 deletions(-) delete mode 100644 src/dstack/_internal/gateway/deps.py delete mode 100644 src/dstack/_internal/gateway/routers/__init__.py delete mode 100644 src/dstack/_internal/gateway/services/__init__.py create mode 100644 src/dstack/_internal/proxy/__init__.py create mode 100644 src/dstack/_internal/proxy/deps.py create mode 100644 src/dstack/_internal/proxy/repos/__init__.py rename src/dstack/_internal/{gateway => proxy}/repos/base.py (97%) rename src/dstack/_internal/{gateway => proxy}/repos/memory.py (84%) create mode 100644 src/dstack/_internal/proxy/routers/__init__.py rename src/dstack/_internal/{gateway => proxy}/routers/service_proxy.py (79%) create mode 100644 src/dstack/_internal/proxy/services/__init__.py rename src/dstack/_internal/{gateway => proxy}/services/service_connection.py (98%) rename src/dstack/_internal/{gateway => proxy}/services/service_proxy.py (96%) delete mode 100644 src/dstack/_internal/server/services/gateway_in_server/__init__.py delete mode 100644 src/dstack/_internal/server/services/gateway_in_server/deps.py create mode 100644 src/dstack/_internal/server/services/proxy/__init__.py create mode 100644 src/dstack/_internal/server/services/proxy/deps.py rename src/dstack/_internal/server/services/{gateway_in_server => proxy}/repo.py (89%) rename src/{dstack/_internal/gateway/repos => tests/_internal/proxy}/__init__.py (100%) rename src/tests/_internal/{gateway => proxy}/routers/test_service_proxy.py (76%) diff --git a/src/dstack/_internal/gateway/deps.py b/src/dstack/_internal/gateway/deps.py deleted file mode 100644 index e0cc30b25..000000000 --- a/src/dstack/_internal/gateway/deps.py +++ /dev/null @@ -1,35 +0,0 @@ -from abc import ABC, abstractmethod -from typing import AsyncGenerator - -from fastapi import Depends, Request -from typing_extensions import Annotated - -from dstack._internal.gateway.repos.base import BaseGatewayRepo - - -class BaseGatewayDependencyInjector(ABC): - """ - The gateway uses different implementations of this injector in different - environments: in-serer and on a remote host. An instance with the injector interface - stored in FastAPI's app.state.gateway_dependency_injector configures the gateway to - use a specific set of dependencies, e.g. a specific repo implementation. - """ - - @abstractmethod - async def get_repo(self) -> AsyncGenerator[BaseGatewayRepo, None]: - if False: - yield # show type checkers this is a generator - - -async def get_injector(request: Request) -> BaseGatewayDependencyInjector: - injector = request.app.state.gateway_dependency_injector - if not isinstance(injector, BaseGatewayDependencyInjector): - raise RuntimeError(f"Wrong BaseGatewayDependencyInjector type {type(injector)}") - return injector - - -async def get_gateway_repo( - injector: Annotated[BaseGatewayDependencyInjector, Depends(get_injector)], -) -> AsyncGenerator[BaseGatewayRepo, None]: - async for repo in injector.get_repo(): - yield repo diff --git a/src/dstack/_internal/gateway/routers/__init__.py b/src/dstack/_internal/gateway/routers/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/dstack/_internal/gateway/services/__init__.py b/src/dstack/_internal/gateway/services/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/dstack/_internal/proxy/__init__.py b/src/dstack/_internal/proxy/__init__.py new file mode 100644 index 000000000..a3e31886b --- /dev/null +++ b/src/dstack/_internal/proxy/__init__.py @@ -0,0 +1,8 @@ +""" +dstack-proxy is a component responsible for proxying ingress HTTP traffic to +services and models hosted by dstack. It can also perform load balancing, +collect service usage stats, obtain SSL certificates, etc. + +This component can run as a standalone web application on a gateway instance or +as part of the dstack-server web application. +""" diff --git a/src/dstack/_internal/proxy/deps.py b/src/dstack/_internal/proxy/deps.py new file mode 100644 index 000000000..36bd17b14 --- /dev/null +++ b/src/dstack/_internal/proxy/deps.py @@ -0,0 +1,36 @@ +from abc import ABC, abstractmethod +from typing import AsyncGenerator + +from fastapi import Depends, Request +from typing_extensions import Annotated + +from dstack._internal.proxy.repos.base import BaseProxyRepo + + +class BaseProxyDependencyInjector(ABC): + """ + dstack-proxy uses different implementations of this injector in different + environments: within dstack-serer and on a gateway instance. An object with + the injector interface stored in FastAPI's + app.state.proxy_dependency_injector configures dstack-proxy to use a + specific set of dependencies, e.g. a specific repo implementation. + """ + + @abstractmethod + async def get_repo(self) -> AsyncGenerator[BaseProxyRepo, None]: + if False: + yield # show type checkers this is a generator + + +async def get_injector(request: Request) -> BaseProxyDependencyInjector: + injector = request.app.state.proxy_dependency_injector + if not isinstance(injector, BaseProxyDependencyInjector): + raise RuntimeError(f"Wrong BaseProxyDependencyInjector type {type(injector)}") + return injector + + +async def get_proxy_repo( + injector: Annotated[BaseProxyDependencyInjector, Depends(get_injector)], +) -> AsyncGenerator[BaseProxyRepo, None]: + async for repo in injector.get_repo(): + yield repo diff --git a/src/dstack/_internal/proxy/repos/__init__.py b/src/dstack/_internal/proxy/repos/__init__.py new file mode 100644 index 000000000..1e969fcdf --- /dev/null +++ b/src/dstack/_internal/proxy/repos/__init__.py @@ -0,0 +1 @@ +"""dstack-proxy data access layer""" diff --git a/src/dstack/_internal/gateway/repos/base.py b/src/dstack/_internal/proxy/repos/base.py similarity index 97% rename from src/dstack/_internal/gateway/repos/base.py rename to src/dstack/_internal/proxy/repos/base.py index 14311ef69..2da002f2c 100644 --- a/src/dstack/_internal/gateway/repos/base.py +++ b/src/dstack/_internal/proxy/repos/base.py @@ -26,7 +26,7 @@ class Project(BaseModel): ssh_private_key: str -class BaseGatewayRepo(ABC): +class BaseProxyRepo(ABC): @abstractmethod async def get_service(self, project_name: str, run_name: str) -> Optional[Service]: pass diff --git a/src/dstack/_internal/gateway/repos/memory.py b/src/dstack/_internal/proxy/repos/memory.py similarity index 84% rename from src/dstack/_internal/gateway/repos/memory.py rename to src/dstack/_internal/proxy/repos/memory.py index 22014911c..7b36ad881 100644 --- a/src/dstack/_internal/gateway/repos/memory.py +++ b/src/dstack/_internal/proxy/repos/memory.py @@ -1,9 +1,9 @@ from typing import Dict, Optional -from dstack._internal.gateway.repos.base import BaseGatewayRepo, Project, Service +from dstack._internal.proxy.repos.base import BaseProxyRepo, Project, Service -class InMemoryGatewayRepo(BaseGatewayRepo): +class InMemoryProxyRepo(BaseProxyRepo): def __init__(self) -> None: self.services: Dict[str, Dict[str, Service]] = {} self.projects: Dict[str, Project] = {} diff --git a/src/dstack/_internal/proxy/routers/__init__.py b/src/dstack/_internal/proxy/routers/__init__.py new file mode 100644 index 000000000..d57010d55 --- /dev/null +++ b/src/dstack/_internal/proxy/routers/__init__.py @@ -0,0 +1 @@ +"""dstack-proxy web endpoints""" diff --git a/src/dstack/_internal/gateway/routers/service_proxy.py b/src/dstack/_internal/proxy/routers/service_proxy.py similarity index 79% rename from src/dstack/_internal/gateway/routers/service_proxy.py rename to src/dstack/_internal/proxy/routers/service_proxy.py index 235b822af..6d9cf0b04 100644 --- a/src/dstack/_internal/gateway/routers/service_proxy.py +++ b/src/dstack/_internal/proxy/routers/service_proxy.py @@ -3,9 +3,9 @@ from fastapi.responses import RedirectResponse, Response from typing_extensions import Annotated -from dstack._internal.gateway.deps import get_gateway_repo -from dstack._internal.gateway.repos.base import BaseGatewayRepo -from dstack._internal.gateway.services import service_proxy +from dstack._internal.proxy.deps import get_proxy_repo +from dstack._internal.proxy.repos.base import BaseProxyRepo +from dstack._internal.proxy.services import service_proxy REDIRECTED_HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD"] PROXIED_HTTP_METHODS = REDIRECTED_HTTP_METHODS + ["OPTIONS"] @@ -27,7 +27,7 @@ async def service_reverse_proxy( run_name: str, path: str, request: Request, - repo: Annotated[BaseGatewayRepo, Depends(get_gateway_repo)], + repo: Annotated[BaseProxyRepo, Depends(get_proxy_repo)], ) -> Response: return await service_proxy.proxy(project_name, run_name, path, request, repo) diff --git a/src/dstack/_internal/proxy/services/__init__.py b/src/dstack/_internal/proxy/services/__init__.py new file mode 100644 index 000000000..997972eee --- /dev/null +++ b/src/dstack/_internal/proxy/services/__init__.py @@ -0,0 +1 @@ +"""dstack-proxy business logic layer""" diff --git a/src/dstack/_internal/gateway/services/service_connection.py b/src/dstack/_internal/proxy/services/service_connection.py similarity index 98% rename from src/dstack/_internal/gateway/services/service_connection.py rename to src/dstack/_internal/proxy/services/service_connection.py index 14197d66c..f2e02e397 100644 --- a/src/dstack/_internal/gateway/services/service_connection.py +++ b/src/dstack/_internal/proxy/services/service_connection.py @@ -12,7 +12,7 @@ SSHTunnel, UnixSocket, ) -from dstack._internal.gateway.repos.base import Project, Replica, Service +from dstack._internal.proxy.repos.base import Project, Replica, Service from dstack._internal.utils.logging import get_logger from dstack._internal.utils.path import FileContent diff --git a/src/dstack/_internal/gateway/services/service_proxy.py b/src/dstack/_internal/proxy/services/service_proxy.py similarity index 96% rename from src/dstack/_internal/gateway/services/service_proxy.py rename to src/dstack/_internal/proxy/services/service_proxy.py index 40a6e3273..9910370b9 100644 --- a/src/dstack/_internal/gateway/services/service_proxy.py +++ b/src/dstack/_internal/proxy/services/service_proxy.py @@ -5,8 +5,8 @@ import httpx from starlette.requests import ClientDisconnect -from dstack._internal.gateway.repos.base import BaseGatewayRepo, Replica, Service -from dstack._internal.gateway.services.service_connection import service_replica_connection_pool +from dstack._internal.proxy.repos.base import BaseProxyRepo, Replica, Service +from dstack._internal.proxy.services.service_connection import service_replica_connection_pool from dstack._internal.utils.logging import get_logger logger = get_logger(__name__) @@ -17,7 +17,7 @@ async def proxy( run_name: str, path: str, request: fastapi.Request, - repo: BaseGatewayRepo, + repo: BaseProxyRepo, ) -> fastapi.responses.Response: if "Upgrade" in request.headers: raise fastapi.exceptions.HTTPException( @@ -72,7 +72,7 @@ async def proxy( async def get_replica_client( - project_name: str, service: Service, replica: Replica, repo: BaseGatewayRepo + project_name: str, service: Service, replica: Replica, repo: BaseProxyRepo ) -> httpx.AsyncClient: connection = await service_replica_connection_pool.get(replica.id) if connection is None: diff --git a/src/dstack/_internal/server/app.py b/src/dstack/_internal/server/app.py index f92390b0d..02adc3238 100644 --- a/src/dstack/_internal/server/app.py +++ b/src/dstack/_internal/server/app.py @@ -14,8 +14,8 @@ from dstack._internal.cli.utils.common import console from dstack._internal.core.errors import ForbiddenError, ServerClientError from dstack._internal.core.services.configs import update_default_project -from dstack._internal.gateway.routers import service_proxy -from dstack._internal.gateway.services.service_connection import service_replica_connection_pool +from dstack._internal.proxy.routers import service_proxy +from dstack._internal.proxy.services.service_connection import service_replica_connection_pool from dstack._internal.server import settings from dstack._internal.server.background import start_background_tasks from dstack._internal.server.db import get_db, get_session_ctx, migrate @@ -34,12 +34,12 @@ volumes, ) from dstack._internal.server.services.config import ServerConfigManager -from dstack._internal.server.services.gateway_in_server.deps import ( - GatewayInServerDependencyInjector, -) from dstack._internal.server.services.gateways import gateway_connections_pool, init_gateways from dstack._internal.server.services.locking import advisory_lock_ctx from dstack._internal.server.services.projects import get_or_create_default_project +from dstack._internal.server.services.proxy.deps import ( + ServerProxyDependencyInjector, +) from dstack._internal.server.services.storage import init_default_storage from dstack._internal.server.services.users import get_or_create_admin_user from dstack._internal.server.settings import ( @@ -74,7 +74,7 @@ def create_app() -> FastAPI: ) app = FastAPI(docs_url="/api/docs", lifespan=lifespan) - app.state.gateway_dependency_injector = GatewayInServerDependencyInjector() + app.state.proxy_dependency_injector = ServerProxyDependencyInjector() return app @@ -174,10 +174,8 @@ def register_routes(app: FastAPI, ui: bool = True): app.include_router(gateways.router) app.include_router(volumes.root_router) app.include_router(volumes.project_router) - if FeatureFlags.GATEWAY_IN_SERVER: - app.include_router( - service_proxy.router, prefix="/gateway/services", tags=["gateway-in-server"] - ) + if FeatureFlags.PROXY: + app.include_router(service_proxy.router, prefix="/services", tags=["service-proxy"]) @app.exception_handler(ForbiddenError) async def forbidden_error_handler(request: Request, exc: ForbiddenError): @@ -243,8 +241,8 @@ async def healthcheck(): async def custom_http_exception_handler(request, exc): if ( request.url.path.startswith("/api") - or FeatureFlags.GATEWAY_IN_SERVER - and _is_gateway_in_server_request(request) + or FeatureFlags.PROXY + and _is_proxied_service_request(request) ): return JSONResponse( {"detail": exc.detail}, @@ -264,16 +262,16 @@ async def index(): return RedirectResponse("/api/docs") -def _is_gateway_in_server_request(request: Request) -> bool: - if request.url.path.startswith("/gateway"): +def _is_proxied_service_request(request: Request) -> bool: + if request.url.path.startswith("/services"): return True - # Attempt detecting requests originating from services served by gateway-in-server. + # Attempt detecting requests originating from services proxied by dstack-proxy. # Such requests can "leak" to dstack server paths if the service does not support # running under a path prefix properly. referrer = URL(request.headers.get("Referer", "")) return ( referrer.netloc == "" or referrer.netloc == request.url.netloc - ) and referrer.path.startswith("/gateway/services") + ) and referrer.path.startswith("/services") def _print_dstack_logo(): diff --git a/src/dstack/_internal/server/services/gateway_in_server/__init__.py b/src/dstack/_internal/server/services/gateway_in_server/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/dstack/_internal/server/services/gateway_in_server/deps.py b/src/dstack/_internal/server/services/gateway_in_server/deps.py deleted file mode 100644 index a170f1dde..000000000 --- a/src/dstack/_internal/server/services/gateway_in_server/deps.py +++ /dev/null @@ -1,12 +0,0 @@ -from typing import AsyncGenerator - -from dstack._internal.gateway.deps import BaseGatewayDependencyInjector -from dstack._internal.gateway.repos.base import BaseGatewayRepo -from dstack._internal.server.db import get_session_ctx -from dstack._internal.server.services.gateway_in_server.repo import DBGatewayRepo - - -class GatewayInServerDependencyInjector(BaseGatewayDependencyInjector): - async def get_repo(self) -> AsyncGenerator[BaseGatewayRepo, None]: - async with get_session_ctx() as session: - yield DBGatewayRepo(session) diff --git a/src/dstack/_internal/server/services/proxy/__init__.py b/src/dstack/_internal/server/services/proxy/__init__.py new file mode 100644 index 000000000..4b503cbfa --- /dev/null +++ b/src/dstack/_internal/server/services/proxy/__init__.py @@ -0,0 +1,3 @@ +""" +Dependencies for dstack-proxy that allow it to run as part of dstack-server. +""" diff --git a/src/dstack/_internal/server/services/proxy/deps.py b/src/dstack/_internal/server/services/proxy/deps.py new file mode 100644 index 000000000..19dd0135e --- /dev/null +++ b/src/dstack/_internal/server/services/proxy/deps.py @@ -0,0 +1,12 @@ +from typing import AsyncGenerator + +from dstack._internal.proxy.deps import BaseProxyDependencyInjector +from dstack._internal.proxy.repos.base import BaseProxyRepo +from dstack._internal.server.db import get_session_ctx +from dstack._internal.server.services.proxy.repo import DBProxyRepo + + +class ServerProxyDependencyInjector(BaseProxyDependencyInjector): + async def get_repo(self) -> AsyncGenerator[BaseProxyRepo, None]: + async with get_session_ctx() as session: + yield DBProxyRepo(session) diff --git a/src/dstack/_internal/server/services/gateway_in_server/repo.py b/src/dstack/_internal/server/services/proxy/repo.py similarity index 89% rename from src/dstack/_internal/server/services/gateway_in_server/repo.py rename to src/dstack/_internal/server/services/proxy/repo.py index 3db7e70d3..aa863c8f5 100644 --- a/src/dstack/_internal/server/services/gateway_in_server/repo.py +++ b/src/dstack/_internal/server/services/proxy/repo.py @@ -8,15 +8,16 @@ from dstack._internal.core.models.configurations import ServiceConfiguration from dstack._internal.core.models.instances import SSHConnectionParams from dstack._internal.core.models.runs import JobProvisioningData, JobStatus, RunSpec -from dstack._internal.gateway.repos.base import BaseGatewayRepo, Project, Replica, Service +from dstack._internal.proxy.repos.base import BaseProxyRepo, Project, Replica, Service from dstack._internal.server.models import JobModel, ProjectModel -class DBGatewayRepo(BaseGatewayRepo): +class DBProxyRepo(BaseProxyRepo): """ - A gateway repo implementation used for gateway-in-server that retrieves data from - dstack-server's database. Since the database is populated by dstack-server, all or - most writer methods in this implementation are expected to be empty. + A repo implementation used by dstack-proxy running within dstack-server. + Retrieves data from dstack-server's database. Since the database is + populated by dstack-server, all or most writer methods in this + implementation are expected to be empty. """ def __init__(self, session: AsyncSession) -> None: diff --git a/src/dstack/_internal/settings.py b/src/dstack/_internal/settings.py index fbce18127..5479da8e6 100644 --- a/src/dstack/_internal/settings.py +++ b/src/dstack/_internal/settings.py @@ -14,4 +14,4 @@ class FeatureFlags: development. Feature flags are environment variables of the form DSTACK_FF_* """ - GATEWAY_IN_SERVER = bool(os.getenv("DSTACK_FF_GATEWAY_IN_SERVER")) + PROXY = bool(os.getenv("DSTACK_FF_PROXY")) diff --git a/src/dstack/_internal/gateway/repos/__init__.py b/src/tests/_internal/proxy/__init__.py similarity index 100% rename from src/dstack/_internal/gateway/repos/__init__.py rename to src/tests/_internal/proxy/__init__.py diff --git a/src/tests/_internal/gateway/routers/test_service_proxy.py b/src/tests/_internal/proxy/routers/test_service_proxy.py similarity index 76% rename from src/tests/_internal/gateway/routers/test_service_proxy.py rename to src/tests/_internal/proxy/routers/test_service_proxy.py index 3236df05f..3299c59f3 100644 --- a/src/tests/_internal/gateway/routers/test_service_proxy.py +++ b/src/tests/_internal/proxy/routers/test_service_proxy.py @@ -5,20 +5,20 @@ import pytest from fastapi import FastAPI -from dstack._internal.gateway.deps import BaseGatewayDependencyInjector -from dstack._internal.gateway.repos.base import BaseGatewayRepo, Project, Replica, Service -from dstack._internal.gateway.repos.memory import InMemoryGatewayRepo -from dstack._internal.gateway.routers.service_proxy import router +from dstack._internal.proxy.deps import BaseProxyDependencyInjector +from dstack._internal.proxy.repos.base import BaseProxyRepo, Project, Replica, Service +from dstack._internal.proxy.repos.memory import InMemoryProxyRepo +from dstack._internal.proxy.routers.service_proxy import router -def make_app(repo: BaseGatewayRepo) -> FastAPI: - class DependencyInjector(BaseGatewayDependencyInjector): - async def get_repo(self) -> AsyncGenerator[BaseGatewayRepo, None]: +def make_app(repo: BaseProxyRepo) -> FastAPI: + class DependencyInjector(BaseProxyDependencyInjector): + async def get_repo(self) -> AsyncGenerator[BaseProxyRepo, None]: yield repo app = FastAPI() - app.state.gateway_dependency_injector = DependencyInjector() - app.include_router(router, prefix="/gateway/services") + app.state.proxy_dependency_injector = DependencyInjector() + app.include_router(router, prefix="/services") return app @@ -26,7 +26,7 @@ def make_client(app: FastAPI) -> httpx.AsyncClient: return httpx.AsyncClient(transport=httpx.ASGITransport(app=app)) -def make_app_client(repo: BaseGatewayRepo) -> Tuple[FastAPI, httpx.AsyncClient]: +def make_app_client(repo: BaseProxyRepo) -> Tuple[FastAPI, httpx.AsyncClient]: app = make_app(repo) client = make_client(app) return app, client @@ -59,7 +59,7 @@ def make_service(run_name: str) -> Service: @pytest.fixture def mock_replica_client_httpbin(httpbin) -> Generator[None, None, None]: with patch( - "dstack._internal.gateway.services.service_proxy.get_replica_client" + "dstack._internal.proxy.services.service_proxy.get_replica_client" ) as get_replica_client_mock: get_replica_client_mock.return_value = httpx.AsyncClient( base_url=httpbin.url, timeout=MOCK_REPLICA_CLIENT_TIMEOUT @@ -71,14 +71,14 @@ def mock_replica_client_httpbin(httpbin) -> Generator[None, None, None]: @pytest.mark.parametrize("method", ["get", "post", "put", "patch", "delete"]) async def test_proxy(mock_replica_client_httpbin, method: str) -> None: methods_without_body = "get", "delete" - repo = InMemoryGatewayRepo() + repo = InMemoryProxyRepo() await repo.add_project(make_project("test-proj")) await repo.add_service(project_name="test-proj", service=make_service("httpbin")) _, client = make_app_client(repo) req_body = "." * 20 * 2**20 if method not in methods_without_body else None resp = await client.request( method, - f"http://test-host:8888/gateway/services/test-proj/httpbin/{method}?a=b&c=", + f"http://test-host:8888/services/test-proj/httpbin/{method}?a=b&c=", headers={"User-Agent": "test-ua", "Connection": "keep-alive"}, content=req_body, ) @@ -96,11 +96,11 @@ async def test_proxy(mock_replica_client_httpbin, method: str) -> None: @pytest.mark.asyncio async def test_proxy_method_head(mock_replica_client_httpbin) -> None: - repo = InMemoryGatewayRepo() + repo = InMemoryProxyRepo() await repo.add_project(make_project("test-proj")) await repo.add_service(project_name="test-proj", service=make_service("httpbin")) _, client = make_app_client(repo) - url = "http://test-host/gateway/services/test-proj/httpbin/" + url = "http://test-host/services/test-proj/httpbin/" get_resp = await client.get(url) head_resp = await client.head(url) assert get_resp.status_code == head_resp.status_code == 200 @@ -111,11 +111,11 @@ async def test_proxy_method_head(mock_replica_client_httpbin) -> None: @pytest.mark.asyncio async def test_proxy_method_options(mock_replica_client_httpbin) -> None: - repo = InMemoryGatewayRepo() + repo = InMemoryProxyRepo() await repo.add_project(make_project("test-proj")) await repo.add_service(project_name="test-proj", service=make_service("httpbin")) _, client = make_app_client(repo) - resp = await client.options("http://test-host/gateway/services/test-proj/httpbin/get") + resp = await client.options("http://test-host/services/test-proj/httpbin/get") assert resp.status_code == 200 assert set(resp.headers["Allow"].split(", ")) == {"HEAD", "GET", "OPTIONS"} assert resp.content == b"" @@ -124,23 +124,23 @@ async def test_proxy_method_options(mock_replica_client_httpbin) -> None: @pytest.mark.asyncio @pytest.mark.parametrize("code", [204, 304, 418, 503]) async def test_proxy_status_codes(mock_replica_client_httpbin, code: int) -> None: - repo = InMemoryGatewayRepo() + repo = InMemoryProxyRepo() await repo.add_project(make_project("test-proj")) await repo.add_service(project_name="test-proj", service=make_service("httpbin")) _, client = make_app_client(repo) - resp = await client.get(f"http://test-host/gateway/services/test-proj/httpbin/status/{code}") + resp = await client.get(f"http://test-host/services/test-proj/httpbin/status/{code}") assert resp.status_code == code @pytest.mark.asyncio async def test_proxy_not_leaks_cookies(mock_replica_client_httpbin) -> None: - repo = InMemoryGatewayRepo() + repo = InMemoryProxyRepo() await repo.add_project(make_project("test-proj")) await repo.add_service(project_name="test-proj", service=make_service("httpbin")) app = make_app(repo) client1 = make_client(app) client2 = make_client(app) - cookies_url = "http://test-host/gateway/services/test-proj/httpbin/cookies" + cookies_url = "http://test-host/services/test-proj/httpbin/cookies" await client1.get(cookies_url + "/set?a=1") await client1.get(cookies_url + "/set?b=2") await client2.get(cookies_url + "/set?a=3") @@ -152,42 +152,42 @@ async def test_proxy_not_leaks_cookies(mock_replica_client_httpbin) -> None: @pytest.mark.asyncio async def test_proxy_gateway_timeout(mock_replica_client_httpbin) -> None: - repo = InMemoryGatewayRepo() + repo = InMemoryProxyRepo() await repo.add_project(make_project("test-proj")) await repo.add_service(project_name="test-proj", service=make_service("httpbin")) _, client = make_app_client(repo) assert MOCK_REPLICA_CLIENT_TIMEOUT < 10 - resp = await client.get("http://test-host/gateway/services/test-proj/httpbin/delay/10") + resp = await client.get("http://test-host/services/test-proj/httpbin/delay/10") assert resp.status_code == 504 assert resp.json()["detail"] == "Gateway Timeout" @pytest.mark.asyncio async def test_proxy_run_not_found(mock_replica_client_httpbin) -> None: - repo = InMemoryGatewayRepo() + repo = InMemoryProxyRepo() await repo.add_project(make_project("test-proj")) await repo.add_service(project_name="test-proj", service=make_service("test-run")) _, client = make_app_client(repo) - resp = await client.get("http://test-host/gateway/services/test-proj/unknown/") + resp = await client.get("http://test-host/services/test-proj/unknown/") assert resp.status_code == 404 assert resp.json()["detail"] == "Service test-proj/unknown not found" @pytest.mark.asyncio async def test_proxy_project_not_found(mock_replica_client_httpbin) -> None: - _, client = make_app_client(InMemoryGatewayRepo()) - resp = await client.get("http://test-host/gateway/services/unknown/test-run/") + _, client = make_app_client(InMemoryProxyRepo()) + resp = await client.get("http://test-host/services/unknown/test-run/") assert resp.status_code == 404 assert resp.json()["detail"] == "Service unknown/test-run not found" @pytest.mark.asyncio async def test_redirect_to_service_root(mock_replica_client_httpbin) -> None: - repo = InMemoryGatewayRepo() + repo = InMemoryProxyRepo() await repo.add_project(make_project("test-proj")) await repo.add_service(project_name="test-proj", service=make_service("httpbin")) _, client = make_app_client(repo) - url = "http://test-host/gateway/services/test-proj/httpbin" + url = "http://test-host/services/test-proj/httpbin" resp = await client.get(url, follow_redirects=False) assert resp.status_code == 308 assert resp.headers["Location"] == url + "/"