Some checks failed
Tests / Backend Tests (Python) (3.10) (push) Has been cancelled
Tests / Backend Tests (Python) (3.11) (push) Has been cancelled
Tests / Backend Tests (Python) (3.12) (push) Has been cancelled
Tests / Frontend Tests (JS) (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / All Tests Passed (push) Has been cancelled
152 lines
4.9 KiB
Python
152 lines
4.9 KiB
Python
"""
|
|
Configuration centralisée de l'application.
|
|
|
|
Toutes les variables d'environnement et paramètres sont centralisés ici.
|
|
"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
from pydantic import Field
|
|
from pydantic import field_validator
|
|
from pydantic_settings import BaseSettings
|
|
|
|
|
|
def parse_env_bool(value: object, default: bool = False) -> bool:
|
|
if value is None:
|
|
return default
|
|
if isinstance(value, bool):
|
|
return value
|
|
if isinstance(value, (int, float)):
|
|
return bool(value)
|
|
if isinstance(value, str):
|
|
normalized = value.strip().lower()
|
|
if normalized in {"1", "true", "yes"}:
|
|
return True
|
|
if normalized in {"0", "false", "no"}:
|
|
return False
|
|
return default
|
|
return default
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
"""Configuration de l'application Homelab Automation."""
|
|
|
|
# === Chemins ===
|
|
base_dir: Path = Field(default_factory=lambda: Path(__file__).resolve().parent.parent)
|
|
logs_dir: Path = Field(default_factory=lambda: Path(os.environ.get("LOGS_DIR", "/logs")))
|
|
|
|
@property
|
|
def ansible_dir(self) -> Path:
|
|
"""Répertoire Ansible (relatif à base_dir.parent)"""
|
|
return self.base_dir.parent / "ansible"
|
|
|
|
@property
|
|
def tasks_logs_dir(self) -> Path:
|
|
"""Répertoire des logs de tâches markdown"""
|
|
return Path(os.environ.get("DIR_LOGS_TASKS", str(self.base_dir.parent / "tasks_logs")))
|
|
|
|
@property
|
|
def db_path(self) -> Path:
|
|
"""Chemin de la base de données SQLite"""
|
|
return self.logs_dir / "homelab.db"
|
|
|
|
# === SSH ===
|
|
ssh_key_path: str = Field(
|
|
default_factory=lambda: os.environ.get("SSH_KEY_PATH", str(Path.home() / ".ssh" / "id_rsa"))
|
|
)
|
|
ssh_user: str = Field(default_factory=lambda: os.environ.get("SSH_USER", "automation"))
|
|
ssh_remote_user: str = Field(default_factory=lambda: os.environ.get("SSH_REMOTE_USER", "root"))
|
|
|
|
# === API ===
|
|
api_key: str = Field(default_factory=lambda: os.environ.get("API_KEY", "dev-key-12345"))
|
|
api_title: str = "Homelab Automation Dashboard API"
|
|
api_version: str = "1.0.0"
|
|
api_description: str = "API REST moderne pour la gestion automatique d'homelab"
|
|
|
|
# === JWT Authentication ===
|
|
jwt_secret_key: str = Field(
|
|
default_factory=lambda: os.environ.get("JWT_SECRET_KEY", "dev-secret-key-change-in-production")
|
|
)
|
|
jwt_expire_minutes: int = Field(
|
|
default_factory=lambda: int(os.environ.get("JWT_EXPIRE_MINUTES", "1440"))
|
|
)
|
|
jwt_algorithm: str = "HS256"
|
|
|
|
# === Database ===
|
|
database_url: Optional[str] = Field(default=None)
|
|
|
|
@property
|
|
def async_database_url(self) -> str:
|
|
"""URL de connexion async pour SQLAlchemy"""
|
|
if self.database_url:
|
|
return self.database_url
|
|
return f"sqlite+aiosqlite:///{self.db_path}"
|
|
|
|
# === CORS ===
|
|
cors_origins: list = Field(default=["*"])
|
|
cors_allow_credentials: bool = True
|
|
cors_allow_methods: list = Field(default=["*"])
|
|
cors_allow_headers: list = Field(default=["*"])
|
|
|
|
# === Notifications ntfy ===
|
|
ntfy_enabled: bool = Field(
|
|
default_factory=lambda: os.environ.get("NTFY_ENABLED", "true").lower() == "true"
|
|
)
|
|
ntfy_base_url: str = Field(
|
|
default_factory=lambda: os.environ.get("NTFY_BASE_URL", "https://ntfy.sh")
|
|
)
|
|
ntfy_default_topic: str = Field(
|
|
default_factory=lambda: os.environ.get("NTFY_TOPIC", "homelab-automation")
|
|
)
|
|
ntfy_timeout: int = Field(
|
|
default_factory=lambda: int(os.environ.get("NTFY_TIMEOUT", "10"))
|
|
)
|
|
ntfy_username: Optional[str] = Field(
|
|
default_factory=lambda: os.environ.get("NTFY_USERNAME")
|
|
)
|
|
ntfy_password: Optional[str] = Field(
|
|
default_factory=lambda: os.environ.get("NTFY_PASSWORD")
|
|
)
|
|
ntfy_token: Optional[str] = Field(
|
|
default_factory=lambda: os.environ.get("NTFY_TOKEN")
|
|
)
|
|
|
|
# === Scheduler ===
|
|
scheduler_timezone: str = Field(
|
|
default_factory=lambda: os.environ.get("SCHEDULER_TIMEZONE", "America/Montreal")
|
|
)
|
|
scheduler_misfire_grace_time: int = 300
|
|
|
|
# === Cache ===
|
|
hosts_cache_ttl: int = 60 # secondes
|
|
inventory_cache_ttl: int = 60 # secondes
|
|
logs_index_rebuild_interval: int = 60 # secondes
|
|
|
|
# === Server ===
|
|
host: str = "0.0.0.0"
|
|
port: int = 8008
|
|
reload: bool = Field(
|
|
default_factory=lambda: os.environ.get("RELOAD", "true").lower() == "true"
|
|
)
|
|
log_level: str = "info"
|
|
|
|
# === Feature Flags ===
|
|
debug_mode: bool = Field(default=False, validation_alias="DEBUG_MODE")
|
|
|
|
@field_validator("debug_mode", mode="before")
|
|
@classmethod
|
|
def _validate_debug_mode(cls, v: object) -> bool:
|
|
return parse_env_bool(v, default=False)
|
|
|
|
class Config:
|
|
env_file = ".env"
|
|
env_file_encoding = "utf-8"
|
|
extra = "ignore"
|
|
|
|
|
|
# Instance singleton de la configuration
|
|
settings = Settings()
|
|
DEBUG_MODE_ENABLED: bool = settings.debug_mode
|