From 626871213d7282b985aae74d898ce6c5c86739c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Br=C3=BCckner?= Date: Thu, 4 Jun 2026 14:48:15 +0200 Subject: [PATCH] fix(checkmk): use monitoring collection endpoint, batch state fetch, clearer Settings hints --- server.ts | 60 ++++++++++++++++++++++--------------- src/components/Settings.tsx | 3 +- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/server.ts b/server.ts index 75d2dba..571659a 100644 --- a/server.ts +++ b/server.ts @@ -712,14 +712,15 @@ async function startServer() { } const authHeader = `Bearer ${CHECKMK_API_USER} ${CHECKMK_API_SECRET}`; + const headers = { Authorization: authHeader, Accept: 'application/json' }; - // Step 1: build IP → hostname map from CheckMK host configurations - // Falls back to effective_attributes for IPs inherited from a parent folder. + // Step 1: build IP → hostname map from host configuration + // Checks both attributes (explicitly set) and effective_attributes (inherited). let ipToHostname: Map; try { const cfgRes = await fetch( `${CHECKMK_API_URL}/domain-types/host_config/collections/all`, - { headers: { Authorization: authHeader, Accept: 'application/json' } } + { headers } ); if (!cfgRes.ok) throw new Error(checkmkHttpHint(cfgRes.status)); const cfgData = await cfgRes.json(); @@ -739,7 +740,32 @@ async function startServer() { return; } - // Step 2: update each device based on IP lookup and log status changes + // Step 2: fetch live monitoring state for all hosts in one call. + // /domain-types/host/collections/all returns monitoring objects with extensions.state + // where 0=UP, 1=DOWN, 2=UNREACHABLE. + let hostnameToState: Map; + try { + const monRes = await fetch( + `${CHECKMK_API_URL}/domain-types/host/collections/all`, + { headers } + ); + if (!monRes.ok) throw new Error(checkmkHttpHint(monRes.status)); + const monData = await monRes.json(); + hostnameToState = new Map(); + for (const host of monData?.value ?? []) { + const name: string | undefined = host?.id; + const state: number | undefined = host?.extensions?.state; + if (name !== undefined && state !== undefined) hostnameToState.set(name, state); + } + } catch (err: any) { + const msg = `CheckMK sync failed — could not fetch monitoring states: ${err?.message ?? err}`; + console.error('[CheckMK]', msg); + db.prepare('INSERT INTO logs (id, timestamp, type, message) VALUES (?, ?, ?, ?)') + .run(uid('log'), now, 'system', msg); + return; + } + + // Step 3: update each device based on IP lookup + live state const rows = db.prepare('SELECT id, hostname, ip, status FROM devices').all() as { id: string; hostname: string; ip: string; status: string }[]; const counts = { online: 0, offline: 0, unknown: 0 }; @@ -754,28 +780,14 @@ async function startServer() { counts.unknown++; continue; } - try { - const res = await fetch( - `${CHECKMK_API_URL}/objects/host/${encodeURIComponent(cmkHost)}`, - { headers: { Authorization: authHeader, Accept: 'application/json' } } - ); - if (!res.ok) throw new Error(checkmkHttpHint(res.status)); - const data = await res.json(); - const hardState: number = data?.extensions?.state ?? -1; - const newStatus = hardState === 0 ? 'online' : 'offline'; - db.prepare('UPDATE devices SET status = ?, lastCheckedAt = ? WHERE id = ?').run(newStatus, now, dev.id); - if (dev.status !== newStatus) { - db.prepare('INSERT INTO logs (id, timestamp, type, message, deviceId) VALUES (?, ?, ?, ?, ?)') - .run(uid('log'), now, 'status', `CheckMK: ${dev.hostname} (${dev.ip}) status changed to ${newStatus} (was: ${dev.status}).`, dev.id); - } - counts[newStatus as 'online' | 'offline']++; - } catch (err: any) { - const msg = `CheckMK: status sync failed for ${dev.hostname} (${dev.ip}) — ${err?.message ?? err}`; - console.error('[CheckMK]', msg); + const state = hostnameToState.get(cmkHost); + const newStatus = state === 0 ? 'online' : state === 1 || state === 2 ? 'offline' : 'unknown'; + db.prepare('UPDATE devices SET status = ?, lastCheckedAt = ? WHERE id = ?').run(newStatus, now, dev.id); + if (dev.status !== newStatus) { db.prepare('INSERT INTO logs (id, timestamp, type, message, deviceId) VALUES (?, ?, ?, ?, ?)') - .run(uid('log'), now, 'system', msg, dev.id); - counts.unknown++; + .run(uid('log'), now, 'status', `CheckMK: ${dev.hostname} (${dev.ip}) status changed to ${newStatus} (was: ${dev.status}).`, dev.id); } + counts[newStatus as 'online' | 'offline' | 'unknown']++; } db.prepare('INSERT INTO logs (id, timestamp, type, message) VALUES (?, ?, ?, ?)') diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index fd48d80..9d4d663 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -449,7 +449,7 @@ export default function Settings({ currentUser: _currentUser }: SettingsProps) { />
- + : undefined} >