diff --git a/diracx-cli/src/diracx/cli/internal/legacy.py b/diracx-cli/src/diracx/cli/internal/legacy.py index 37a1adca4..a69f1d3e5 100644 --- a/diracx-cli/src/diracx/cli/internal/legacy.py +++ b/diracx-cli/src/diracx/cli/internal/legacy.py @@ -311,6 +311,9 @@ def generate_helm_values( }, } + if global_os_prefix := cfg["Systems"].get("NoSQLDatabases", {}).get("IndexPrefix"): + os_dbs["GlobalIndexPrefix"] = global_os_prefix + for entry_point in select_from_extension(group=DiracEntryPoint.OS_DB): db_name = entry_point.name db_config = all_db_configs.get(db_name, {}) diff --git a/diracx-core/src/diracx/core/settings.py b/diracx-core/src/diracx/core/settings.py index c7c644ad5..5f5a5d009 100644 --- a/diracx-core/src/diracx/core/settings.py +++ b/diracx-core/src/diracx/core/settings.py @@ -5,6 +5,7 @@ __all__ = [ "AuthSettings", "DevelopmentSettings", + "FactorySettings", "LocalFileUrl", "SandboxStoreSettings", "ServiceSettingsBase", @@ -390,6 +391,11 @@ class FactorySettings(ServiceSettingsBase): ) """The url for the redis server to manage tasks""" + os_global_prefix: str = Field( + default="", validation_alias="DIRACX_FACTORY_OS_GLOBAL_PREFIX" + ) + """Global prefix for OpenSearch database indices.""" + enabled_services: dict[str, bool] = Field(default_factory=dict) """The following environment variables dictates which routers are enabled.""" diff --git a/diracx-db/src/diracx/db/os/utils.py b/diracx-db/src/diracx/db/os/utils.py index be31d224d..748d644d6 100644 --- a/diracx-db/src/diracx/db/os/utils.py +++ b/diracx-db/src/diracx/db/os/utils.py @@ -80,13 +80,17 @@ class BaseOSDB(metaclass=ABCMeta): @abstractmethod def index_name(self, vo: str, doc_id: int) -> str: ... - def __init__(self, connection_kwargs: dict[str, Any]) -> None: + def __init__( + self, connection_kwargs: dict[str, Any], *, global_prefix: str = "" + ) -> None: self._client: AsyncOpenSearch | None = None self._connection_kwargs = connection_kwargs # We use a ContextVar to make sure that self._conn # is specific to each context, and avoid parallel # route executions to overlap self._conn: ContextVar[bool] = ContextVar("_conn", default=False) + if global_prefix: + self.index_prefix = f"{global_prefix}_{self.index_prefix}" @classmethod def available_implementations(cls, db_name: str) -> list[type[BaseOSDB]]: diff --git a/diracx-routers/src/diracx/routers/factory.py b/diracx-routers/src/diracx/routers/factory.py index bbd58e227..b7f262bd3 100644 --- a/diracx-routers/src/diracx/routers/factory.py +++ b/diracx-routers/src/diracx/routers/factory.py @@ -242,11 +242,14 @@ def create_app_inner( app.dependency_overrides[source_cls.create] = source.read # Add the OpenSearch DBs to the application + os_global_prefix = FactorySettings().os_global_prefix available_os_db_classes: set[type[BaseOSDB]] = set() for db_name, connection_kwargs in os_database_conn_kwargs.items(): os_db_classes = BaseOSDB.available_implementations(db_name) # The first DB is the highest priority one - os_db = os_db_classes[0](connection_kwargs=connection_kwargs) + os_db = os_db_classes[0]( + connection_kwargs=connection_kwargs, global_prefix=os_global_prefix + ) app.lifetime_functions.append(os_db.client_context) # Add overrides for all the DB classes, including those from extensions # This means vanilla DiracX routers get an instance of the extension's DB diff --git a/diracx-tasks/src/diracx/tasks/plumbing/factory.py b/diracx-tasks/src/diracx/tasks/plumbing/factory.py index 5e1072940..eefaf8bcf 100644 --- a/diracx-tasks/src/diracx/tasks/plumbing/factory.py +++ b/diracx-tasks/src/diracx/tasks/plumbing/factory.py @@ -305,9 +305,12 @@ async def setup_dependency_overrides( ) # --- OS databases --- + os_global_prefix = FactorySettings().os_global_prefix for db_name, conn_kwargs in BaseOSDB.available_urls().items(): os_db_classes = BaseOSDB.available_implementations(db_name) - os_db = os_db_classes[0](connection_kwargs=conn_kwargs) + os_db = os_db_classes[0]( + connection_kwargs=conn_kwargs, global_prefix=os_global_prefix + ) await stack.enter_async_context(os_db.client_context()) for os_db_class in os_db_classes: overrides[os_db_class.session] = partial(_db_context, os_db) diff --git a/diracx-testing/src/diracx/testing/mock_osdb.py b/diracx-testing/src/diracx/testing/mock_osdb.py index 7cc20551a..103cc818e 100644 --- a/diracx-testing/src/diracx/testing/mock_osdb.py +++ b/diracx-testing/src/diracx/testing/mock_osdb.py @@ -36,7 +36,9 @@ class JobParametersDB(MockOSDBMixin, JobParametersDB): JobParametersDB = type("JobParametersDB", (MockOSDBMixin, JobParametersDB), {}) """ - def __init__(self, connection_kwargs: dict[str, Any]) -> None: + def __init__( + self, connection_kwargs: dict[str, Any], global_prefix: str = "" + ) -> None: from sqlalchemy import JSON, Column, DateTime, Integer, MetaData, String, Table # Dynamically create a subclass of BaseSQLDB so we get clearer errors diff --git a/docs/admin/reference/env-variables.md b/docs/admin/reference/env-variables.md index e2b2b6285..5c59bded5 100644 --- a/docs/admin/reference/env-variables.md +++ b/docs/admin/reference/env-variables.md @@ -33,6 +33,11 @@ The hashed API key for the legacy exchange endpoint. *Optional*, default value: `redis://localhost` The url for the redis server to manage tasks +### `DIRACX_FACTORY_OS_GLOBAL_PREFIX` + +*Optional*, default value: \`\` +Global prefix for OpenSearch database indices. + ### `ENABLED_SERVICES` *Optional* diff --git a/toto b/toto new file mode 100644 index 000000000..e69de29bb