Add docker-ip-addr-manager initial app
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.responses import FileResponse, JSONResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from app.config import get_settings
|
||||
from app.docker_api import DockerApiClient, DockerApiError, DockerUsageResolver
|
||||
from app.ip_commands import CommandError, IpAddressManager
|
||||
from app.service import (
|
||||
ConflictError,
|
||||
DependencyError,
|
||||
EntryService,
|
||||
NotFoundError,
|
||||
ValidationError,
|
||||
)
|
||||
from app.storage import EntryStorage
|
||||
|
||||
|
||||
def build_service() -> EntryService:
|
||||
settings = get_settings()
|
||||
storage = EntryStorage(settings.state_file)
|
||||
docker_client = DockerApiClient(settings.docker_api_url, timeout_seconds=settings.docker_timeout_seconds)
|
||||
usage_resolver = DockerUsageResolver(docker_client)
|
||||
ip_manager = IpAddressManager()
|
||||
return EntryService(storage=storage, usage_resolver=usage_resolver, ip_manager=ip_manager)
|
||||
|
||||
|
||||
service = build_service()
|
||||
app = FastAPI(title="Docker IP Addr Manager", version="0.1.0")
|
||||
|
||||
static_dir = Path(__file__).parent / "static"
|
||||
app.mount("/static", StaticFiles(directory=static_dir), name="static")
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
def startup_reconcile() -> None:
|
||||
errors = service.reconcile_enabled_entries()
|
||||
if errors:
|
||||
for error in errors:
|
||||
print(f"[startup-reconcile] {error}")
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def index() -> FileResponse:
|
||||
return FileResponse(static_dir / "index.html")
|
||||
|
||||
|
||||
@app.get("/healthz")
|
||||
def healthz() -> dict:
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@app.get("/api/interfaces")
|
||||
def list_interfaces() -> dict:
|
||||
try:
|
||||
return {"items": service.list_interfaces()}
|
||||
except DependencyError as exc:
|
||||
raise HTTPException(status_code=503, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/api/entries")
|
||||
def list_entries() -> dict:
|
||||
response = service.list_entries()
|
||||
return response.to_dict()
|
||||
|
||||
|
||||
@app.post("/api/refresh")
|
||||
def refresh_entries() -> dict:
|
||||
response = service.list_entries()
|
||||
return response.to_dict()
|
||||
|
||||
|
||||
@app.post("/api/entries")
|
||||
def create_entry(payload: dict) -> dict:
|
||||
try:
|
||||
entry = service.create_entry(payload)
|
||||
return entry.to_dict()
|
||||
except ValidationError as exc:
|
||||
raise HTTPException(status_code=422, detail=str(exc)) from exc
|
||||
except ConflictError as exc:
|
||||
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.put("/api/entries/{entry_id}")
|
||||
def update_entry(entry_id: str, payload: dict) -> dict:
|
||||
try:
|
||||
entry = service.update_entry(entry_id, payload)
|
||||
return entry.to_dict()
|
||||
except ValidationError as exc:
|
||||
raise HTTPException(status_code=422, detail=str(exc)) from exc
|
||||
except ConflictError as exc:
|
||||
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/api/entries/{entry_id}/enable")
|
||||
def enable_entry(entry_id: str) -> dict:
|
||||
try:
|
||||
entry = service.set_enabled(entry_id, enabled=True)
|
||||
return entry.to_dict()
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
except (ConflictError, CommandError) as exc:
|
||||
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
||||
except DependencyError as exc:
|
||||
raise HTTPException(status_code=503, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/api/entries/{entry_id}/disable")
|
||||
def disable_entry(entry_id: str) -> dict:
|
||||
try:
|
||||
entry = service.set_enabled(entry_id, enabled=False)
|
||||
return entry.to_dict()
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
except (ConflictError, CommandError) as exc:
|
||||
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
||||
except DependencyError as exc:
|
||||
raise HTTPException(status_code=503, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.delete("/api/entries/{entry_id}")
|
||||
def delete_entry(entry_id: str) -> dict:
|
||||
try:
|
||||
service.delete_entry(entry_id)
|
||||
return {"deleted": True}
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
except ConflictError as exc:
|
||||
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
||||
except DependencyError as exc:
|
||||
raise HTTPException(status_code=503, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.exception_handler(DockerApiError)
|
||||
async def docker_error_handler(_, exc: DockerApiError):
|
||||
return JSONResponse(status_code=503, content={"detail": str(exc)})
|
||||
Reference in New Issue
Block a user