예제 #1
0
def init_app(settings: Optional[AppSettings] = None) -> FastAPI:
    if settings is None:
        settings = AppSettings.create_from_envs()
    assert settings  # nosec
    logging.basicConfig(level=settings.LOG_LEVEL.value)
    logging.root.setLevel(settings.LOG_LEVEL.value)
    logger.debug(settings.json(indent=2))

    app = FastAPI(
        debug=settings.SC_BOOT_MODE
        in [BootModeEnum.DEBUG, BootModeEnum.DEVELOPMENT, BootModeEnum.LOCAL],
        title=PROJECT_NAME,
        description=SUMMARY,
        version=API_VERSION,
        openapi_url=f"/api/{API_VTAG}/openapi.json",
        docs_url="/dev/doc",
        redoc_url=None,  # default disabled
    )
    override_fastapi_openapi_method(app)

    app.state.settings = settings

    if settings.SC_BOOT_MODE == BootModeEnum.DEBUG:
        remote_debug.setup(app)

    if settings.DIRECTOR_V0.DIRECTOR_V0_ENABLED:
        director_v0.setup(app, settings.DIRECTOR_V0)

    if settings.POSTGRES.DIRECTOR_V2_POSTGRES_ENABLED:
        db.setup(app, settings.POSTGRES)

    if settings.DYNAMIC_SERVICES.DIRECTOR_V2_DYNAMIC_SERVICES_ENABLED:
        dynamic_services.setup(app, settings.DYNAMIC_SERVICES)

    if settings.DYNAMIC_SERVICES.DYNAMIC_SIDECAR and (
            settings.DYNAMIC_SERVICES.DYNAMIC_SCHEDULER
            and settings.DYNAMIC_SERVICES.DYNAMIC_SCHEDULER.
            DIRECTOR_V2_DYNAMIC_SCHEDULER_ENABLED):
        dynamic_sidecar.setup(app)

    if settings.DASK_SCHEDULER.DIRECTOR_V2_DASK_CLIENT_ENABLED:
        dask_clients_pool.setup(app, settings.DASK_SCHEDULER)

    if settings.DASK_SCHEDULER.DIRECTOR_V2_DASK_SCHEDULER_ENABLED:
        rabbitmq.setup(app)
        comp_scheduler.setup(app)

    if settings.DIRECTOR_V2_TRACING:
        setup_tracing(app, settings.DIRECTOR_V2_TRACING)

    # setup app --
    app.add_event_handler("startup", on_startup)
    app.add_event_handler("shutdown", on_shutdown)
    _set_exception_handlers(app)

    app.include_router(api_router)

    config_all_loggers()

    return app
예제 #2
0
def assemble_application() -> FastAPI:
    """
    Creates the application from using the env vars as a context
    Also stores inside the state all instances of classes
    needed in other requests and used to share data.
    """

    dynamic_sidecar_settings = DynamicSidecarSettings.create_from_envs()

    logging.basicConfig(level=dynamic_sidecar_settings.loglevel)
    logging.root.setLevel(dynamic_sidecar_settings.loglevel)
    logger.debug(dynamic_sidecar_settings.json(indent=2))

    application = FastAPI(
        debug=dynamic_sidecar_settings.DEBUG,
        openapi_url=f"/api/{API_VTAG}/openapi.json",
        docs_url="/dev/doc",
    )
    override_fastapi_openapi_method(application)

    # store "settings"  and "shared_store" for later usage
    application.state.settings = dynamic_sidecar_settings
    application.state.shared_store = SharedStore(
        settings=dynamic_sidecar_settings)  # type: ignore
    # used to keep track of the health of the application
    # also will be used in the /health endpoint
    application.state.application_health = ApplicationHealth()

    # enable debug if required
    if dynamic_sidecar_settings.is_development_mode:
        remote_debug_setup(application)

    if dynamic_sidecar_settings.RABBIT_SETTINGS:
        setup_rabbitmq(application)
        # requires rabbitmq to be in place
        setup_background_log_fetcher(application)

    # add routing paths
    application.include_router(main_router)

    setup_directory_watcher(application)

    def create_start_app_handler() -> Callable[[], Coroutine[Any, Any, None]]:
        async def on_startup() -> None:
            await login_registry(application.state.settings.REGISTRY_SETTINGS)
            print(WELCOME_MSG, flush=True)

        return on_startup

    def create_stop_app_handler() -> Callable[[], Coroutine[Any, Any, None]]:
        async def on_shutdown() -> None:
            await on_shutdown_handler(application)
            logger.info("shutdown cleanup completed")

        return on_shutdown

    application.add_event_handler("startup", create_start_app_handler())
    application.add_event_handler("shutdown", create_stop_app_handler())

    return application
예제 #3
0
def test_overriding_openapi_method(app: FastAPI):
    assert not hasattr(app, "_original_openapi")
    assert app.openapi.__doc__ is None

    override_fastapi_openapi_method(app)

    assert hasattr(app, "_original_openapi")
    assert "Overrides FastAPI.openapi member function" in str(
        app.openapi.__doc__)

    # override patches should now work
    openapi = app.openapi()
    assert openapi and isinstance(openapi, dict)

    validate_spec(openapi)

    params = openapi["paths"]["/data"]["get"]["parameters"]
    assert params == [
        {
            "required": True,
            "schema": {
                "title": "X",
                "exclusiveMinimum": True,
                "type": "number",
                "minimum": 0.0,
            },
            "name": "x",
            "in": "query",
        },
        {
            "required": True,
            "schema": {
                "title": "Y",
                "exclusiveMaximum": True,
                "exclusiveMinimum": True,
                "type": "integer",
                "maximum": 4,
                "minimum": 3,
            },
            "name": "y",
            "in": "query",
        },
    ]
예제 #4
0
def init_app(settings: Optional[AppSettings] = None) -> FastAPI:
    if settings is None:
        settings = AppSettings.create_from_envs()
    assert settings  # nosec
    logging.basicConfig(level=settings.LOG_LEVEL.value)
    logging.root.setLevel(settings.LOG_LEVEL.value)
    logger.debug(settings.json(indent=2))

    app = FastAPI(
        debug=settings.SC_BOOT_MODE
        in [BootModeEnum.DEBUG, BootModeEnum.DEVELOPMENT, BootModeEnum.LOCAL],
        title=PROJECT_NAME,
        description=SUMMARY,
        version=API_VERSION,
        openapi_url=f"/api/{API_VTAG}/openapi.json",
        docs_url="/dev/doc",
        redoc_url=None,  # default disabled
    )
    override_fastapi_openapi_method(app)

    app.state.settings = settings

    if settings.SC_BOOT_MODE == BootModeEnum.DEBUG:
        remote_debug.setup(app)

    if settings.DIRECTOR_V0.DIRECTOR_V0_ENABLED:
        director_v0.setup(app, settings.DIRECTOR_V0)

    if settings.POSTGRES.DIRECTOR_V2_POSTGRES_ENABLED:
        db.setup(app, settings.POSTGRES)

    if settings.DYNAMIC_SERVICES.DIRECTOR_V2_DYNAMIC_SERVICES_ENABLED:
        dynamic_services.setup(app, settings.DYNAMIC_SERVICES)

    if settings.DYNAMIC_SERVICES.DYNAMIC_SIDECAR and (
            settings.DYNAMIC_SERVICES.DYNAMIC_SCHEDULER
            and settings.DYNAMIC_SERVICES.DYNAMIC_SCHEDULER.
            DIRECTOR_V2_DYNAMIC_SCHEDULER_ENABLED):
        dynamic_sidecar.setup(app)

    if settings.DASK_SCHEDULER.DIRECTOR_V2_DASK_CLIENT_ENABLED:
        dask_clients_pool.setup(app, settings.DASK_SCHEDULER)

    if settings.DASK_SCHEDULER.DIRECTOR_V2_DASK_SCHEDULER_ENABLED:
        rabbitmq.setup(app)
        comp_scheduler.setup(app)

    if settings.DIRECTOR_V2_TRACING:
        setup_tracing(app, settings.DIRECTOR_V2_TRACING)

    # setup app --
    app.add_event_handler("startup", on_startup)
    app.add_event_handler("shutdown", on_shutdown)

    app.add_exception_handler(HTTPException, http_error_handler)
    app.add_exception_handler(RequestValidationError, http422_error_handler)
    # director-v2 core.errors mappend into HTTP errors
    app.add_exception_handler(
        ProjectNotFoundError,
        make_http_error_handler_for_exception(status.HTTP_404_NOT_FOUND,
                                              ProjectNotFoundError),
    )
    app.add_exception_handler(
        PipelineNotFoundError,
        make_http_error_handler_for_exception(status.HTTP_404_NOT_FOUND,
                                              PipelineNotFoundError),
    )

    # SEE https://docs.python.org/3/library/exceptions.html#exception-hierarchy
    app.add_exception_handler(
        NotImplementedError,
        make_http_error_handler_for_exception(status.HTTP_501_NOT_IMPLEMENTED,
                                              NotImplementedError),
    )
    app.add_exception_handler(
        Exception,
        make_http_error_handler_for_exception(
            status.HTTP_500_INTERNAL_SERVER_ERROR, Exception),
    )

    app.include_router(api_router)

    config_all_loggers()

    return app
예제 #5
0
def init_app(settings: Optional[AppSettings] = None) -> FastAPI:
    if settings is None:
        settings = AppSettings.create_from_envs()
    assert settings  # nosec
    logging.basicConfig(level=settings.CATALOG_LOG_LEVEL.value)
    logging.root.setLevel(settings.CATALOG_LOG_LEVEL.value)
    logger.debug(settings.json(indent=2))

    app = FastAPI(
        debug=settings.SC_BOOT_MODE
        in [BootModeEnum.DEBUG, BootModeEnum.DEVELOPMENT, BootModeEnum.LOCAL],
        title=PROJECT_NAME,
        description=SUMMARY,
        version=API_VERSION,
        openapi_url=f"/api/{API_VTAG}/openapi.json",
        docs_url="/dev/doc",
        redoc_url=None,  # default disabled
    )
    override_fastapi_openapi_method(app)

    app.state.settings = settings

    setup_function_services(app)

    # events
    app.add_event_handler("startup", on_startup)
    app.add_event_handler("startup", create_start_app_handler(app))

    app.add_event_handler("shutdown", on_shutdown)
    app.add_event_handler("shutdown", create_stop_app_handler(app))

    # exception handlers
    app.add_exception_handler(HTTPException, http_error_handler)
    app.add_exception_handler(RequestValidationError, http422_error_handler)
    # SEE https://docs.python.org/3/library/exceptions.html#exception-hierarchy
    app.add_exception_handler(
        NotImplementedError,
        make_http_error_handler_for_exception(status.HTTP_501_NOT_IMPLEMENTED,
                                              NotImplementedError),
    )
    app.add_exception_handler(
        Exception,
        make_http_error_handler_for_exception(
            status.HTTP_500_INTERNAL_SERVER_ERROR, Exception),
    )

    # Routing

    # healthcheck at / and at /v0/
    app.include_router(health_router)

    # api under /v*
    app.include_router(api_router, prefix=f"/{API_VTAG}")
    # middleware to time requests (ONLY for development)
    if settings.SC_BOOT_MODE != BootModeEnum.PRODUCTION:

        async def _add_process_time_header(request: Request,
                                           call_next: Callable):
            start_time = time.time()
            response = await call_next(request)
            process_time = time.time() - start_time
            response.headers["X-Process-Time"] = str(process_time)
            return response

        app.add_middleware(BaseHTTPMiddleware,
                           dispatch=_add_process_time_header)

    # gzip middleware
    app.add_middleware(GZipMiddleware)

    return app
예제 #6
0
def init_app(settings: Optional[AppSettings] = None) -> FastAPI:
    if settings is None:
        settings = AppSettings.create_default()

    logging.basicConfig(level=settings.loglevel)
    logging.root.setLevel(settings.loglevel)

    app = FastAPI(
        debug=settings.debug,
        title="Components Catalog Service",
        description=
        "Manages and maintains a **catalog** of all published components (e.g. macro-algorithms, scripts, etc)",
        version=api_version,
        openapi_url=f"/api/{api_vtag}/openapi.json",
        docs_url="/dev/doc",
        redoc_url=None,  # default disabled
    )
    override_fastapi_openapi_method(app)

    logger.debug("App settings:%s", settings.json(indent=2))

    app.state.settings = settings

    setup_frontend_services(app)

    # events
    app.add_event_handler("startup", on_startup)
    app.add_event_handler("startup", create_start_app_handler(app))

    app.add_event_handler("shutdown", on_shutdown)
    app.add_event_handler("shutdown", create_stop_app_handler(app))

    # exception handlers
    app.add_exception_handler(HTTPException, http_error_handler)
    app.add_exception_handler(RequestValidationError, http422_error_handler)
    # SEE https://docs.python.org/3/library/exceptions.html#exception-hierarchy
    app.add_exception_handler(
        NotImplementedError,
        make_http_error_handler_for_exception(status.HTTP_501_NOT_IMPLEMENTED,
                                              NotImplementedError),
    )
    app.add_exception_handler(
        Exception,
        make_http_error_handler_for_exception(
            status.HTTP_500_INTERNAL_SERVER_ERROR, Exception),
    )

    # Routing

    # healthcheck at / and at /v0/
    app.include_router(health_router)

    # api under /v*
    app.include_router(api_router, prefix=f"/{api_vtag}")

    # middleware to time requests (ONLY for development)
    if settings.boot_mode != BootModeEnum.PRODUCTION:

        @app.middleware("http")
        async def _add_process_time_header(request: Request,
                                           call_next: Callable):
            start_time = time.time()
            response = await call_next(request)
            process_time = time.time() - start_time
            response.headers["X-Process-Time"] = str(process_time)
            return response

    # gzip middleware
    app.add_middleware(GZipMiddleware)

    return app