refactor: Extract deploy logic to castle-core and add deploy API endpoint
- Extract all deploy logic from CLI into castle-core/deploy.py as a reusable deploy() function
* Resolves services/jobs to DeployedComponents
* Generates systemd units and Caddyfile
* Copies frontend assets and reloads systemd
* Returns DeployResult with deployed count and messages
- Simplify CLI deploy command to a thin wrapper calling castle_core.deploy()
- Add POST /deploy endpoint to castle-api for remote deployment management
* Supports optional {name} body param to deploy one or all services
* Returns deployment result as JSON
- Register deploy router in castle-api main.py
- Update README with new deploy endpoint documentation
This enables full remote management: build, test, lint, and deploy any castle
node over HTTP (e.g. POST http://node:9000/api/deploy)
This commit is contained in:
49
castle-api/src/castle_api/deploy_routes.py
Normal file
49
castle-api/src/castle_api/deploy_routes.py
Normal file
@@ -0,0 +1,49 @@
|
||||
"""Deploy API endpoint."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
|
||||
from castle_core.deploy import deploy
|
||||
|
||||
router = APIRouter(tags=["deploy"])
|
||||
|
||||
|
||||
class DeployRequest(BaseModel):
|
||||
"""Optional request body for deploy."""
|
||||
|
||||
name: str | None = None
|
||||
|
||||
|
||||
class DeployResponse(BaseModel):
|
||||
"""Response from a deploy operation."""
|
||||
|
||||
status: str
|
||||
deployed_count: int
|
||||
messages: list[str]
|
||||
|
||||
|
||||
@router.post("/deploy", response_model=DeployResponse)
|
||||
def run_deploy(request: DeployRequest | None = None) -> DeployResponse:
|
||||
"""Deploy services and jobs from castle.yaml to runtime.
|
||||
|
||||
Resolves env vars and secrets, generates systemd units and Caddyfile,
|
||||
copies frontend build outputs, and reloads systemd.
|
||||
|
||||
Optionally pass a name to deploy a single service or job.
|
||||
"""
|
||||
target_name = request.name if request else None
|
||||
|
||||
try:
|
||||
result = deploy(target_name=target_name)
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e)) from e
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e)) from e
|
||||
|
||||
return DeployResponse(
|
||||
status="ok",
|
||||
deployed_count=result.deployed_count,
|
||||
messages=result.messages,
|
||||
)
|
||||
Reference in New Issue
Block a user