feat: add cc-connect dashboard health integration
Deploy Dashboard (Dev) / deploy-dev (push) Successful in 2m49s

Add a protected backend health endpoint and a new dashboard page/sidebar entry so cc-connect operational status is visible in the UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Gan, Jimmy
2026-03-02 23:24:03 +08:00
parent e76f15c432
commit 14965c7e03
8 changed files with 242 additions and 2 deletions
+3
View File
@@ -48,6 +48,9 @@ CHAT_SUMMARY_DB = os.environ.get("CHAT_SUMMARY_DB", "/app/data/chat-summarizer/c
LITELLM_URL = os.environ.get("LITELLM_URL", "http://127.0.0.1:4005")
LITELLM_HEALTH_API_KEY = os.environ.get("LITELLM_HEALTH_API_KEY", "")
# CC Connect
CC_CONNECT_URL = os.environ.get("CC_CONNECT_URL", "")
# OpenClaw
OPENCLAW_GATEWAY_TOKEN = os.environ.get("OPENCLAW_GATEWAY_TOKEN", "")
+3 -1
View File
@@ -6,7 +6,7 @@ from fastapi.responses import JSONResponse
from slowapi import Limiter
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from routers import docker_router, gitea, files, terminal, system, auth, chat_summary, security, passkey, totp, litellm
from routers import docker_router, gitea, files, terminal, system, auth, chat_summary, security, passkey, totp, litellm, cc_connect
import auth as auth_module
from rbac import require_page, require_write
@@ -181,6 +181,8 @@ app.include_router(system.router, prefix="/api/system",
dependencies=[Depends(_inject_user), Depends(require_page("dashboard"))])
app.include_router(litellm.router, prefix="/api/litellm",
dependencies=[Depends(_inject_user), Depends(require_page("dashboard"))])
app.include_router(cc_connect.router, prefix="/api/cc-connect",
dependencies=[Depends(_inject_user), Depends(require_page("dashboard"))])
app.include_router(chat_summary.router, prefix="/api/chat-summary",
dependencies=[Depends(_inject_user), Depends(require_page("chat-digest"))])
app.include_router(security.router, prefix="/api/security",
+107
View File
@@ -0,0 +1,107 @@
import time
import docker
import httpx
from fastapi import APIRouter
from config import CC_CONNECT_URL, DOCKER_HOST
router = APIRouter()
client = docker.DockerClient(base_url=DOCKER_HOST, timeout=5)
@router.get("/health")
async def cc_connect_health():
url = (CC_CONNECT_URL or "").strip()
container = None
try:
matches = client.containers.list(all=True, filters={"name": "cc-connect"})
if matches:
container = matches[0]
except Exception as exc:
return {
"ok": False,
"status": "down",
"source": "docker",
"container_name": None,
"container_status": None,
"endpoint": None,
"http_status": None,
"latency_ms": None,
"error": f"docker check failed: {exc}",
}
container_name = container.name if container else None
container_status = container.status if container else "not_found"
container_up = container_status == "running"
if not url:
return {
"ok": container_up,
"status": "up" if container_up else "down",
"source": "docker",
"container_name": container_name,
"container_status": container_status,
"endpoint": None,
"http_status": None,
"latency_ms": None,
"error": None if container_up else "cc-connect container is not running",
}
timeout = httpx.Timeout(2.0)
started = time.perf_counter()
try:
async with httpx.AsyncClient(timeout=timeout) as http_client:
response = await http_client.get(url)
latency_ms = round((time.perf_counter() - started) * 1000, 1)
if response.is_success and container_up:
return {
"ok": True,
"status": "up",
"source": "docker+http",
"container_name": container_name,
"container_status": container_status,
"endpoint": url,
"http_status": response.status_code,
"latency_ms": latency_ms,
"error": None,
}
if response.is_success and not container_up:
return {
"ok": False,
"status": "down",
"source": "docker+http",
"container_name": container_name,
"container_status": container_status,
"endpoint": url,
"http_status": response.status_code,
"latency_ms": latency_ms,
"error": "HTTP probe succeeded but cc-connect container is not running",
}
return {
"ok": False,
"status": "down",
"source": "docker+http",
"container_name": container_name,
"container_status": container_status,
"endpoint": url,
"http_status": response.status_code,
"latency_ms": latency_ms,
"error": f"HTTP probe returned {response.status_code}",
}
except Exception as exc:
return {
"ok": False,
"status": "down",
"source": "docker+http",
"container_name": container_name,
"container_status": container_status,
"endpoint": url,
"http_status": None,
"latency_ms": None,
"error": str(exc),
}