from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Enum, Boolean, Float from sqlalchemy.orm import relationship from sqlalchemy.sql import func from app.core.database import Base import enum class AlertType(str, enum.Enum): """告警类型""" IP_CONFLICT = "ip_conflict" # IP 冲突 UNAUTHORIZED_ACCESS = "unauthorized_access" # 未授权接入 SUBNET_FULL = "subnet_full" # 网段耗尽 SCAN_FAILED = "scan_failed" # 扫描失败 DEVICE_OFFLINE = "device_offline" # 设备离线 NEW_DEVICE_DETECTED = "new_device_detected" # 新设备发现 MAC_CHANGED = "mac_changed" # MAC 地址变化 class AlertSeverity(str, enum.Enum): """告警级别""" INFO = "info" # 信息 WARNING = "warning" # 警告 ERROR = "error" # 错误 CRITICAL = "critical" # 严重 class AlertStatus(str, enum.Enum): """告警状态""" ACTIVE = "active" # 活跃 ACKNOWLEDGED = "acknowledged" # 已确认 RESOLVED = "resolved" # 已解决 IGNORED = "ignored" # 已忽略 class Alert(Base): """告警""" __tablename__ = "alerts" id = Column(Integer, primary_key=True, index=True) alert_type = Column(Enum(AlertType), nullable=False, index=True) severity = Column(Enum(AlertSeverity), default=AlertSeverity.WARNING, index=True) status = Column(Enum(AlertStatus), default=AlertStatus.ACTIVE, index=True) title = Column(String(255), nullable=False) message = Column(Text) # 关联对象 network_id = Column(Integer, ForeignKey("networks.id"), nullable=True) ip_address_id = Column(Integer, ForeignKey("ip_addresses.id"), nullable=True) device_id = Column(Integer, ForeignKey("network_devices.id"), nullable=True) ip_address_str = Column(String(50), nullable=True) # 冗余存储便于查询 # 关联的 IP/MAC 信息 mac_address = Column(String(50), nullable=True) conflicting_mac = Column(String(50), nullable=True) # 用于 IP 冲突告警 # 统计信息 usage_percent = Column(Float, nullable=True) # 网段使用率告警时存储 # 处理信息 acknowledged_by = Column(String(100), nullable=True) acknowledged_at = Column(DateTime(timezone=True), nullable=True) resolved_by = Column(String(100), nullable=True) resolved_at = Column(DateTime(timezone=True), nullable=True) resolution_notes = Column(Text, nullable=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), index=True) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) # 关系 network = relationship("Network") ip_address = relationship("IPAddress") device = relationship("NetworkDevice") class AlertRule(Base): """告警规则配置""" __tablename__ = "alert_rules" id = Column(Integer, primary_key=True, index=True) name = Column(String(100), unique=True, nullable=False) description = Column(Text, nullable=True) alert_type = Column(Enum(AlertType), nullable=False) severity = Column(Enum(AlertSeverity), default=AlertSeverity.WARNING) # 规则条件 enabled = Column(Boolean, default=True) # 阈值配置 subnet_usage_threshold = Column(Float, default=90.0) # 网段使用率阈值 % scan_failure_threshold = Column(Integer, default=3) # 扫描失败次数阈值 inactivity_threshold_minutes = Column(Integer, default=60) # 设备不活动阈值(分钟) # MAC 白名单(用于未授权接入检测) mac_whitelist_enabled = Column(Boolean, default=False) mac_whitelist = Column(Text, nullable=True) # JSON 格式的 MAC 列表 # 通知配置 notify_email = Column(Boolean, default=False) notify_webhook = Column(Boolean, default=False) notification_channels = Column(Text, nullable=True) # JSON 格式的通知渠道 created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) class WhitelistedMAC(Base): """MAC 地址白名单""" __tablename__ = "whitelisted_macs" id = Column(Integer, primary_key=True, index=True) mac_address = Column(String(50), unique=True, nullable=False, index=True) description = Column(String(255), nullable=True) owner = Column(String(100), nullable=True) is_active = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now())