"""VPN Server model for managing multiple OpenVPN instances.""" from datetime import datetime from enum import Enum as PyEnum from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, Enum, Text from sqlalchemy.orm import relationship from ..database import Base class VPNProtocol(str, PyEnum): """VPN protocol type.""" UDP = "udp" TCP = "tcp" class VPNCipher(str, PyEnum): """VPN cipher options.""" AES_256_GCM = "AES-256-GCM" AES_128_GCM = "AES-128-GCM" AES_256_CBC = "AES-256-CBC" CHACHA20_POLY1305 = "CHACHA20-POLY1305" class VPNAuth(str, PyEnum): """VPN auth digest options.""" SHA256 = "SHA256" SHA384 = "SHA384" SHA512 = "SHA512" class VPNCompression(str, PyEnum): """VPN compression options.""" NONE = "none" LZ4 = "lz4" LZ4_V2 = "lz4-v2" LZO = "lzo" class VPNServerStatus(str, PyEnum): """VPN Server status.""" PENDING = "pending" # Server created but not started STARTING = "starting" # Container starting RUNNING = "running" # Server running STOPPED = "stopped" # Server stopped ERROR = "error" # Error state class VPNServer(Base): """VPN Server instance configuration.""" __tablename__ = "vpn_servers" id = Column(Integer, primary_key=True, index=True) tenant_id = Column(Integer, ForeignKey("tenants.id"), nullable=True) # NULL for global ca_id = Column(Integer, ForeignKey("certificate_authorities.id"), nullable=False) # Basic info name = Column(String(255), nullable=False) description = Column(Text, nullable=True) # Network configuration hostname = Column(String(255), nullable=False) # External hostname/IP port = Column(Integer, default=1194, nullable=False) protocol = Column(Enum(VPNProtocol), default=VPNProtocol.UDP, nullable=False) # VPN network vpn_network = Column(String(18), default="10.8.0.0", nullable=False) # CIDR or IP vpn_netmask = Column(String(15), default="255.255.255.0", nullable=False) # Server certificate (PEM encoded) server_cert = Column(Text, nullable=True) server_key = Column(Text, nullable=True) ta_key = Column(Text, nullable=True) # TLS-Auth key # Security settings cipher = Column(Enum(VPNCipher), default=VPNCipher.AES_256_GCM) auth = Column(Enum(VPNAuth), default=VPNAuth.SHA256) tls_version_min = Column(String(10), default="1.2") tls_auth_enabled = Column(Boolean, default=True) # Performance settings compression = Column(Enum(VPNCompression), default=VPNCompression.NONE) max_clients = Column(Integer, default=100) keepalive_interval = Column(Integer, default=10) # seconds keepalive_timeout = Column(Integer, default=60) # seconds # Docker settings docker_container_name = Column(String(255), nullable=True) management_port = Column(Integer, default=7505) # Status status = Column(Enum(VPNServerStatus), default=VPNServerStatus.PENDING) is_active = Column(Boolean, default=True) is_primary = Column(Boolean, default=False) # Primary server for tenant auto_start = Column(Boolean, default=True) # Start on system boot # Statistics (updated periodically) connected_clients = Column(Integer, default=0) last_status_check = Column(DateTime, nullable=True) # Audit created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Relationships tenant = relationship("Tenant", back_populates="vpn_servers") certificate_authority = relationship("CertificateAuthority", back_populates="vpn_servers") vpn_profiles = relationship("VPNProfile", back_populates="vpn_server") client_vpn_profiles = relationship("ClientVPNProfile", back_populates="vpn_server") def __repr__(self): return f"" @property def is_ready(self) -> bool: """Check if server is ready to accept connections.""" return ( self.server_cert is not None and self.server_key is not None and self.certificate_authority is not None and self.certificate_authority.is_ready ) @property def connection_string(self) -> str: """Get connection string for display.""" return f"{self.hostname}:{self.port}/{self.protocol.value.upper()}" def get_docker_port_mapping(self) -> dict: """Get Docker port mapping for this server.""" return {f"{self.port}/{self.protocol.value}": self.port}