Open-source AI data analyst platform extracted from internal repo. Includes data sync engine, Keboola adapter, Flask web portal, server deployment scripts, and configuration templates.
104 lines
2.7 KiB
Python
104 lines
2.7 KiB
Python
"""
|
|
Instance configuration loader.
|
|
|
|
Loads instance.yaml from CONFIG_DIR (env var) or ./config/ fallback.
|
|
Used by both webapp and src modules for instance-specific settings.
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import yaml
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
CONFIG_DIR = Path(os.environ.get("CONFIG_DIR", "./config"))
|
|
|
|
|
|
def load_instance_config() -> dict[str, Any]:
|
|
"""Load instance configuration from instance.yaml.
|
|
|
|
Search order:
|
|
1. $CONFIG_DIR/instance.yaml
|
|
2. ./config/instance.yaml
|
|
|
|
Raises:
|
|
FileNotFoundError: If instance.yaml not found.
|
|
yaml.YAMLError: If YAML is invalid.
|
|
ValueError: If config is empty or missing required fields.
|
|
"""
|
|
path = CONFIG_DIR / "instance.yaml"
|
|
if not path.exists():
|
|
# Fallback to local config dir
|
|
path = Path("./config/instance.yaml")
|
|
|
|
if not path.exists():
|
|
raise FileNotFoundError(
|
|
"Instance configuration not found. "
|
|
"Copy config/instance.yaml.example to config/instance.yaml "
|
|
"and fill in your values."
|
|
)
|
|
|
|
with open(path) as f:
|
|
config = yaml.safe_load(f)
|
|
|
|
if not config:
|
|
raise ValueError("instance.yaml is empty")
|
|
|
|
_validate_config(config)
|
|
logger.info("Instance config loaded from %s", path)
|
|
return config
|
|
|
|
|
|
def _validate_config(config: dict) -> None:
|
|
"""Validate required configuration fields.
|
|
|
|
Raises:
|
|
ValueError: If required fields are missing or empty.
|
|
"""
|
|
required_paths = [
|
|
("instance", "name"),
|
|
("auth", "allowed_domain"),
|
|
("server", "host"),
|
|
("server", "hostname"),
|
|
]
|
|
|
|
missing = []
|
|
for keys in required_paths:
|
|
value = config
|
|
path_str = ".".join(keys)
|
|
for key in keys:
|
|
if not isinstance(value, dict) or key not in value:
|
|
missing.append(path_str)
|
|
break
|
|
value = value[key]
|
|
else:
|
|
if not value:
|
|
missing.append(path_str)
|
|
|
|
if missing:
|
|
raise ValueError(
|
|
f"Missing required instance config fields: {', '.join(missing)}. "
|
|
f"Check config/instance.yaml"
|
|
)
|
|
|
|
|
|
def get_instance_value(config: dict, *keys: str, default: Any = None) -> Any:
|
|
"""Get a nested value from instance config.
|
|
|
|
Args:
|
|
config: Instance config dict.
|
|
*keys: Path of keys (e.g., "instance", "name").
|
|
default: Default value if path not found.
|
|
|
|
Returns:
|
|
Config value or default.
|
|
"""
|
|
value = config
|
|
for key in keys:
|
|
if not isinstance(value, dict) or key not in value:
|
|
return default
|
|
value = value[key]
|
|
return value if value is not None else default
|