SQLite DB in the K8s pod is ephemeral (no PV). On pod restart,
migrate_from_json() re-reads the remote JSON files. Without syncing
back, any server/cert changes after migration would be lost.
Now every server/cert write to SQLite also writes the corresponding
JSON file to the remote host, keeping them in sync.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace servers.json, certificates.json, and map file parsing with
SQLite (WAL mode) as single source of truth. HAProxy map files are
now generated from SQLite via sync_map_files().
Key changes:
- Add db.py with schema, connection management, and JSON migration
- Add DB_FILE config constant
- Delegate file_ops.py functions to db.py
- Refactor domains.py to use file_ops instead of direct list manipulation
- Fix subprocess.TimeoutExpired not caught (doesn't inherit TimeoutError)
- Add DB health check in health.py
- Init DB on startup in server.py and __main__.py
- Update all 359 tests to use SQLite-backed functions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MCP server can now manage HAProxy running on a remote host via SSH.
When SSH_HOST env var is set, all file I/O and subprocess commands
(podman, acme.sh, openssl) are routed through SSH instead of local exec.
- Add ssh_ops.py module with remote_exec, run_command, file I/O helpers
- Modify file_ops.py to support remote reads/writes via SSH
- Update all tools (domains, certificates, health, configuration) for SSH
- Fix domains.py: replace direct fcntl usage with file_lock context manager
- Add openssh-client to Docker image for SSH connectivity
- Update k8s deployment with SSH env vars and SSH key secret mount
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow multiple domains to share the same backend pool using share_with parameter.
This saves pool slots when domains point to the same servers.
- Add share_with parameter to haproxy_add_domain
- Add helper functions for shared domain management
- Protect shared pools from being cleared on domain removal
- Update documentation with pool sharing examples
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Split domain routing into two stages for improved performance:
- Stage 1: map_str for exact domains (O(log n) using ebtree)
- Stage 2: map_dom for wildcards only (O(n) but small set)
Wildcards now stored in separate wildcards.map file.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>