from fastapi import FastAPI, HTTPException, Depends from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles import os import logging from dotenv import load_dotenv from app.routers import jobs, logs, configs, repositories, claude from app.services.nomad_client import get_nomad_client from app.services.gitea_client import GiteaClient # Load environment variables load_dotenv() # Configure logging logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", ) logger = logging.getLogger(__name__) # Initialize the FastAPI app app = FastAPI( title="Nomad MCP", description="Service for AI agents to manage Nomad jobs via MCP protocol", version="0.1.0", ) # Add CORS middleware app.add_middleware( CORSMiddleware, allow_origins=["*"], # Can be set to specific origins in production allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include routers app.include_router(jobs.router, prefix="/api/jobs", tags=["jobs"]) app.include_router(logs.router, prefix="/api/logs", tags=["logs"]) app.include_router(configs.router, prefix="/api/configs", tags=["configs"]) app.include_router(repositories.router, prefix="/api/repositories", tags=["repositories"]) app.include_router(claude.router, prefix="/api/claude", tags=["claude"]) @app.get("/api/health", tags=["health"]) async def health_check(): """Health check endpoint.""" health_status = { "status": "healthy", "services": {} } # Check Nomad connection try: client = get_nomad_client() nomad_status = client.agent.get_agent() health_status["services"]["nomad"] = { "status": "connected", "version": nomad_status.get("config", {}).get("Version", "unknown"), } except Exception as e: logger.error(f"Nomad health check failed: {str(e)}") health_status["services"]["nomad"] = { "status": "failed", "error": str(e), } # Check Gitea connection try: gitea_client = GiteaClient() if gitea_client.api_base_url: # Try to list repositories as a connection test repos = gitea_client.list_repositories(limit=1) health_status["services"]["gitea"] = { "status": "connected", "api_url": gitea_client.api_base_url, } else: health_status["services"]["gitea"] = { "status": "not_configured", } except Exception as e: logger.error(f"Gitea health check failed: {str(e)}") health_status["services"]["gitea"] = { "status": "failed", "error": str(e), } # Overall status is unhealthy if any service is failed if any(service["status"] == "failed" for service in health_status["services"].values()): health_status["status"] = "unhealthy" return health_status # Mount static files app.mount("/", StaticFiles(directory="static", html=True), name="static") if __name__ == "__main__": import uvicorn port = int(os.getenv("PORT", "8000")) uvicorn.run("app.main:app", host="0.0.0.0", port=port, reload=True)