Skip to content

Commit

Permalink
feat:add apollo configuration to load env file (#11210)
Browse files Browse the repository at this point in the history
Signed-off-by: -LAN- <[email protected]>
Co-authored-by: huanshare <[email protected]>
Co-authored-by: -LAN- <[email protected]>
  • Loading branch information
3 people authored Dec 9, 2024
1 parent 32f8439 commit 967b7d8
Show file tree
Hide file tree
Showing 17 changed files with 578 additions and 24 deletions.
73 changes: 66 additions & 7 deletions api/configs/app_config.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,51 @@
from pydantic_settings import SettingsConfigDict
import logging
from typing import Any

from configs.deploy import DeploymentConfig
from configs.enterprise import EnterpriseFeatureConfig
from configs.extra import ExtraServiceConfig
from configs.feature import FeatureConfig
from configs.middleware import MiddlewareConfig
from configs.packaging import PackagingInfo
from pydantic.fields import FieldInfo
from pydantic_settings import BaseSettings, PydanticBaseSettingsSource, SettingsConfigDict

from .deploy import DeploymentConfig
from .enterprise import EnterpriseFeatureConfig
from .extra import ExtraServiceConfig
from .feature import FeatureConfig
from .middleware import MiddlewareConfig
from .packaging import PackagingInfo
from .remote_settings_sources import RemoteSettingsSource, RemoteSettingsSourceConfig, RemoteSettingsSourceName
from .remote_settings_sources.apollo import ApolloSettingsSource

logger = logging.getLogger(__name__)


class RemoteSettingsSourceFactory(PydanticBaseSettingsSource):
def __init__(self, settings_cls: type[BaseSettings]):
super().__init__(settings_cls)

def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]:
raise NotImplementedError

def __call__(self) -> dict[str, Any]:
current_state = self.current_state
remote_source_name = current_state.get("REMOTE_SETTINGS_SOURCE_NAME")
if not remote_source_name:
return {}

remote_source: RemoteSettingsSource | None = None
match remote_source_name:
case RemoteSettingsSourceName.APOLLO:
remote_source = ApolloSettingsSource(current_state)
case _:
logger.warning(f"Unsupported remote source: {remote_source_name}")
return {}

d: dict[str, Any] = {}

for field_name, field in self.settings_cls.model_fields.items():
field_value, field_key, value_is_complex = remote_source.get_field_value(field, field_name)
field_value = remote_source.prepare_field_value(field_name, field, field_value, value_is_complex)
if field_value is not None:
d[field_key] = field_value

return d


class DifyConfig(
Expand All @@ -19,6 +59,8 @@ class DifyConfig(
MiddlewareConfig,
# Extra service configs
ExtraServiceConfig,
# Remote source configs
RemoteSettingsSourceConfig,
# Enterprise feature configs
# **Before using, please contact [email protected] by email to inquire about licensing matters.**
EnterpriseFeatureConfig,
Expand All @@ -35,3 +77,20 @@ class DifyConfig(
# please consider to arrange it in the proper config group of existed or added
# for better readability and maintainability.
# Thanks for your concentration and consideration.

@classmethod
def settings_customise_sources(
cls,
settings_cls: type[BaseSettings],
init_settings: PydanticBaseSettingsSource,
env_settings: PydanticBaseSettingsSource,
dotenv_settings: PydanticBaseSettingsSource,
file_secret_settings: PydanticBaseSettingsSource,
) -> tuple[PydanticBaseSettingsSource, ...]:
return (
init_settings,
env_settings,
RemoteSettingsSourceFactory(settings_cls),
dotenv_settings,
file_secret_settings,
)
2 changes: 1 addition & 1 deletion api/configs/middleware/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class KeywordStoreConfig(BaseSettings):
)


class DatabaseConfig:
class DatabaseConfig(BaseSettings):
DB_HOST: str = Field(
description="Hostname or IP address of the database server.",
default="localhost",
Expand Down
5 changes: 3 additions & 2 deletions api/configs/middleware/storage/baidu_obs_storage_config.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from typing import Optional

from pydantic import BaseModel, Field
from pydantic import Field
from pydantic_settings import BaseSettings


class BaiduOBSStorageConfig(BaseModel):
class BaiduOBSStorageConfig(BaseSettings):
"""
Configuration settings for Baidu Object Storage Service (OBS)
"""
Expand Down
5 changes: 3 additions & 2 deletions api/configs/middleware/storage/huawei_obs_storage_config.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from typing import Optional

from pydantic import BaseModel, Field
from pydantic import Field
from pydantic_settings import BaseSettings


class HuaweiCloudOBSStorageConfig(BaseModel):
class HuaweiCloudOBSStorageConfig(BaseSettings):
"""
Configuration settings for Huawei Cloud Object Storage Service (OBS)
"""
Expand Down
5 changes: 3 additions & 2 deletions api/configs/middleware/storage/supabase_storage_config.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from typing import Optional

from pydantic import BaseModel, Field
from pydantic import Field
from pydantic_settings import BaseSettings


class SupabaseStorageConfig(BaseModel):
class SupabaseStorageConfig(BaseSettings):
"""
Configuration settings for Supabase Object Storage Service
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from typing import Optional

from pydantic import BaseModel, Field
from pydantic import Field
from pydantic_settings import BaseSettings


class VolcengineTOSStorageConfig(BaseModel):
class VolcengineTOSStorageConfig(BaseSettings):
"""
Configuration settings for Volcengine Tinder Object Storage (TOS)
"""
Expand Down
5 changes: 3 additions & 2 deletions api/configs/middleware/vdb/analyticdb_config.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from typing import Optional

from pydantic import BaseModel, Field, PositiveInt
from pydantic import Field, PositiveInt
from pydantic_settings import BaseSettings


class AnalyticdbConfig(BaseModel):
class AnalyticdbConfig(BaseSettings):
"""
Configuration for connecting to Alibaba Cloud AnalyticDB for PostgreSQL.
Refer to the following documentation for details on obtaining credentials:
Expand Down
5 changes: 3 additions & 2 deletions api/configs/middleware/vdb/couchbase_config.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from typing import Optional

from pydantic import BaseModel, Field
from pydantic import Field
from pydantic_settings import BaseSettings


class CouchbaseConfig(BaseModel):
class CouchbaseConfig(BaseSettings):
"""
Couchbase configs
"""
Expand Down
5 changes: 3 additions & 2 deletions api/configs/middleware/vdb/myscale_config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from pydantic import BaseModel, Field, PositiveInt
from pydantic import Field, PositiveInt
from pydantic_settings import BaseSettings


class MyScaleConfig(BaseModel):
class MyScaleConfig(BaseSettings):
"""
Configuration settings for MyScale vector database
"""
Expand Down
5 changes: 3 additions & 2 deletions api/configs/middleware/vdb/vikingdb_config.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from typing import Optional

from pydantic import BaseModel, Field
from pydantic import Field
from pydantic_settings import BaseSettings


class VikingDBConfig(BaseModel):
class VikingDBConfig(BaseSettings):
"""
Configuration for connecting to Volcengine VikingDB.
Refer to the following documentation for details on obtaining credentials:
Expand Down
17 changes: 17 additions & 0 deletions api/configs/remote_settings_sources/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import Optional

from pydantic import Field

from .apollo import ApolloSettingsSourceInfo
from .base import RemoteSettingsSource
from .enums import RemoteSettingsSourceName


class RemoteSettingsSourceConfig(ApolloSettingsSourceInfo):
REMOTE_SETTINGS_SOURCE_NAME: Optional[RemoteSettingsSourceName] = Field(
description="name of remote config source",
default=None,
)


__all__ = ["RemoteSettingsSource", "RemoteSettingsSourceConfig", "RemoteSettingsSourceName"]
55 changes: 55 additions & 0 deletions api/configs/remote_settings_sources/apollo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from collections.abc import Mapping
from typing import Any, Optional

from pydantic import Field
from pydantic.fields import FieldInfo
from pydantic_settings import BaseSettings

from configs.remote_settings_sources.base import RemoteSettingsSource

from .client import ApolloClient


class ApolloSettingsSourceInfo(BaseSettings):
"""
Packaging build information
"""

APOLLO_APP_ID: Optional[str] = Field(
description="apollo app_id",
default=None,
)

APOLLO_CLUSTER: Optional[str] = Field(
description="apollo cluster",
default=None,
)

APOLLO_CONFIG_URL: Optional[str] = Field(
description="apollo config url",
default=None,
)

APOLLO_NAMESPACE: Optional[str] = Field(
description="apollo namespace",
default=None,
)


class ApolloSettingsSource(RemoteSettingsSource):
def __init__(self, configs: Mapping[str, Any]):
self.client = ApolloClient(
app_id=configs["APOLLO_APP_ID"],
cluster=configs["APOLLO_CLUSTER"],
config_url=configs["APOLLO_CONFIG_URL"],
start_hot_update=False,
_notification_map={configs["APOLLO_NAMESPACE"]: -1},
)
self.namespace = configs["APOLLO_NAMESPACE"]
self.remote_configs = self.client.get_all_dicts(self.namespace)

def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]:
if not isinstance(self.remote_configs, dict):
raise ValueError(f"remote configs is not dict, but {type(self.remote_configs)}")
field_value = self.remote_configs.get(field_name)
return field_value, field_name, False
Loading

0 comments on commit 967b7d8

Please sign in to comment.