Das Problem
“I felt a great disturbance in the Force, as if millions of API calls suddenly cried out in terror and were suddenly silenced.”
Nach dem Upgrade auf Zabbix 7.0 funktioniert dein selbstgeschriebenes Dashboard nicht mehr:
HTTP 502 Bad Gateway
Oder noch kryptischer:
{
"error": {
"code": -32602,
"message": "Invalid params.",
"data": "Invalid parameter \"/\": unexpected parameter \"selectHosts\"."
}
}
Gestern hat noch alles funktioniert. Was ist passiert?
TL;DR
Zabbix 7.0 hat zwei Breaking Changes in der API:
- Auth-Token: Nur noch im JSON-Body, nicht mehr im
AuthorizationHeader selectHostsbeiproblem.get: Parameter entfernt, nutzeevent.getstattdessen
Diagnose: Ist mein Code betroffen?
Wenn dein Dashboard nach dem Zabbix 7.0 Upgrade kaputt ist, prüfe diese Punkte:
Test 1: Alte Auth-Methode (wird ignoriert)
curl -s 'http://zabbix.deathstar.lan:8080/api_jsonrpc.php' \
-H 'Content-Type: application/json-rpc' \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{"jsonrpc":"2.0","method":"problem.get","params":{"recent":true},"id":1}'
Ergebnis: "Not authorised" oder "Invalid params"
Test 2: Neue Auth-Methode (funktioniert)
curl -s 'http://zabbix.deathstar.lan:8080/api_jsonrpc.php' \
-H 'Content-Type: application/json-rpc' \
-d '{"jsonrpc":"2.0","method":"problem.get","params":{"recent":true},"auth":"YOUR_TOKEN","id":1}'
Ergebnis: Array mit Problemen
Test 3: selectHosts mit problem.get (broken)
curl -s 'http://zabbix.deathstar.lan:8080/api_jsonrpc.php' \
-H 'Content-Type: application/json-rpc' \
-d '{"jsonrpc":"2.0","method":"problem.get","params":{"output":["eventid"],"selectHosts":["host"]},"auth":"YOUR_TOKEN","id":1}'
Ergebnis: "Invalid parameter \"/\" unexpected parameter \"selectHosts\""
Test 4: Workaround mit event.get (funktioniert)
curl -s 'http://zabbix.deathstar.lan:8080/api_jsonrpc.php' \
-H 'Content-Type: application/json-rpc' \
-d '{"jsonrpc":"2.0","method":"event.get","params":{"output":["eventid"],"selectHosts":["host"]},"auth":"YOUR_TOKEN","id":1}'
Ergebnis: Array mit Events + Hosts
Breaking Change 1: Auth-Token im Body
Vorher (Zabbix 6.x)
const response = await fetch(ZABBIX_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json-rpc',
'Authorization': `Bearer ${token}`, // Token im Header
},
body: JSON.stringify({
jsonrpc: '2.0',
method: 'problem.get',
params: { recent: true },
id: 1,
}),
});
Nachher (Zabbix 7.0+)
const response = await fetch(ZABBIX_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json-rpc',
// KEIN Authorization Header mehr!
},
body: JSON.stringify({
jsonrpc: '2.0',
method: 'problem.get',
params: { recent: true },
id: 1,
auth: token, // Token hier im Body!
}),
});
Der Authorization: Bearer Header wird in Zabbix 7.0 komplett ignoriert. Das Resultat ist ein 502 Bad Gateway oder eine “Not authorised” Meldung.
Breaking Change 2: selectHosts bei problem.get
Viele Dashboards nutzen problem.get mit selectHosts um sowohl die Probleme als auch die betroffenen Hosts in einem Request zu bekommen:
// FUNKTIONIERT NICHT MEHR IN ZABBIX 7.0!
const problems = await zabbixRequest('problem.get', {
output: ['eventid', 'name', 'severity'],
selectHosts: ['host', 'name'], // <-- Fehler!
recent: true,
});
Der Workaround
In Zabbix 7.0 musst du zwei Requests machen:
// 1. Probleme holen (ohne Host-Info)
const problems = await zabbixRequest('problem.get', {
output: ['eventid', 'objectid', 'clock', 'name', 'severity', 'acknowledged'],
recent: true,
sortfield: ['eventid'],
sortorder: 'DESC',
limit: 100,
});
if (problems.length === 0) return [];
// 2. Host-Info via event.get holen
// (selectHosts funktioniert bei event.get noch!)
const eventIds = problems.map(p => p.eventid);
const events = await zabbixRequest('event.get', {
eventids: eventIds,
output: ['eventid'],
selectHosts: ['host', 'name'],
});
// 3. Zusammenführen
const eventHostMap = new Map();
for (const event of events) {
eventHostMap.set(event.eventid, event.hosts || []);
}
const result = problems.map(p => ({
...p,
hosts: eventHostMap.get(p.eventid) || [],
}));
Ja, das sind zwei API-Calls statt einem. Aber es funktioniert - wie der Kessel Run in unter 12 Parsec.
Vollständiges Beispiel (TypeScript)
async function getProblems(): Promise<ZabbixProblem[]> {
// Probleme ohne Host-Info holen
const problems = await zabbixRequest<Array<{
eventid: string;
objectid: string;
clock: string;
name: string;
severity: string;
acknowledged: string;
}>>('problem.get', {
output: ['eventid', 'objectid', 'clock', 'name', 'severity', 'acknowledged'],
recent: true,
sortfield: ['eventid'],
sortorder: 'DESC',
limit: 100,
});
if (problems.length === 0) return [];
// Host-Info via event.get
const eventIds = problems.map(p => p.eventid);
const events = await zabbixRequest<Array<{
eventid: string;
hosts: { host: string; name: string }[];
}>>('event.get', {
eventids: eventIds,
output: ['eventid'],
selectHosts: ['host', 'name'],
});
// Merge
const eventHostMap = new Map<string, { host: string; name: string }[]>();
for (const event of events) {
eventHostMap.set(event.eventid, event.hosts || []);
}
return problems.map(p => ({
...p,
hosts: eventHostMap.get(p.eventid) || [],
}));
}
// API Request Helper
async function zabbixRequest<T>(
method: string,
params: Record<string, unknown>
): Promise<T> {
const response = await fetch(ZABBIX_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json-rpc',
},
body: JSON.stringify({
jsonrpc: '2.0',
method,
params,
id: 1,
auth: getToken(), // Token im Body!
}),
});
const data = await response.json();
if (data.error) {
throw new Error(`Zabbix API error: ${data.error.message}`);
}
return data.result;
}
Wie prüfe ich meine Zabbix-Version?
curl -s 'http://zabbix.deathstar.lan:8080/api_jsonrpc.php' \
-H 'Content-Type: application/json-rpc' \
-d '{"jsonrpc":"2.0","method":"apiinfo.version","params":[],"id":1}'
Antwort:
{"jsonrpc":"2.0","result":"7.0.22","id":1}
Alles ab 7.0.x ist betroffen - das Imperium hat die API geändert und niemandem Bescheid gesagt.
Zusammenfassung
| Was | Zabbix 6.x | Zabbix 7.0+ |
|---|---|---|
| Auth-Token | Authorization: Bearer Header | auth Parameter im JSON-Body |
problem.get + selectHosts | Funktioniert | Entfernt - nutze event.get |
event.get + selectHosts | Funktioniert | Funktioniert |
trigger.get + selectHosts | Funktioniert | Funktioniert |
Diese Änderungen sind nicht in den Release Notes prominent dokumentiert, also spar dir die Frustration und check deinen Code jetzt.
Fazit
Das Imperium (Zabbix Inc.) hat die API geändert ohne die Rebellen-Allianz (uns Nutzer) ausreichend zu warnen. Aber mit dem Workaround über event.get kannst du dein Dashboard retten.
“Do. Or do not. There is no selectHosts.” — Yoda, vermutlich