feat: add node agent system with heartbeat collection, installer generation, and traffic flow telemetry
Add NodeAgent and TrafficFlow models to track agent status and network flows, implement /agents/heartbeat endpoint to receive interface counters, conntrack flows, firewall status, and nftables ruleset hash from agents, add nexafabric-agent.py Python script to collect host telemetry including VM/LXC interface hints via tap/fwbr regex matching, conntrack flow parsing with protocol/state/byte counters, and pve-firewall status checks,
This commit is contained in:
@@ -2,7 +2,7 @@ from datetime import datetime
|
||||
from enum import StrEnum
|
||||
from uuid import uuid4
|
||||
|
||||
from sqlalchemy import JSON, Boolean, DateTime, Enum, ForeignKey, Integer, String, Text, UniqueConstraint
|
||||
from sqlalchemy import JSON, BigInteger, Boolean, DateTime, Enum, ForeignKey, Integer, String, Text, UniqueConstraint
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.db.session import Base
|
||||
@@ -129,6 +129,18 @@ class Node(Base, TimestampMixin):
|
||||
cluster: Mapped[Cluster] = relationship()
|
||||
|
||||
|
||||
class NodeAgent(Base, TimestampMixin):
|
||||
__tablename__ = "node_agents"
|
||||
|
||||
node_id: Mapped[str] = mapped_column(ForeignKey("nodes.id"), primary_key=True)
|
||||
status: Mapped[str] = mapped_column(String(100), default="not_installed")
|
||||
version: Mapped[str | None] = mapped_column(String(50))
|
||||
last_seen_at: Mapped[datetime | None] = mapped_column(DateTime)
|
||||
last_payload: Mapped[dict | None] = mapped_column(JSON)
|
||||
install_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
node: Mapped[Node] = relationship()
|
||||
|
||||
|
||||
class Workload(Base, TimestampMixin):
|
||||
__tablename__ = "workloads"
|
||||
|
||||
@@ -183,6 +195,23 @@ class IpAddress(Base, TimestampMixin):
|
||||
note: Mapped[str | None] = mapped_column(Text)
|
||||
|
||||
|
||||
class TrafficFlow(Base, TimestampMixin):
|
||||
__tablename__ = "traffic_flows"
|
||||
|
||||
id: Mapped[str] = mapped_column(String, primary_key=True, default=new_id)
|
||||
node_id: Mapped[str] = mapped_column(ForeignKey("nodes.id"), index=True)
|
||||
source_ip: Mapped[str] = mapped_column(String(100), index=True)
|
||||
destination_ip: Mapped[str] = mapped_column(String(100), index=True)
|
||||
protocol: Mapped[str] = mapped_column(String(20), default="unknown")
|
||||
source_port: Mapped[int | None] = mapped_column(Integer)
|
||||
destination_port: Mapped[int | None] = mapped_column(Integer)
|
||||
bytes: Mapped[int] = mapped_column(BigInteger, default=0)
|
||||
packets: Mapped[int] = mapped_column(BigInteger, default=0)
|
||||
state: Mapped[str | None] = mapped_column(String(100))
|
||||
observed_at: Mapped[datetime | None] = mapped_column(DateTime)
|
||||
raw: Mapped[dict | None] = mapped_column(JSON)
|
||||
|
||||
|
||||
class SecurityGroup(Base, TimestampMixin):
|
||||
__tablename__ = "security_groups"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user