- Move load_certs_config, save_certs_config, add_cert_to_config, remove_cert_from_config from certificates.py to file_ops.py - Add CERTS_FILE constant to config.py - Add file locking for certificate config operations (was missing) - Consistent pattern with servers.json handling certificates.py: 543 → 503 lines file_ops.py: 263 → 337 lines Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
83 lines
3.2 KiB
Python
83 lines
3.2 KiB
Python
"""Configuration constants and environment variables for HAProxy MCP Server."""
|
|
|
|
import os
|
|
import re
|
|
import logging
|
|
|
|
# Configure structured logging
|
|
log_level = os.getenv("LOG_LEVEL", "INFO").upper()
|
|
logging.basicConfig(
|
|
level=getattr(logging, log_level, logging.INFO),
|
|
format='%(asctime)s [%(levelname)s] %(message)s',
|
|
datefmt='%Y-%m-%d %H:%M:%S'
|
|
)
|
|
logger = logging.getLogger("haproxy_mcp")
|
|
|
|
# MCP Server configuration
|
|
MCP_HOST: str = os.getenv("MCP_HOST", "0.0.0.0")
|
|
MCP_PORT: int = int(os.getenv("MCP_PORT", "8000"))
|
|
|
|
# HAProxy Runtime API configuration
|
|
HAPROXY_HOST: str = os.getenv("HAPROXY_HOST", "localhost")
|
|
HAPROXY_PORT: int = int(os.getenv("HAPROXY_PORT", "9999"))
|
|
HAPROXY_SOCKET: tuple[str, int] = (HAPROXY_HOST, HAPROXY_PORT)
|
|
|
|
# File paths (configurable via environment)
|
|
STATE_FILE: str = os.getenv("HAPROXY_STATE_FILE", "/opt/haproxy/data/servers.state")
|
|
MAP_FILE: str = os.getenv("HAPROXY_MAP_FILE", "/opt/haproxy/conf/domains.map")
|
|
MAP_FILE_CONTAINER: str = os.getenv("HAPROXY_MAP_FILE_CONTAINER", "/usr/local/etc/haproxy/domains.map")
|
|
SERVERS_FILE: str = os.getenv("HAPROXY_SERVERS_FILE", "/opt/haproxy/conf/servers.json")
|
|
CERTS_FILE: str = os.getenv("HAPROXY_CERTS_FILE", "/opt/haproxy/conf/certificates.json")
|
|
|
|
# Pool configuration
|
|
POOL_COUNT: int = int(os.getenv("HAPROXY_POOL_COUNT", "100"))
|
|
MAX_SLOTS: int = int(os.getenv("HAPROXY_MAX_SLOTS", "10"))
|
|
|
|
# Container configuration
|
|
HAPROXY_CONTAINER: str = os.getenv("HAPROXY_CONTAINER", "haproxy")
|
|
|
|
# Validation patterns - compiled once for performance
|
|
DOMAIN_PATTERN = re.compile(
|
|
r'^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?'
|
|
r'(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$'
|
|
)
|
|
# Backend/server names: alphanumeric, underscore, hyphen only
|
|
BACKEND_NAME_PATTERN = re.compile(r'^[a-zA-Z0-9_-]+$')
|
|
# Pattern for converting domain to backend name
|
|
NON_ALNUM_PATTERN = re.compile(r'[^a-zA-Z0-9]')
|
|
|
|
# Limits
|
|
MAX_RESPONSE_SIZE = 10 * 1024 * 1024 # 10 MB max response from HAProxy
|
|
SUBPROCESS_TIMEOUT = 30 # seconds
|
|
STARTUP_RETRY_COUNT = 10 # HAProxy ready check retries
|
|
STATE_MIN_COLUMNS = 19 # Minimum columns in HAProxy server state output
|
|
SOCKET_TIMEOUT = 5 # seconds for HAProxy socket connection
|
|
SOCKET_RECV_TIMEOUT = 30 # seconds for HAProxy socket recv loop
|
|
MAX_BULK_SERVERS = 10 # Max servers per bulk add call
|
|
MAX_SERVERS_JSON_SIZE = 10000 # Max size of servers JSON in haproxy_add_servers
|
|
|
|
|
|
# CSV field indices for HAProxy stats (show stat command)
|
|
class StatField:
|
|
"""HAProxy CSV stat field indices."""
|
|
PXNAME = 0 # Proxy name (frontend/backend)
|
|
SVNAME = 1 # Server name (or FRONTEND/BACKEND)
|
|
SCUR = 4 # Current sessions
|
|
SMAX = 6 # Max sessions
|
|
STATUS = 17 # Status (UP/DOWN/MAINT/etc)
|
|
WEIGHT = 18 # Server weight
|
|
CHECK_STATUS = 36 # Check status
|
|
|
|
|
|
# Field indices for HAProxy server state (show servers state command)
|
|
class StateField:
|
|
"""HAProxy server state field indices."""
|
|
BE_ID = 0 # Backend ID
|
|
BE_NAME = 1 # Backend name
|
|
SRV_ID = 2 # Server ID
|
|
SRV_NAME = 3 # Server name
|
|
SRV_ADDR = 4 # Server address
|
|
SRV_OP_STATE = 5 # Operational state
|
|
SRV_ADMIN_STATE = 6 # Admin state
|
|
SRV_PORT = 18 # Server port
|