diff --git a/server.ts b/server.ts index 8f8bdb6..ca5f7fe 100644 --- a/server.ts +++ b/server.ts @@ -125,6 +125,10 @@ async function startServer() { const token = jwt.sign({ userId: row.id, email: row.email }, JWT_SECRET, { expiresIn: JWT_EXPIRY }); const user: User = { id: row.id, name: row.name, role: row.role, email: row.email }; + const logId = uid("log"); + db.prepare(`INSERT INTO logs (id, timestamp, type, message, deviceId, userId) VALUES (?, ?, ?, ?, ?, ?)`) + .run(logId, new Date().toISOString(), 'system', `${row.name} logged in.`, null, row.id); + res.json({ token, user }); } catch (err: any) { res.status(500).json({ error: err.message }); @@ -686,36 +690,51 @@ async function startServer() { // in Settings take effect on the next cycle without a server restart. // ------------------------------------------------------------- async function syncCheckMkStatuses() { + const now = new Date().toISOString(); + if (getSetting('checkmk_enabled') !== 'true') return; + const CHECKMK_API_URL = getSetting('checkmk_api_url') || process.env.CHECKMK_API_URL; const CHECKMK_API_USER = getSetting('checkmk_api_user') || process.env.CHECKMK_API_USER || 'automation'; const CHECKMK_API_SECRET = getSetting('checkmk_api_secret') || process.env.CHECKMK_API_SECRET; - if (!CHECKMK_API_URL || !CHECKMK_API_SECRET) return; + + if (!CHECKMK_API_URL || !CHECKMK_API_SECRET) { + db.prepare('INSERT INTO logs (id, timestamp, type, message) VALUES (?, ?, ?, ?)') + .run(uid('log'), now, 'system', 'CheckMK sync skipped — API URL or secret not configured. Check Settings.'); + return; + } + + const authHeader = `Bearer ${CHECKMK_API_USER} ${CHECKMK_API_SECRET}`; // Step 1: build IP → hostname map from CheckMK host configurations + // Falls back to effective_attributes for IPs inherited from a parent folder. let ipToHostname: Map; try { const cfgRes = await fetch( `${CHECKMK_API_URL}/domain-types/host_config/collections/all`, - { headers: { Authorization: `Bearer ${CHECKMK_API_USER} ${CHECKMK_API_SECRET}`, Accept: 'application/json' } } + { headers: { Authorization: authHeader, Accept: 'application/json' } } ); - if (!cfgRes.ok) throw new Error(`HTTP ${cfgRes.status}`); + if (!cfgRes.ok) throw new Error(`HTTP ${cfgRes.status} — ${await cfgRes.text()}`); const cfgData = await cfgRes.json(); ipToHostname = new Map(); for (const host of cfgData?.value ?? []) { - const ip: string | undefined = host?.extensions?.attributes?.ipaddress; + const ext = host?.extensions; + const ip: string | undefined = + ext?.attributes?.ipaddress || ext?.effective_attributes?.ipaddress; const name: string | undefined = host?.id; if (ip && name) ipToHostname.set(ip, name); } - } catch (err) { - console.error('[CheckMK] Failed to fetch host configs:', err); + } catch (err: any) { + const msg = `CheckMK sync failed — could not fetch host list: ${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 2: update each device based on IP lookup and log status changes 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 }; - const now = new Date().toISOString(); for (const dev of rows) { const cmkHost = ipToHostname.get(dev.ip); @@ -731,9 +750,9 @@ async function startServer() { try { const res = await fetch( `${CHECKMK_API_URL}/objects/host/${encodeURIComponent(cmkHost)}`, - { headers: { Authorization: `Bearer ${CHECKMK_API_USER} ${CHECKMK_API_SECRET}`, Accept: 'application/json' } } + { headers: { Authorization: authHeader, Accept: 'application/json' } } ); - if (!res.ok) throw new Error(`HTTP ${res.status}`); + if (!res.ok) throw new Error(`HTTP ${res.status} — ${await res.text()}`); const data = await res.json(); const hardState: number = data?.extensions?.state ?? -1; const newStatus = hardState === 0 ? 'online' : 'offline'; @@ -743,13 +762,15 @@ async function startServer() { .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) { - console.error(`[CheckMK] Status sync failed for ${dev.hostname} (${dev.ip}):`, err); + } catch (err: any) { + const msg = `CheckMK: status sync failed for ${dev.hostname} (${dev.ip}) — ${err?.message ?? err}`; + console.error('[CheckMK]', msg); + db.prepare('INSERT INTO logs (id, timestamp, type, message, deviceId) VALUES (?, ?, ?, ?, ?)') + .run(uid('log'), now, 'system', msg, dev.id); counts.unknown++; } } - // Summary log entry for every sync run db.prepare('INSERT INTO logs (id, timestamp, type, message) VALUES (?, ?, ?, ?)') .run(uid('log'), now, 'system', `CheckMK sync completed — ${counts.online} online, ${counts.offline} offline, ${counts.unknown} unknown (${rows.length} devices total).`);