108 lines
3.7 KiB
Python
Executable File
108 lines
3.7 KiB
Python
Executable File
"""Configuration loader.
|
|
|
|
Reads from the path in FESTER_CONFIG env var if set, otherwise from
|
|
config.yaml in the project root. Provides CONFIG as a module-level dict.
|
|
|
|
F-06 / F-17 remediation:
|
|
External-service endpoints (MinIO, Prometheus, Firecracker SSH key,
|
|
default node host) are now resolved from environment variables with
|
|
sensible fallbacks — no hardcoded ``localhost:9000`` /
|
|
``http://localhost:9090`` / ``/root/.ssh/fc_builder`` literals in
|
|
the runtime modules. Operators override via env vars; the YAML
|
|
config can still set them under ``CONFIG["external"]``.
|
|
"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
|
|
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
|
|
|
# Allow override via env var (for tests / dev / multi-cluster setups)
|
|
_env_config = os.environ.get("FESTER_CONFIG")
|
|
if _env_config:
|
|
CONFIG_PATH = _env_config
|
|
else:
|
|
CONFIG_PATH = os.path.join(BASE_DIR, "config.yaml")
|
|
|
|
# Graceful fallback: if the requested config doesn't exist, use a sensible
|
|
# default so the backend can still boot (e.g. in a fresh clone or container).
|
|
if not Path(CONFIG_PATH).exists():
|
|
CONFIG = {
|
|
"master": {"name": "fester-master", "role": "control"},
|
|
"nodes": [
|
|
{
|
|
"name": os.environ.get("FESTER_NODE_NAME", "localhost"),
|
|
"host": os.environ.get("FESTER_NODE_HOST", "127.0.0.1"),
|
|
"max_jobs": int(os.environ.get("FESTER_NODE_MAX_JOBS", "4")),
|
|
},
|
|
],
|
|
"projects": [],
|
|
"btc": {
|
|
"enabled": True,
|
|
"root": "/opt/BTC",
|
|
"primary": False,
|
|
},
|
|
}
|
|
else:
|
|
with open(CONFIG_PATH, "r") as f:
|
|
CONFIG = yaml.safe_load(f) or {}
|
|
|
|
# Ensure required keys exist
|
|
CONFIG.setdefault("master", {"name": "fester-master", "role": "control"})
|
|
CONFIG.setdefault("nodes", [])
|
|
CONFIG.setdefault("projects", [])
|
|
|
|
# BTC (Build Tool Chain) configuration
|
|
CONFIG.setdefault("btc", {})
|
|
CONFIG["btc"].setdefault("enabled", True)
|
|
CONFIG["btc"].setdefault("root", "/opt/BTC")
|
|
CONFIG["btc"].setdefault("primary", False)
|
|
|
|
|
|
# ---------------------------------------------------------------------
|
|
# External-service endpoints (F-06 / F-17)
|
|
# ---------------------------------------------------------------------
|
|
# Single source of truth for every external service Fester talks to.
|
|
# Modules import EXTERNAL_CONFIG instead of hardcoding URLs / paths.
|
|
def _env_bool(name: str, default: bool = False) -> bool:
|
|
return os.environ.get(name, "").lower() in ("1", "true", "yes", "on")
|
|
|
|
|
|
EXTERNAL_CONFIG: dict = {
|
|
# MinIO build cache
|
|
"minio_endpoint": os.environ.get("FESTER_MINIO_ENDPOINT", "localhost:9000"),
|
|
"minio_access_key": os.environ.get("FESTER_MINIO_ACCESS_KEY", ""),
|
|
"minio_secret_key": os.environ.get("FESTER_MINIO_SECRET_KEY", ""),
|
|
"minio_bucket": os.environ.get("FESTER_MINIO_BUCKET", "fester-cache"),
|
|
"minio_secure": _env_bool("FESTER_MINIO_SECURE", False),
|
|
"minio_required": _env_bool("FESTER_MINIO_REQUIRED", False),
|
|
|
|
# Prometheus
|
|
"prometheus_url": os.environ.get(
|
|
"FESTER_PROM_URL", os.environ.get("PROM_URL", "http://localhost:9090"),
|
|
),
|
|
|
|
# Firecracker
|
|
"firecracker_bin": os.environ.get("FESTER_FIRECRACKER_BIN", "firecracker"),
|
|
"firecracker_ssh_key": os.environ.get(
|
|
"FESTER_FC_SSH_KEY", "/root/.ssh/fc_builder",
|
|
),
|
|
"firecracker_socket_dir": os.environ.get(
|
|
"FESTER_FC_SOCKET_DIR", "/run/fester/firecracker",
|
|
),
|
|
|
|
# Cluster agent
|
|
"agent_port": int(os.environ.get("FESTER_AGENT_PORT", "8787")),
|
|
}
|
|
|
|
|
|
def get_external() -> dict:
|
|
"""Return a deep copy of the external-service config dict.
|
|
|
|
Returned at call time so tests / operators can monkey-patch env
|
|
vars between requests.
|
|
"""
|
|
return dict(EXTERNAL_CONFIG)
|