Accumulated uncommitted infra changes: - Caddyfile: repoint HA/Zabbix to 192.168.1.4/.3, add ~20 new site routes - Immich: move media to /mnt/smsg, enable CUDA ML, mem limits, rewrite backup.sh - Add service stacks: agap-mcp, anki, family, freshrss, iperf3, kanboard, linkwarden, qbittorrent, radicale, syncthing, vikunja, windows - openwebui: enable API keys; ollama: drop CPU fallback - seafile/zabbix: extra_hosts entries; matrix: add user juris - Remove pihole stack and stale wiki/migrate.py - Ignore marketplace-mcp (standalone repo) and linkwarden runtime data Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
76 lines
2.3 KiB
JavaScript
76 lines
2.3 KiB
JavaScript
const BASE = () => `${process.env.ZABBIX_URL || 'http://localhost:81'}/api_jsonrpc.php`;
|
|
let _token = null;
|
|
let _reqId = 1;
|
|
|
|
export function initZabbix(token) {
|
|
_token = token;
|
|
console.log('Zabbix: ready');
|
|
}
|
|
|
|
async function api(method, params = {}) {
|
|
const res = await fetch(BASE(), {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${_token}` },
|
|
body: JSON.stringify({ jsonrpc: '2.0', method, params, id: _reqId++ }),
|
|
});
|
|
const data = await res.json();
|
|
if (data.error) throw new Error(`Zabbix ${method}: ${data.error.data}`);
|
|
return data.result;
|
|
}
|
|
|
|
export async function zabbixGetProblems() {
|
|
const problems = await api('problem.get', {
|
|
output: ['eventid', 'name', 'severity', 'clock', 'acknowledged'],
|
|
selectAcknowledges: 'count',
|
|
recent: true,
|
|
sortfield: 'eventid',
|
|
sortorder: 'DESC',
|
|
});
|
|
return problems.map(p => ({
|
|
id: p.eventid,
|
|
name: p.name,
|
|
severity: ['Not classified','Information','Warning','Average','High','Disaster'][+p.severity],
|
|
time: new Date(+p.clock * 1000).toISOString(),
|
|
acknowledged: +p.acknowledged > 0,
|
|
}));
|
|
}
|
|
|
|
export async function zabbixGetHosts() {
|
|
return api('host.get', {
|
|
output: ['hostid', 'host', 'name', 'available', 'status'],
|
|
selectInterfaces: ['ip'],
|
|
}).then(hosts => hosts.map(h => ({
|
|
id: h.hostid,
|
|
name: h.name || h.host,
|
|
available: ['Unknown','Available','Unavailable'][+h.available] || 'Unknown',
|
|
enabled: h.status === '0',
|
|
ip: h.interfaces?.[0]?.ip,
|
|
})));
|
|
}
|
|
|
|
export async function zabbixGetItems(hostid) {
|
|
return api('item.get', {
|
|
output: ['itemid', 'name', 'key_', 'lastvalue', 'units', 'lastclock'],
|
|
hostids: hostid,
|
|
monitored: true,
|
|
sortfield: 'name',
|
|
}).then(items => items.map(i => ({
|
|
name: i.name,
|
|
key: i.key_,
|
|
value: i.lastvalue,
|
|
units: i.units,
|
|
updated: new Date(+i.lastclock * 1000).toISOString(),
|
|
})));
|
|
}
|
|
|
|
export async function zabbixGetTriggers(hostid) {
|
|
const params = { output: ['triggerid','description','priority','value'], active: 1, monitored: 1 };
|
|
if (hostid) params.hostids = hostid;
|
|
return api('trigger.get', params).then(triggers => triggers.map(t => ({
|
|
id: t.triggerid,
|
|
name: t.description,
|
|
severity: ['Not classified','Information','Warning','Average','High','Disaster'][+t.priority],
|
|
problem: t.value === '1',
|
|
})));
|
|
}
|