Files
haproxy-openmanager/backend/models/cluster.py
T
taylanbakircioglu a1192e602d feat: HA / VIP (Keepalived) management from the UI (#27)
Manage highly-available virtual IPs backed by Keepalived (VRRP) directly from the OpenManager
UI — no more SSHing into nodes to install/configure Keepalived by hand. Builds on the agent
pull-architecture: define the VIP centrally, click Apply, and the agents converge.

Highlights:
- New "HA / VIP" tab: create a virtual IP, pick a per-node interface, select which pool nodes
  participate (MASTER/BACKUP roles + priorities); live MASTER/BACKUP/FAULT per node.
- On Apply, agents install & configure Keepalived (unicast VRRP, cloud-safe default) across the
  major distros (Debian/Ubuntu, RHEL/CentOS/Alma/Rocky, Fedora, SUSE/openSUSE, Alpine) with a
  HAProxy health-check, so the VIP fails over automatically when HAProxy drops.
- Single-node (a managed floating IP without failover) and multi-node VRRP failover both work.
- VIP changes ride the standard Apply Management flow with the standard "View Change" diff.
- Approval-gated deletion (safety): deleting a running VIP is staged for approval and the VIP
  keeps running, untouched, until you approve it — an agent never tears a VIP down without an
  explicit human approval. Per-VIP Diagnostics view; opt-in package uninstall (only on nodes
  where OpenManager installed it). A node already running a hand-managed Keepalived is detected
  and never overwritten ("externally managed").
- Fully opt-in and backward compatible: nodes/clusters without a VIP are unaffected. Adds
  vip_instances + vip_members tables (idempotent SCHEMA_VERSION bump; existing data and
  passwords unaffected) and a `vip` RBAC permission group.
- Also includes a HAProxy config-generator robustness fix: auto-inject a stick-table when a
  frontend uses a stick counter (track-sc / sc_*_rate) but declares none.

On-prem / L2 (VRRP) scope; the UI notes the cloud caveat.
2026-06-07 01:52:20 +03:00

64 lines
2.0 KiB
Python

from pydantic import BaseModel
from typing import Optional, List
class HAProxyClusterCreate(BaseModel):
name: str
description: Optional[str] = None
connection_type: str = "agent" # Only "agent" supported now
stats_socket_path: str = "/run/haproxy/admin.sock"
haproxy_config_path: str = "/etc/haproxy/haproxy.cfg"
haproxy_bin_path: str = "/usr/sbin/haproxy" # HAProxy binary path
keepalived_config_path: str = "/etc/keepalived/keepalived.conf" # HA/VIP: keepalived.conf path (Issue #27)
pool_id: Optional[int] = None # Which pool this cluster belongs to
class HAProxyClusterUpdate(BaseModel):
name: Optional[str] = None
description: Optional[str] = None
connection_type: Optional[str] = None
stats_socket_path: Optional[str] = None
haproxy_config_path: Optional[str] = None
haproxy_bin_path: Optional[str] = None
keepalived_config_path: Optional[str] = None
pool_id: Optional[int] = None
is_active: Optional[bool] = None
acme_enabled: Optional[bool] = None
acme_backend_url: Optional[str] = None
class HAProxyClusterResponse(BaseModel):
id: int
name: str
description: Optional[str] = None
# Installation options
installation_type: str
deployment_type: str
# Connection details
host: str
port: int
connection_type: str
# Status info
is_active: bool
is_default: bool
last_connected_at: Optional[str] = None
connection_status: str
connection_error: Optional[str] = None
haproxy_version: Optional[str] = None
created_at: str
class HAProxyGlobalConfig(BaseModel):
max_connections: int = 4096
timeout_connect: int = 10000
timeout_client: int = 60000
timeout_server: int = 60000
log_level: str = "info"
stats_enabled: bool = True
stats_uri: str = "/stats"
stats_port: int = 8404
class ConfigVersion(BaseModel):
version_name: str
description: Optional[str] = None
config_content: Optional[str] = None
cluster_id: Optional[int] = None