2026-01-01 23:17:19 -03:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _env_bool(name: str, default: str = "false") -> bool:
|
|
|
|
|
return os.getenv(name, default).lower() in ("1", "true", "yes")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MONERO_GET_INFO_URL = os.getenv("MONERO_GET_INFO_URL", "http://monerod.crypto.svc.cluster.local:18081/get_info")
|
|
|
|
|
VM_BASE_URL = os.getenv(
|
|
|
|
|
"VM_BASE_URL",
|
|
|
|
|
"http://victoria-metrics-single-server.monitoring.svc.cluster.local:8428",
|
|
|
|
|
).rstrip("/")
|
|
|
|
|
VM_QUERY_TIMEOUT_SEC = float(os.getenv("VM_QUERY_TIMEOUT_SEC", "2"))
|
|
|
|
|
HTTP_CHECK_TIMEOUT_SEC = float(os.getenv("HTTP_CHECK_TIMEOUT_SEC", "2"))
|
2026-01-03 12:18:46 -03:00
|
|
|
K8S_API_TIMEOUT_SEC = float(os.getenv("K8S_API_TIMEOUT_SEC", "5"))
|
2026-01-01 23:17:19 -03:00
|
|
|
LAB_STATUS_CACHE_SEC = float(os.getenv("LAB_STATUS_CACHE_SEC", "30"))
|
2026-01-03 19:50:12 -03:00
|
|
|
GRAFANA_HEALTH_URL = os.getenv("GRAFANA_HEALTH_URL", "http://grafana.monitoring.svc.cluster.local/api/health")
|
2026-01-01 23:17:19 -03:00
|
|
|
OCEANUS_NODE_EXPORTER_URL = os.getenv("OCEANUS_NODE_EXPORTER_URL", "http://192.168.22.24:9100/metrics")
|
|
|
|
|
|
|
|
|
|
AI_CHAT_API = os.getenv("AI_CHAT_API", "http://ollama.ai.svc.cluster.local:11434").rstrip("/")
|
|
|
|
|
AI_CHAT_MODEL = os.getenv("AI_CHAT_MODEL", "qwen2.5-coder:7b-instruct-q4_0")
|
|
|
|
|
AI_CHAT_SYSTEM_PROMPT = os.getenv(
|
|
|
|
|
"AI_CHAT_SYSTEM_PROMPT",
|
|
|
|
|
"You are the Titan Lab assistant for bstein.dev. Be concise and helpful.",
|
|
|
|
|
)
|
|
|
|
|
AI_CHAT_TIMEOUT_SEC = float(os.getenv("AI_CHAT_TIMEOUT_SEC", "20"))
|
|
|
|
|
AI_NODE_NAME = os.getenv("AI_CHAT_NODE_NAME") or os.getenv("AI_NODE_NAME") or "ai-cluster"
|
|
|
|
|
AI_GPU_DESC = os.getenv("AI_CHAT_GPU_DESC") or "local GPU (dynamic)"
|
|
|
|
|
AI_PUBLIC_ENDPOINT = os.getenv("AI_PUBLIC_CHAT_ENDPOINT", "https://chat.ai.bstein.dev/api/chat")
|
|
|
|
|
AI_K8S_LABEL = os.getenv("AI_K8S_LABEL", "app=ollama")
|
|
|
|
|
AI_K8S_NAMESPACE = os.getenv("AI_K8S_NAMESPACE", "ai")
|
|
|
|
|
AI_MODEL_ANNOTATION = os.getenv("AI_MODEL_ANNOTATION", "ai.bstein.dev/model")
|
|
|
|
|
AI_GPU_ANNOTATION = os.getenv("AI_GPU_ANNOTATION", "ai.bstein.dev/gpu")
|
|
|
|
|
AI_WARM_INTERVAL_SEC = float(os.getenv("AI_WARM_INTERVAL_SEC", "300"))
|
|
|
|
|
AI_WARM_ENABLED = _env_bool("AI_WARM_ENABLED", "true")
|
|
|
|
|
|
|
|
|
|
KEYCLOAK_ENABLED = _env_bool("KEYCLOAK_ENABLED", "false")
|
|
|
|
|
KEYCLOAK_URL = os.getenv("KEYCLOAK_URL", "https://sso.bstein.dev").rstrip("/")
|
|
|
|
|
KEYCLOAK_REALM = os.getenv("KEYCLOAK_REALM", "atlas")
|
|
|
|
|
KEYCLOAK_CLIENT_ID = os.getenv("KEYCLOAK_CLIENT_ID", "bstein-dev-home")
|
|
|
|
|
KEYCLOAK_ISSUER = os.getenv("KEYCLOAK_ISSUER", f"{KEYCLOAK_URL}/realms/{KEYCLOAK_REALM}").rstrip("/")
|
|
|
|
|
KEYCLOAK_JWKS_URL = os.getenv("KEYCLOAK_JWKS_URL", f"{KEYCLOAK_ISSUER}/protocol/openid-connect/certs").rstrip("/")
|
|
|
|
|
|
|
|
|
|
KEYCLOAK_ADMIN_URL = os.getenv("KEYCLOAK_ADMIN_URL", KEYCLOAK_URL).rstrip("/")
|
|
|
|
|
KEYCLOAK_ADMIN_CLIENT_ID = os.getenv("KEYCLOAK_ADMIN_CLIENT_ID", "")
|
|
|
|
|
KEYCLOAK_ADMIN_CLIENT_SECRET = os.getenv("KEYCLOAK_ADMIN_CLIENT_SECRET", "")
|
|
|
|
|
KEYCLOAK_ADMIN_REALM = os.getenv("KEYCLOAK_ADMIN_REALM", KEYCLOAK_REALM)
|
|
|
|
|
|
2026-01-19 19:21:22 -03:00
|
|
|
ARIADNE_URL = os.getenv("ARIADNE_URL", "").strip()
|
|
|
|
|
ARIADNE_TIMEOUT_SEC = float(os.getenv("ARIADNE_TIMEOUT_SEC", "10"))
|
2026-01-21 18:21:42 -03:00
|
|
|
ARIADNE_RETRY_COUNT = int(os.getenv("ARIADNE_RETRY_COUNT", "2"))
|
|
|
|
|
ARIADNE_RETRY_BACKOFF_SEC = float(os.getenv("ARIADNE_RETRY_BACKOFF_SEC", "0.2"))
|
2026-01-19 19:21:22 -03:00
|
|
|
|
2026-01-01 23:17:19 -03:00
|
|
|
ACCOUNT_ALLOWED_GROUPS = [
|
|
|
|
|
g.strip()
|
|
|
|
|
for g in os.getenv("ACCOUNT_ALLOWED_GROUPS", "dev,admin").split(",")
|
|
|
|
|
if g.strip()
|
|
|
|
|
]
|
|
|
|
|
|
2026-01-02 00:41:49 -03:00
|
|
|
PORTAL_DATABASE_URL = os.getenv("PORTAL_DATABASE_URL", "").strip()
|
|
|
|
|
|
2026-01-01 23:17:19 -03:00
|
|
|
PORTAL_ADMIN_USERS = [u.strip() for u in os.getenv("PORTAL_ADMIN_USERS", "bstein").split(",") if u.strip()]
|
|
|
|
|
PORTAL_ADMIN_GROUPS = [g.strip() for g in os.getenv("PORTAL_ADMIN_GROUPS", "admin").split(",") if g.strip()]
|
|
|
|
|
|
2026-01-02 11:12:43 -03:00
|
|
|
DEFAULT_USER_GROUPS = [g.strip() for g in os.getenv("DEFAULT_USER_GROUPS", "dev").split(",") if g.strip()]
|
|
|
|
|
|
2026-01-01 23:17:19 -03:00
|
|
|
ACCESS_REQUEST_ENABLED = _env_bool("ACCESS_REQUEST_ENABLED", "true")
|
|
|
|
|
ACCESS_REQUEST_RATE_LIMIT = int(os.getenv("ACCESS_REQUEST_RATE_LIMIT", "5"))
|
|
|
|
|
ACCESS_REQUEST_RATE_WINDOW_SEC = int(os.getenv("ACCESS_REQUEST_RATE_WINDOW_SEC", str(60 * 60)))
|
2026-01-02 01:34:18 -03:00
|
|
|
ACCESS_REQUEST_SUBMIT_RATE_LIMIT = int(
|
|
|
|
|
os.getenv("ACCESS_REQUEST_SUBMIT_RATE_LIMIT", str(ACCESS_REQUEST_RATE_LIMIT))
|
|
|
|
|
)
|
|
|
|
|
ACCESS_REQUEST_SUBMIT_RATE_WINDOW_SEC = int(
|
|
|
|
|
os.getenv("ACCESS_REQUEST_SUBMIT_RATE_WINDOW_SEC", str(ACCESS_REQUEST_RATE_WINDOW_SEC))
|
|
|
|
|
)
|
|
|
|
|
ACCESS_REQUEST_STATUS_RATE_LIMIT = int(os.getenv("ACCESS_REQUEST_STATUS_RATE_LIMIT", "60"))
|
|
|
|
|
ACCESS_REQUEST_STATUS_RATE_WINDOW_SEC = int(os.getenv("ACCESS_REQUEST_STATUS_RATE_WINDOW_SEC", "60"))
|
2026-01-03 02:36:29 -03:00
|
|
|
ACCESS_REQUEST_EMAIL_VERIFY_TTL_SEC = int(os.getenv("ACCESS_REQUEST_EMAIL_VERIFY_TTL_SEC", str(24 * 60 * 60)))
|
2026-01-04 01:47:29 -03:00
|
|
|
ACCESS_REQUEST_INTERNAL_EMAIL_ALLOWLIST = {
|
|
|
|
|
address.strip().lower()
|
|
|
|
|
for address in os.getenv("ACCESS_REQUEST_INTERNAL_EMAIL_ALLOWLIST", "").split(",")
|
|
|
|
|
if address.strip()
|
|
|
|
|
}
|
2026-01-03 04:08:13 -03:00
|
|
|
ACCESS_REQUEST_PROVISION_RETRY_COOLDOWN_SEC = float(
|
|
|
|
|
os.getenv("ACCESS_REQUEST_PROVISION_RETRY_COOLDOWN_SEC", "30")
|
|
|
|
|
)
|
2026-01-03 02:36:29 -03:00
|
|
|
|
|
|
|
|
PORTAL_PUBLIC_BASE_URL = os.getenv("PORTAL_PUBLIC_BASE_URL", "https://bstein.dev").rstrip("/")
|
2026-01-01 23:17:19 -03:00
|
|
|
|
|
|
|
|
MAILU_DOMAIN = os.getenv("MAILU_DOMAIN", "bstein.dev")
|
|
|
|
|
MAILU_SYNC_URL = os.getenv(
|
|
|
|
|
"MAILU_SYNC_URL",
|
|
|
|
|
"http://mailu-sync-listener.mailu-mailserver.svc.cluster.local:8080/events",
|
|
|
|
|
).rstrip("/")
|
|
|
|
|
|
2026-01-03 12:18:46 -03:00
|
|
|
NEXTCLOUD_NAMESPACE = os.getenv("NEXTCLOUD_NAMESPACE", "nextcloud").strip()
|
|
|
|
|
NEXTCLOUD_MAIL_SYNC_CRONJOB = os.getenv("NEXTCLOUD_MAIL_SYNC_CRONJOB", "nextcloud-mail-sync").strip()
|
|
|
|
|
NEXTCLOUD_MAIL_SYNC_WAIT_TIMEOUT_SEC = float(os.getenv("NEXTCLOUD_MAIL_SYNC_WAIT_TIMEOUT_SEC", "90"))
|
|
|
|
|
NEXTCLOUD_MAIL_SYNC_JOB_TTL_SEC = int(os.getenv("NEXTCLOUD_MAIL_SYNC_JOB_TTL_SEC", "3600"))
|
|
|
|
|
|
2026-01-14 17:32:20 -03:00
|
|
|
WGER_NAMESPACE = os.getenv("WGER_NAMESPACE", "health").strip()
|
|
|
|
|
WGER_USER_SYNC_CRONJOB = os.getenv("WGER_USER_SYNC_CRONJOB", "wger-user-sync").strip()
|
|
|
|
|
WGER_USER_SYNC_WAIT_TIMEOUT_SEC = float(os.getenv("WGER_USER_SYNC_WAIT_TIMEOUT_SEC", "60"))
|
2026-01-16 23:50:07 -03:00
|
|
|
FIREFLY_NAMESPACE = os.getenv("FIREFLY_NAMESPACE", "finance").strip()
|
|
|
|
|
FIREFLY_USER_SYNC_CRONJOB = os.getenv("FIREFLY_USER_SYNC_CRONJOB", "firefly-user-sync").strip()
|
|
|
|
|
FIREFLY_USER_SYNC_WAIT_TIMEOUT_SEC = float(os.getenv("FIREFLY_USER_SYNC_WAIT_TIMEOUT_SEC", "90"))
|
2026-01-14 17:32:20 -03:00
|
|
|
|
2026-01-03 02:36:29 -03:00
|
|
|
SMTP_HOST = os.getenv("SMTP_HOST", "mailu-front.mailu-mailserver.svc.cluster.local").strip()
|
|
|
|
|
SMTP_PORT = int(os.getenv("SMTP_PORT", "25"))
|
|
|
|
|
SMTP_USERNAME = os.getenv("SMTP_USERNAME", "").strip()
|
|
|
|
|
SMTP_PASSWORD = os.getenv("SMTP_PASSWORD", "").strip()
|
|
|
|
|
SMTP_STARTTLS = _env_bool("SMTP_STARTTLS", "false")
|
|
|
|
|
SMTP_USE_TLS = _env_bool("SMTP_USE_TLS", "false")
|
|
|
|
|
SMTP_FROM = os.getenv("SMTP_FROM", "").strip() or f"postmaster@{MAILU_DOMAIN}"
|
|
|
|
|
SMTP_TIMEOUT_SEC = float(os.getenv("SMTP_TIMEOUT_SEC", "10"))
|
|
|
|
|
|
2026-01-01 23:17:19 -03:00
|
|
|
JELLYFIN_SYNC_URL = os.getenv("JELLYFIN_SYNC_URL", "").rstrip("/")
|
2026-01-02 04:27:44 -03:00
|
|
|
JELLYFIN_LDAP_HOST = os.getenv("JELLYFIN_LDAP_HOST", "openldap.sso.svc.cluster.local").strip()
|
|
|
|
|
JELLYFIN_LDAP_PORT = int(os.getenv("JELLYFIN_LDAP_PORT", "389"))
|
|
|
|
|
JELLYFIN_LDAP_CHECK_TIMEOUT_SEC = float(os.getenv("JELLYFIN_LDAP_CHECK_TIMEOUT_SEC", "1"))
|
2026-01-02 19:16:54 -03:00
|
|
|
|
|
|
|
|
VAULTWARDEN_NAMESPACE = os.getenv("VAULTWARDEN_NAMESPACE", "vaultwarden").strip()
|
|
|
|
|
VAULTWARDEN_POD_LABEL = os.getenv("VAULTWARDEN_POD_LABEL", "app=vaultwarden").strip()
|
|
|
|
|
VAULTWARDEN_POD_PORT = int(os.getenv("VAULTWARDEN_POD_PORT", "80"))
|
|
|
|
|
VAULTWARDEN_SERVICE_HOST = os.getenv("VAULTWARDEN_SERVICE_HOST", "vaultwarden-service.vaultwarden.svc.cluster.local").strip()
|
|
|
|
|
VAULTWARDEN_ADMIN_SECRET_NAME = os.getenv("VAULTWARDEN_ADMIN_SECRET_NAME", "vaultwarden-admin").strip()
|
|
|
|
|
VAULTWARDEN_ADMIN_SECRET_KEY = os.getenv("VAULTWARDEN_ADMIN_SECRET_KEY", "ADMIN_TOKEN").strip()
|
|
|
|
|
VAULTWARDEN_ADMIN_SESSION_TTL_SEC = float(os.getenv("VAULTWARDEN_ADMIN_SESSION_TTL_SEC", "300"))
|
2026-01-18 02:50:17 -03:00
|
|
|
VAULTWARDEN_ADMIN_RATE_LIMIT_BACKOFF_SEC = float(
|
|
|
|
|
os.getenv("VAULTWARDEN_ADMIN_RATE_LIMIT_BACKOFF_SEC", "600")
|
|
|
|
|
)
|