1 | |
2 |
|
3 | |
4 | * Push value |
5 | * Push a value to a Zabbix trapper item (history.push, Zabbix 7.0+), identified by itemid or by technical host name + item key, e.g. to raise an alarm when a workflow fails. The trapper item and its trigger must already exist; if the item restricts Allowed hosts, include the Zabbix web frontend's IP. Minimal setup: a trapper item with key "trap" (numeric) and a trigger like last(/<host>/trap)>0; push 1 on failure and 0 to recover. Throws if Zabbix rejects the push (unknown item, no permission, source not in Allowed hosts). A value that doesn't fit the item's type is accepted, then makes the item unsupported. |
6 | */ |
7 | export async function main( |
8 | auth: RT.Zabbix, |
9 | value: string, |
10 | itemid: string | undefined, |
11 | host: string | undefined, |
12 | key: string | undefined, |
13 | clock: string | undefined |
14 | ) { |
15 | const params: { [key: string]: any } = { value } |
16 | if (itemid && (host || key)) { |
17 | throw new Error("Provide itemid, or host and key, not both") |
18 | } |
19 | if (itemid) { |
20 | params.itemid = itemid |
21 | } else if (host && key) { |
22 | params.host = host |
23 | params.key = key |
24 | } else { |
25 | throw new Error("Provide itemid, or both host and key") |
26 | } |
27 | if (clock) { |
28 | const seconds = Math.floor(new Date(clock).getTime() / 1000) |
29 | if (Number.isNaN(seconds)) { |
30 | throw new Error(`Invalid clock: ${clock}`) |
31 | } |
32 | params.clock = seconds |
33 | } |
34 |
|
35 | const result = await call(auth, "history.push", params) |
36 | const failed = (result.data ?? []).filter((d: any) => d.error) |
37 | if (failed.length) { |
38 | throw new Error( |
39 | `history.push rejected the value: ${failed.map((d: any) => d.error).join("; ")}` |
40 | ) |
41 | } |
42 | return result |
43 | } |
44 |
|
45 | async function call(auth: RT.Zabbix, method: string, params: any) { |
46 | const response = await fetch( |
47 | `${auth.base_url.replace(/\/+$/, "").replace(/\/api_jsonrpc\.php$/, "")}/api_jsonrpc.php`, |
48 | { |
49 | method: "POST", |
50 | headers: { |
51 | Authorization: `Bearer ${auth.token}`, |
52 | "Content-Type": "application/json-rpc", |
53 | Accept: "application/json", |
54 | }, |
55 | body: JSON.stringify({ jsonrpc: "2.0", method, params, id: 1 }), |
56 | } |
57 | ) |
58 |
|
59 | if (!response.ok) { |
60 | throw new Error(`${response.status} ${await response.text()}`) |
61 | } |
62 |
|
63 | const text = await response.text() |
64 | let data: any |
65 | try { |
66 | data = JSON.parse(text) |
67 | } catch { |
68 | throw new Error( |
69 | `Not a JSON-RPC response (check base_url): ${text.slice(0, 300)}` |
70 | ) |
71 | } |
72 | if (data.error) { |
73 | throw new Error( |
74 | `${data.error.code} ${data.error.message} ${data.error.data ?? ""}` |
75 | ) |
76 | } |
77 | return data.result |
78 | } |
79 |
|