From 14dcda3cdcef4c354ddbd64a6ed5177626a7b68b Mon Sep 17 00:00:00 2001 From: zhi Date: Fri, 20 Mar 2026 10:03:56 +0000 Subject: [PATCH] feat(monitor): store nginx telemetry for generic clients - accept nginx installation status and sites-enabled list - persist nginx fields in server state - expose nginx data in monitor overview/admin views - auto-migrate new server_states columns on startup --- app/api/routers/monitor.py | 8 ++++++++ app/main.py | 6 ++++++ app/models/monitor.py | 2 ++ app/services/monitoring.py | 2 ++ 4 files changed, 18 insertions(+) diff --git a/app/api/routers/monitor.py b/app/api/routers/monitor.py index ba5557f..88ca447 100644 --- a/app/api/routers/monitor.py +++ b/app/api/routers/monitor.py @@ -180,6 +180,8 @@ class ServerHeartbeat(BaseModel): openclaw_version: str | None = None plugin_version: str | None = None agents: List[dict] = [] + nginx_installed: bool | None = None + nginx_sites: List[str] = [] cpu_pct: float | None = None mem_pct: float | None = None disk_pct: float | None = None @@ -198,6 +200,8 @@ def server_heartbeat(payload: ServerHeartbeat, db: Session = Depends(get_db)): st.openclaw_version = payload.openclaw_version st.plugin_version = payload.plugin_version st.agents_json = json.dumps(payload.agents, ensure_ascii=False) + st.nginx_installed = payload.nginx_installed + st.nginx_sites_json = json.dumps(payload.nginx_sites, ensure_ascii=False) st.cpu_pct = payload.cpu_pct st.mem_pct = payload.mem_pct st.disk_pct = payload.disk_pct @@ -213,6 +217,8 @@ class TelemetryPayload(BaseModel): openclaw_version: str | None = None plugin_version: str | None = None agents: List[dict] = [] + nginx_installed: bool | None = None + nginx_sites: List[str] = [] cpu_pct: float | None = None mem_pct: float | None = None disk_pct: float | None = None @@ -241,6 +247,8 @@ def server_heartbeat_v2( st.openclaw_version = payload.openclaw_version st.plugin_version = payload.plugin_version st.agents_json = json.dumps(payload.agents, ensure_ascii=False) + st.nginx_installed = payload.nginx_installed + st.nginx_sites_json = json.dumps(payload.nginx_sites, ensure_ascii=False) st.cpu_pct = payload.cpu_pct st.mem_pct = payload.mem_pct st.disk_pct = payload.disk_pct diff --git a/app/main.py b/app/main.py index 7d85ef7..63a267a 100644 --- a/app/main.py +++ b/app/main.py @@ -224,6 +224,12 @@ def _migrate_schema(): if _has_table(db, "server_states") and not _has_column(db, "server_states", "plugin_version"): db.execute(text("ALTER TABLE server_states ADD COLUMN plugin_version VARCHAR(64) NULL")) + # --- server_states nginx telemetry for generic monitor client --- + if _has_table(db, "server_states") and not _has_column(db, "server_states", "nginx_installed"): + db.execute(text("ALTER TABLE server_states ADD COLUMN nginx_installed BOOLEAN NULL")) + if _has_table(db, "server_states") and not _has_column(db, "server_states", "nginx_sites_json"): + db.execute(text("ALTER TABLE server_states ADD COLUMN nginx_sites_json TEXT NULL")) + db.commit() except Exception as e: db.rollback() diff --git a/app/models/monitor.py b/app/models/monitor.py index b16a04f..a563236 100644 --- a/app/models/monitor.py +++ b/app/models/monitor.py @@ -52,6 +52,8 @@ class ServerState(Base): openclaw_version = Column(String(64), nullable=True) plugin_version = Column(String(64), nullable=True) agents_json = Column(Text, nullable=True) # json list + nginx_installed = Column(Boolean, nullable=True) + nginx_sites_json = Column(Text, nullable=True) # json list cpu_pct = Column(Float, nullable=True) mem_pct = Column(Float, nullable=True) disk_pct = Column(Float, nullable=True) diff --git a/app/services/monitoring.py b/app/services/monitoring.py index 0f10811..c297966 100644 --- a/app/services/monitoring.py +++ b/app/services/monitoring.py @@ -304,6 +304,8 @@ def get_server_states_view(db: Session, offline_after_minutes: int = 7): 'disk_pct': st.disk_pct if st else None, 'swap_pct': st.swap_pct if st else None, 'agents': json.loads(st.agents_json) if st and st.agents_json else [], + 'nginx_installed': st.nginx_installed if st else None, + 'nginx_sites': json.loads(st.nginx_sites_json) if st and st.nginx_sites_json else [], 'last_seen_at': last_seen.isoformat() if last_seen else None, }) return out