diff --git a/controller/cuda_grid_controller/config.py b/controller/cuda_grid_controller/config.py index bffd9cc..963fa4f 100644 --- a/controller/cuda_grid_controller/config.py +++ b/controller/cuda_grid_controller/config.py @@ -28,13 +28,33 @@ from __future__ import annotations import os +import re from pathlib import Path -from typing import Self +from typing import Any, Self import yaml from pydantic import BaseModel, Field, field_validator +_ENV_PATTERN = re.compile(r"\$\{(\w+)(?::-([^}]*))?\}") + + +def _expand_env(obj: Any) -> Any: + """Recursively replace ${VAR} and ${VAR:-default} в string values + через os.environ. Используется при load YAML config — secrets вроде + API tokens хранятся в .env (gitignored) и interpolate'ятся при start.""" + if isinstance(obj, str): + return _ENV_PATTERN.sub( + lambda m: os.environ.get(m.group(1), m.group(2) or ""), + obj, + ) + if isinstance(obj, dict): + return {k: _expand_env(v) for k, v in obj.items()} + if isinstance(obj, list): + return [_expand_env(v) for v in obj] + return obj + + class BrokerCfg(BaseModel): host: str = "localhost" port: int = 1883 @@ -202,4 +222,5 @@ class Config(BaseModel): def from_yaml(cls, path: Path | str) -> Self: with open(path) as f: data = yaml.safe_load(f) or {} + data = _expand_env(data) return cls.model_validate(data)