openvpn-endpoint-server/server/app/models/gateway.py

92 lines
3.5 KiB
Python

"""Gateway model for mGuard routers."""
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 RouterType(str, PyEnum):
"""Supported mGuard router types."""
FL_MGUARD_2000 = "FL_MGUARD_2000"
FL_MGUARD_4000 = "FL_MGUARD_4000"
FL_MGUARD_RS4000 = "FL_MGUARD_RS4000"
FL_MGUARD_1000 = "FL_MGUARD_1000"
class ProvisioningMethod(str, PyEnum):
"""Method used to provision the gateway."""
REST_API = "rest_api" # For firmware 10.5.x+
SSH = "ssh" # For older firmware
ATV_FILE = "atv_file" # Offline via config file
class Gateway(Base):
"""Gateway model representing an mGuard router."""
__tablename__ = "gateways"
id = Column(Integer, primary_key=True, index=True)
tenant_id = Column(Integer, ForeignKey("tenants.id"), nullable=False)
# Basic info
name = Column(String(255), nullable=False)
description = Column(Text, nullable=True)
location = Column(String(255), nullable=True) # Physical location
# Router details
serial_number = Column(String(100), nullable=True, unique=True)
router_type = Column(Enum(RouterType), nullable=False)
firmware_version = Column(String(50), nullable=True)
provisioning_method = Column(Enum(ProvisioningMethod), default=ProvisioningMethod.ATV_FILE)
# VPN configuration
vpn_ip = Column(String(45), nullable=True, unique=True) # IPv4/IPv6
vpn_cert_cn = Column(String(255), nullable=True, unique=True) # Certificate Common Name
vpn_subnet = Column(String(50), nullable=True) # Network behind gateway, e.g., "10.0.0.0/24"
# Status
is_online = Column(Boolean, default=False, nullable=False)
is_provisioned = Column(Boolean, default=False, nullable=False)
last_seen = Column(DateTime, nullable=True)
last_config_update = Column(DateTime, nullable=True)
# Timestamps
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="gateways")
endpoints = relationship("Endpoint", back_populates="gateway", cascade="all, delete-orphan")
user_access = relationship("UserGatewayAccess", back_populates="gateway", cascade="all, delete-orphan")
connection_logs = relationship("ConnectionLog", back_populates="gateway")
vpn_profiles = relationship("VPNProfile", back_populates="gateway", cascade="all, delete-orphan", order_by="VPNProfile.priority")
def __repr__(self):
return f"<Gateway(id={self.id}, name='{self.name}', type='{self.router_type}')>"
@property
def supports_rest_api(self) -> bool:
"""Check if gateway supports REST API (firmware 10.x+)."""
if not self.firmware_version:
return False
try:
major_version = int(self.firmware_version.split('.')[0])
return major_version >= 10
except (ValueError, IndexError):
return False
@property
def primary_profile(self):
"""Get the primary VPN profile (highest priority)."""
active_profiles = [p for p in self.vpn_profiles if p.is_active]
if active_profiles:
return min(active_profiles, key=lambda p: p.priority)
return None
@property
def has_vpn_profiles(self) -> bool:
"""Check if gateway has any VPN profiles."""
return len(self.vpn_profiles) > 0