fix(checkmk): use monitoring collection endpoint, batch state fetch, clearer Settings hints
This commit is contained in:
54
server.ts
54
server.ts
@ -712,14 +712,15 @@ async function startServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const authHeader = `Bearer ${CHECKMK_API_USER} ${CHECKMK_API_SECRET}`;
|
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
|
// Step 1: build IP → hostname map from host configuration
|
||||||
// Falls back to effective_attributes for IPs inherited from a parent folder.
|
// Checks both attributes (explicitly set) and effective_attributes (inherited).
|
||||||
let ipToHostname: Map<string, string>;
|
let ipToHostname: Map<string, string>;
|
||||||
try {
|
try {
|
||||||
const cfgRes = await fetch(
|
const cfgRes = await fetch(
|
||||||
`${CHECKMK_API_URL}/domain-types/host_config/collections/all`,
|
`${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));
|
if (!cfgRes.ok) throw new Error(checkmkHttpHint(cfgRes.status));
|
||||||
const cfgData = await cfgRes.json();
|
const cfgData = await cfgRes.json();
|
||||||
@ -739,7 +740,32 @@ async function startServer() {
|
|||||||
return;
|
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<string, number>;
|
||||||
|
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<string, number>();
|
||||||
|
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 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 counts = { online: 0, offline: 0, unknown: 0 };
|
||||||
|
|
||||||
@ -754,28 +780,14 @@ async function startServer() {
|
|||||||
counts.unknown++;
|
counts.unknown++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
const state = hostnameToState.get(cmkHost);
|
||||||
const res = await fetch(
|
const newStatus = state === 0 ? 'online' : state === 1 || state === 2 ? 'offline' : 'unknown';
|
||||||
`${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);
|
db.prepare('UPDATE devices SET status = ?, lastCheckedAt = ? WHERE id = ?').run(newStatus, now, dev.id);
|
||||||
if (dev.status !== newStatus) {
|
if (dev.status !== newStatus) {
|
||||||
db.prepare('INSERT INTO logs (id, timestamp, type, message, deviceId) VALUES (?, ?, ?, ?, ?)')
|
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);
|
.run(uid('log'), now, 'status', `CheckMK: ${dev.hostname} (${dev.ip}) status changed to ${newStatus} (was: ${dev.status}).`, dev.id);
|
||||||
}
|
}
|
||||||
counts[newStatus as 'online' | 'offline']++;
|
counts[newStatus as 'online' | 'offline' | 'unknown']++;
|
||||||
} 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++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db.prepare('INSERT INTO logs (id, timestamp, type, message) VALUES (?, ?, ?, ?)')
|
db.prepare('INSERT INTO logs (id, timestamp, type, message) VALUES (?, ?, ?, ?)')
|
||||||
|
|||||||
@ -449,7 +449,7 @@ export default function Settings({ currentUser: _currentUser }: SettingsProps) {
|
|||||||
/>
|
/>
|
||||||
</FieldRow>
|
</FieldRow>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
|
||||||
<FieldRow label="Automation User" hint="CheckMK automation user (default: automation)">
|
<FieldRow label="Automation User" hint="Setup → Users → Automation user (e.g. automation)">
|
||||||
<Input
|
<Input
|
||||||
value={checkmkApiUser}
|
value={checkmkApiUser}
|
||||||
onChange={setCheckmkApiUser}
|
onChange={setCheckmkApiUser}
|
||||||
@ -460,6 +460,7 @@ export default function Settings({ currentUser: _currentUser }: SettingsProps) {
|
|||||||
</FieldRow>
|
</FieldRow>
|
||||||
<FieldRow
|
<FieldRow
|
||||||
label="Automation Secret"
|
label="Automation Secret"
|
||||||
|
hint="Setup → Users → Automation user → Automation secret"
|
||||||
badge={checkmkSecretSet ? <ConfiguredBadge /> : undefined}
|
badge={checkmkSecretSet ? <ConfiguredBadge /> : undefined}
|
||||||
>
|
>
|
||||||
<SecretInput
|
<SecretInput
|
||||||
|
|||||||
Reference in New Issue
Block a user