from typing import Optional from fastapi import APIRouter, Header from app.schemas.common import ApiResponse from app.services.ops_agent_service import ( agent_append_job_event, agent_complete_job, agent_heartbeat, agent_mark_job_started, agent_pull_jobs, agent_pull_runtime_config, agent_register, build_node_agent_bootstrap_plan, issue_node_agent_token, ) router = APIRouter(tags=["ops-agent"]) def _resolve_agent_token(x_domaincheck_agent_token: Optional[str]) -> str: return str(x_domaincheck_agent_token or "").strip() def _build_agent_response(ok: bool, message: str, data: object) -> ApiResponse: detail_code = None if isinstance(data, dict): detail_code = str(data.get("detail_code") or "").strip() or None return ApiResponse(code=0 if ok else 1, message=message, data=data, detail_code=detail_code) @router.post("/ops/agent/tokens", response_model=ApiResponse) def ops_agent_issue_token(payload: dict) -> ApiResponse: ok, message, data = issue_node_agent_token( node_code=str(payload.get("node_code") or "").strip(), issued_by=str(payload.get("issued_by") or "api").strip() or "api", expires_in_hours=int(payload.get("expires_in_hours") or 72), metadata=payload.get("metadata") or {}, ) return _build_agent_response(ok, message, data) @router.post("/ops/agent/bootstrap-plan", response_model=ApiResponse) def ops_agent_bootstrap_plan(payload: dict) -> ApiResponse: ok, message, data = build_node_agent_bootstrap_plan( node_code=str(payload.get("node_code") or "").strip(), node_region=str(payload.get("node_region") or "mainland").strip() or "mainland", node_role=str(payload.get("node_role") or "worker").strip() or "worker", issued_by=str(payload.get("issued_by") or "api").strip() or "api", expires_in_hours=int(payload.get("expires_in_hours") or 72), control_plane_base_url=str(payload.get("control_plane_base_url") or "").strip(), root_dir=str(payload.get("root_dir") or "/opt/domaincheck").strip() or "/opt/domaincheck", metadata=payload.get("metadata") or {}, ) return _build_agent_response(ok, message, data) @router.post("/ops/agent/register", response_model=ApiResponse) def ops_agent_register(payload: dict, x_domaincheck_agent_token: Optional[str] = Header(default=None)) -> ApiResponse: ok, message, data = agent_register(payload, token=_resolve_agent_token(x_domaincheck_agent_token)) return _build_agent_response(ok, message, data) @router.post("/ops/agent/heartbeat", response_model=ApiResponse) def ops_agent_heartbeat(payload: dict, x_domaincheck_agent_token: Optional[str] = Header(default=None)) -> ApiResponse: ok, message, data = agent_heartbeat(payload, token=_resolve_agent_token(x_domaincheck_agent_token)) return _build_agent_response(ok, message, data) @router.post("/ops/agent/pull", response_model=ApiResponse) def ops_agent_pull(payload: dict, limit: int = 1, x_domaincheck_agent_token: Optional[str] = Header(default=None)) -> ApiResponse: ok, message, data = agent_pull_jobs(payload, token=_resolve_agent_token(x_domaincheck_agent_token), limit=limit) return _build_agent_response(ok, message, data) @router.post("/ops/agent/runtime-config", response_model=ApiResponse) def ops_agent_runtime_config(payload: dict, x_domaincheck_agent_token: Optional[str] = Header(default=None)) -> ApiResponse: ok, message, data = agent_pull_runtime_config(payload, token=_resolve_agent_token(x_domaincheck_agent_token)) return _build_agent_response(ok, message, data) @router.post("/ops/agent/jobs/{job_id}/start", response_model=ApiResponse) def ops_agent_job_start(job_id: int, payload: dict, x_domaincheck_agent_token: Optional[str] = Header(default=None)) -> ApiResponse: ok, message, data = agent_mark_job_started(job_id, payload, token=_resolve_agent_token(x_domaincheck_agent_token)) return _build_agent_response(ok, message, data) @router.post("/ops/agent/jobs/{job_id}/complete", response_model=ApiResponse) def ops_agent_job_complete(job_id: int, payload: dict, x_domaincheck_agent_token: Optional[str] = Header(default=None)) -> ApiResponse: ok, message, data = agent_complete_job(job_id, payload, token=_resolve_agent_token(x_domaincheck_agent_token)) return _build_agent_response(ok, message, data) @router.post("/ops/agent/jobs/{job_id}/events", response_model=ApiResponse) def ops_agent_job_event(job_id: int, payload: dict, x_domaincheck_agent_token: Optional[str] = Header(default=None)) -> ApiResponse: ok, message, data = agent_append_job_event(job_id, payload, token=_resolve_agent_token(x_domaincheck_agent_token)) return _build_agent_response(ok, message, data)