feat: Add support for remote services
- Added base_url field to DeployedComponent for external URL proxying - Updated Caddyfile generator to proxy to base_url when present instead of requiring local port - Added runner: remote handling in deploy command (returns empty run_cmd, marks as unmanaged) - Reformatted long ternary expression in registry.py for readability This enables castle to manage services that proxy to external endpoints without requiring a local process.
This commit is contained in:
@@ -122,7 +122,7 @@ def _build_deployed_service(config: CastleConfig, name: str, svc: ServiceSpec) -
|
|||||||
env: dict[str, str] = {}
|
env: dict[str, str] = {}
|
||||||
|
|
||||||
# Data dir convention (for managed services)
|
# Data dir convention (for managed services)
|
||||||
managed = True # Services are always managed by default
|
managed = run.runner != "remote" # Remote services have no local process
|
||||||
if svc.manage and svc.manage.systemd and not svc.manage.systemd.enable:
|
if svc.manage and svc.manage.systemd and not svc.manage.systemd.enable:
|
||||||
managed = False
|
managed = False
|
||||||
if managed:
|
if managed:
|
||||||
@@ -159,6 +159,9 @@ def _build_deployed_service(config: CastleConfig, name: str, svc: ServiceSpec) -
|
|||||||
if svc.component and svc.component in config.programs:
|
if svc.component and svc.component in config.programs:
|
||||||
stack = config.programs[svc.component].stack
|
stack = config.programs[svc.component].stack
|
||||||
|
|
||||||
|
# Remote services proxy to an external base_url
|
||||||
|
base_url = getattr(run, "base_url", None)
|
||||||
|
|
||||||
return DeployedComponent(
|
return DeployedComponent(
|
||||||
runner=run.runner,
|
runner=run.runner,
|
||||||
run_cmd=run_cmd,
|
run_cmd=run_cmd,
|
||||||
@@ -169,6 +172,7 @@ def _build_deployed_service(config: CastleConfig, name: str, svc: ServiceSpec) -
|
|||||||
port=port,
|
port=port,
|
||||||
health_path=health_path,
|
health_path=health_path,
|
||||||
proxy_path=proxy_path,
|
proxy_path=proxy_path,
|
||||||
|
base_url=base_url,
|
||||||
managed=managed,
|
managed=managed,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -322,6 +326,8 @@ def _build_run_cmd(run: object, env: dict[str, str]) -> list[str]:
|
|||||||
if run.args:
|
if run.args:
|
||||||
cmd.extend(run.args)
|
cmd.extend(run.args)
|
||||||
return cmd
|
return cmd
|
||||||
|
case "remote":
|
||||||
|
return [] # No local process for remote services
|
||||||
case _:
|
case _:
|
||||||
raise ValueError(f"Unsupported runner: {run.runner}")
|
raise ValueError(f"Unsupported runner: {run.runner}")
|
||||||
|
|
||||||
|
|||||||
@@ -24,12 +24,16 @@ def generate_caddyfile_from_registry(
|
|||||||
local_paths: set[str] = set()
|
local_paths: set[str] = set()
|
||||||
|
|
||||||
for name, deployed in registry.deployed.items():
|
for name, deployed in registry.deployed.items():
|
||||||
if not deployed.proxy_path or not deployed.port:
|
if not deployed.proxy_path:
|
||||||
|
continue
|
||||||
|
# Need either a local port or a remote base_url to proxy to
|
||||||
|
if not deployed.port and not deployed.base_url:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
local_paths.add(deployed.proxy_path)
|
local_paths.add(deployed.proxy_path)
|
||||||
|
target = deployed.base_url or f"localhost:{deployed.port}"
|
||||||
lines.append(f" handle_path {deployed.proxy_path}/* {{")
|
lines.append(f" handle_path {deployed.proxy_path}/* {{")
|
||||||
lines.append(f" reverse_proxy localhost:{deployed.port}")
|
lines.append(f" reverse_proxy {target}")
|
||||||
lines.append(" }")
|
lines.append(" }")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class DeployedComponent:
|
|||||||
port: int | None = None
|
port: int | None = None
|
||||||
health_path: str | None = None
|
health_path: str | None = None
|
||||||
proxy_path: str | None = None
|
proxy_path: str | None = None
|
||||||
|
base_url: str | None = None
|
||||||
schedule: str | None = None
|
schedule: str | None = None
|
||||||
managed: bool = False
|
managed: bool = False
|
||||||
|
|
||||||
@@ -82,7 +83,15 @@ def load_registry(path: Path | None = None) -> NodeRegistry:
|
|||||||
behavior = comp_data.get("behavior")
|
behavior = comp_data.get("behavior")
|
||||||
if behavior is None:
|
if behavior is None:
|
||||||
category = comp_data.get("category", "service")
|
category = comp_data.get("category", "service")
|
||||||
behavior = "daemon" if category == "service" else "tool" if category in ("job", "tool") else "frontend" if category == "frontend" else category
|
behavior = (
|
||||||
|
"daemon"
|
||||||
|
if category == "service"
|
||||||
|
else "tool"
|
||||||
|
if category in ("job", "tool")
|
||||||
|
else "frontend"
|
||||||
|
if category == "frontend"
|
||||||
|
else category
|
||||||
|
)
|
||||||
deployed[name] = DeployedComponent(
|
deployed[name] = DeployedComponent(
|
||||||
runner=comp_data.get("runner", "command"),
|
runner=comp_data.get("runner", "command"),
|
||||||
run_cmd=comp_data.get("run_cmd", []),
|
run_cmd=comp_data.get("run_cmd", []),
|
||||||
@@ -93,6 +102,7 @@ def load_registry(path: Path | None = None) -> NodeRegistry:
|
|||||||
port=comp_data.get("port"),
|
port=comp_data.get("port"),
|
||||||
health_path=comp_data.get("health_path"),
|
health_path=comp_data.get("health_path"),
|
||||||
proxy_path=comp_data.get("proxy_path"),
|
proxy_path=comp_data.get("proxy_path"),
|
||||||
|
base_url=comp_data.get("base_url"),
|
||||||
schedule=comp_data.get("schedule"),
|
schedule=comp_data.get("schedule"),
|
||||||
managed=comp_data.get("managed", False),
|
managed=comp_data.get("managed", False),
|
||||||
)
|
)
|
||||||
@@ -136,6 +146,8 @@ def save_registry(registry: NodeRegistry, path: Path | None = None) -> None:
|
|||||||
entry["health_path"] = comp.health_path
|
entry["health_path"] = comp.health_path
|
||||||
if comp.proxy_path:
|
if comp.proxy_path:
|
||||||
entry["proxy_path"] = comp.proxy_path
|
entry["proxy_path"] = comp.proxy_path
|
||||||
|
if comp.base_url:
|
||||||
|
entry["base_url"] = comp.base_url
|
||||||
if comp.schedule:
|
if comp.schedule:
|
||||||
entry["schedule"] = comp.schedule
|
entry["schedule"] = comp.schedule
|
||||||
if comp.managed:
|
if comp.managed:
|
||||||
|
|||||||
Reference in New Issue
Block a user