def init_app() -> FastAPI: # Warm the sources once before starting sources_refresh() LOG.info('Initial fetch of Sources completed') application = FastAPI( title='Sovereign', version=__versionstr__, debug=config.debug_enabled ) application.include_router(discovery.router, tags=['Configuration Discovery'], prefix='/v2') application.include_router(crypto.router, tags=['Cryptographic Utilities'], prefix='/crypto') application.include_router(admin.router, tags=['Debugging Endpoints'], prefix='/admin') application.include_router(interface.router, tags=['User Interface'], prefix='/ui') application.include_router(healthchecks.router, tags=['Healthchecks']) application.add_middleware(RequestContextLogMiddleware) application.add_middleware(LoggingMiddleware) application.add_middleware(ScheduledTasksMiddleware) if config.sentry_dsn and sentry_sdk: sentry_sdk.init(config.sentry_dsn) application.add_middleware(SentryAsgiMiddleware) LOG.info('Sentry middleware enabled') @application.exception_handler(500) async def exception_handler(_, exc: Exception) -> json_response_class: """ We cannot incur the execution of this function from unit tests because the starlette test client simply returns exceptions and does not run them through the exception handler. Ergo, this is a facade function for `generic_error_response` """ return generic_error_response(exc) # pragma: no cover @application.get('/') def redirect_to_docs(): return RedirectResponse('/ui') @application.get('/static/{filename}', summary='Return a static asset') def static(filename: str): return FileResponse(resource_filename('sovereign', f'static/{filename}')) return application
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint): start_time = time.time() response = Response("Internal server error", status_code=500) new_log_context() add_log_context(env=config.environment, site=request.headers.get('host', '-'), method=request.method, uri_path=request.url.path, uri_query=dict(request.query_params.items()), src_ip=request.client.host, src_port=request.client.port, pid=os.getpid(), user_agent=request.headers.get('user-agent', '-'), bytes_in=request.headers.get('content-length', '-')) try: response: Response = await call_next(request) finally: duration = time.time() - start_time LOG.info(bytes_out=response.headers.get('content-length', '-'), status=response.status_code, duration=duration, request_id=response.headers.get('X-Request-Id', '-')) if 'discovery' in str(request.url): tags = { 'path': request.url.path, 'xds_type': response.headers.get("X-Sovereign-Requested-Type"), 'client_version': response.headers.get("X-Sovereign-Client-Build"), 'response_code': response.status_code, } tags = [ ':'.join(map(str, [k, v])) for k, v in tags.items() if v is not None ] stats.increment('discovery.rq_total', tags=tags) stats.timing('discovery.rq_ms', value=duration * 1000, tags=tags) return response
application.add_middleware(SentryAsgiMiddleware) LOG.info('Sentry middleware enabled') @application.exception_handler(500) async def exception_handler(_, exc: Exception) -> json_response_class: """ We cannot incur the execution of this function from unit tests because the starlette test client simply returns exceptions and does not run them through the exception handler. Ergo, this is a facade function for `generic_error_response` """ return generic_error_response(exc) # pragma: no cover @application.get('/') def redirect_to_docs(): return RedirectResponse('/ui') @application.get('/static/{filename}', summary='Return a static asset') def static(filename: str): return FileResponse(resource_filename('sovereign', f'static/{filename}')) return application app = init_app() LOG.info(f'Sovereign started and listening on {asgi_config.host}:{asgi_config.port}') if __name__ == '__main__': # pragma: no cover uvicorn.run(app, host='0.0.0.0', port=8000, access_log=False)