import logging from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.openapi.utils import get_openapi from app.middleware.auth import AuthMiddleware from app.plugins.loader import load_plugins from app.routers import admin, alerts, auth, dashboard, devices, events, global_devices, objects, racks, snapshots, ssh_keys, tags, tasks, zones from app.services.dashboard_monitor import ensure_dashboard_bootstrap from app.workers.dashboard_monitor import start_dashboard_monitor, stop_dashboard_monitor from app.workers.monitor import start_monitor, stop_monitor from app.workers.startup import recover_stale_tasks # Configure logging to output to console logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', ) logging.getLogger('app.services.dashboard_monitor').setLevel(logging.DEBUG) @asynccontextmanager async def lifespan(app: FastAPI): await load_plugins() await recover_stale_tasks() await ensure_dashboard_bootstrap() start_monitor() start_dashboard_monitor() yield await stop_dashboard_monitor() await stop_monitor() def create_app() -> FastAPI: app = FastAPI( title="Fleet Manager", description="Centralized device fleet management service", version="0.1.0", docs_url="/docs", redoc_url="/redoc", lifespan=lifespan, ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.add_middleware(AuthMiddleware) app.include_router(auth.router) app.include_router(objects.router) app.include_router(global_devices.router) app.include_router(devices.router) app.include_router(racks.router) app.include_router(zones.router) app.include_router(tags.router) app.include_router(ssh_keys.router) app.include_router(admin.router) app.include_router(alerts.router) app.include_router(snapshots.router) app.include_router(tasks.router) app.include_router(events.router) app.include_router(dashboard.router) def custom_openapi(): if app.openapi_schema: return app.openapi_schema schema = get_openapi( title=app.title, version=app.version, description=app.description, routes=app.routes, ) schema.setdefault("components", {}).setdefault("securitySchemes", {})["BearerAuth"] = { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", } for path in schema.get("paths", {}).values(): for operation in path.values(): operation.setdefault("security", [{"BearerAuth": []}]) # Login and refresh don't need auth for no_auth in ["/api/v1/auth/login", "/api/v1/auth/refresh"]: if no_auth in schema.get("paths", {}): for op in schema["paths"][no_auth].values(): op["security"] = [] app.openapi_schema = schema return schema app.openapi = custom_openapi return app app = create_app()