zabbix-argus-glue
A glue service that synchronizes Zabbix 7.2+ problems with Argus incidents. It translates Zabbix problem events into Argus incident state changes, keeping both systems in sync.
Status: Early development. The reconciliation poller and webhook receiver are functional; ack sync is planned but not yet implemented.
Architecture
Hybrid push + poll design:
┌─────────────┐ webhook POST ┌──────────────────────┐ REST API ┌───────────┐
│ Zabbix │ ───────────────> │ zabbix-argus-glue │ ───────────> │ Argus │
│ Server │ <─────────────── │ │ <─────────── │ Server │
│ │ API polling │ - HTTP receiver │ │ │
└─────────────┘ │ - Reconciliation │ └───────────┘
│ - Ack sync * │
└──────────────────────┘
* planned
- Webhook receiver — receives Zabbix webhook POSTs, creates/closes Argus incidents in near-real-time. (implemented)
- Reconciliation poller — periodically fetches open problems from Zabbix, compares against Argus state, fixes drift. Full sync on startup. (implemented)
- Ack sync — detect acknowledgements and closures made in Argus, write them back to Zabbix. (planned)
Installation
uv tool install zabbix-argus-glue
Or install the latest unreleased version directly from the repository:
uv tool install git+https://github.com/Uninett/zabbix-argus-glue.git
Configuration
Copy the example configuration and edit it:
cp zabbixargus.example.toml zabbixargus.toml
See zabbixargus.example.toml for all available options with comments.
The program searches for zabbixargus.toml in the following locations
(first match wins):
- Current working directory
$XDG_CONFIG_HOME/zabbixargus/(typically~/.config/zabbixargus/)- System config directory (typically
/etc/xdg/zabbixargus/)
You can override this with --config PATH.
API tokens can also be provided via the ARGUS_TOKEN and ZABBIX_TOKEN
environment variables instead of storing them in the config file. The
webhook shared secret can likewise be set via WEBHOOK_SECRET instead of
[webhook] secret, so it can be sourced from a Kubernetes Secret or vault
rather than a plaintext config file.
Incident detail links point back to the Zabbix problem page using
relative URLs (e.g. tr_events.php?triggerid=...&eventid=...). The
Argus source system's base_url must include the full path prefix to
the Zabbix frontend — for Apache-based installs this is typically
https://zabbix.example.com/zabbix/, while Nginx-based installs
usually use https://zabbix.example.com/.
Usage
# Run the service (config auto-discovered)
zabbix-argus-glue
# Verify API connectivity before running
zabbix-argus-glue --verify
# Use an explicit config file
zabbix-argus-glue --config /etc/zabbixargus/zabbixargus.toml
# Enable debug logging
zabbix-argus-glue -v
Webhook setup
The webhook receiver listens for HTTP POSTs from Zabbix. To use it, you need to configure a webhook media type and a trigger action in Zabbix.
By default the receiver binds 0.0.0.0:8080; change the bind address
and port with [webhook] listen and port, or turn the receiver off
entirely with [webhook] enabled = false.
Requires Zabbix 7.2 or later (the setup uses the {EVENT.TIMESTAMP}
macro, introduced after the 7.0 LTS).
1. Create a webhook media type
In Zabbix, go to Alerts → Media types → Create media type and configure:
-
Name:
Argus -
Type: Webhook
-
Parameters:
Name Value glue_urlhttp://glue-host:8080/webhooksecret(same value as [webhook] secretin your config)eventid{EVENT.ID}value{EVENT.VALUE}severity{EVENT.NSEVERITY}hostname{HOST.NAME}name{EVENT.NAME}timestamp{EVENT.TIMESTAMP}triggerid{TRIGGER.ID}tags{EVENT.TAGSJSON}update_status{EVENT.UPDATE.STATUS}update_action{EVENT.UPDATE.ACTIONJSON}update_user{USER.FULLNAME} -
Script:
var params = JSON.parse(value), req = new HttpRequest(), payload = {}; req.addHeader('Content-Type: application/json'); req.addHeader('X-Webhook-Secret: ' + params.secret); payload.eventid = params.eventid; payload.value = params.value; payload.severity = params.severity; payload.hostname = params.hostname; payload.name = params.name; payload.timestamp = params.timestamp; payload.triggerid = params.triggerid; payload.tags = params.tags; payload.update_status = params.update_status; payload.update_action = params.update_action; payload.update_user = params.update_user; var resp = req.post(params.glue_url, JSON.stringify(payload)); if (req.getStatus() < 200 || req.getStatus() >= 300) { throw 'Request failed with status ' + req.getStatus() + ': ' + resp; } return 'OK';
2. Assign the media type to a user
Zabbix sends alerts through users. Create a dedicated service account or use an existing user.
Go to Users → Users and create or edit a user:
- Username: e.g.
argus-glue - Role: a User-type role (with the problem-update actions enabled) is enough — the account only fires webhooks and, once acknowledgement sync lands, acts on problems. Avoid Super admin: a credential-bearing service account should not hold full configuration rights.
- Groups: a user group with read access to the hosts you want to sync. (Acknowledgement sync back to Zabbix additionally needs read-write access to those host groups.)
- Media tab → Add:
- Type:
Argus - Send to:
argus(required by Zabbix but ignored by webhooks) - Enabled: checked
- Type:
Resolving "Inaccessible user" in update notifications
Update notifications carry {USER.FULLNAME} — the person who
acknowledged or commented on a problem. Zabbix only reveals a user's
name to accounts that share at least one user group with them;
otherwise the macro resolves to the literal string Inaccessible user
(a privacy safeguard introduced by
ZBX-12441). To make names
resolve without widening the service account's access, create a user
group with no permissions (e.g. argus-visibility) and add both the
argus-glue account and every operator who acknowledges problems to it.
Membership alone establishes visibility; the empty permission set keeps
it least-privilege. Granting Super admin also works but
over-privileges the account — don't.
3. Create a trigger action
Go to Alerts → Actions → Trigger actions → Create action:
- Name:
Send to Argus - Conditions: (adjust to match the problems you want to sync)
- Operations → Add:
- Send to users: select the user from step 2
- Send only to:
Argus - Check Custom message and set any non-empty subject and
body (e.g.
{EVENT.NAME}/{EVENT.ID}). Zabbix requires a message to be defined even though webhooks ignore it.
- Recovery operations → Add:
- Same settings as above, including a custom message
- Update operations → Add:
- Same settings as above (forwards acks, comments, and severity changes)
4. Test with curl
curl -X POST http://localhost:8080/webhook \
-H 'Content-Type: application/json' \
-H 'X-Webhook-Secret: your-secret' \
-d '{
"eventid": "12345",
"value": "1",
"severity": "4",
"hostname": "web01.example.com",
"name": "High CPU usage on web01",
"timestamp": "1745326800",
"triggerid": "678",
"tags": "[{\"tag\": \"application\", \"value\": \"nginx\"}]"
}'
Development
Requires Python 3.11+.
# Clone and install in editable mode
git clone https://github.com/Uninett/zabbix-argus-glue.git
cd zabbix-argus-glue
uv venv --python 3.13
uv sync --all-groups
# Set up pre-commit hooks
pre-commit install
# Run tests
pytest
# Lint and format
ruff check --fix src/
ruff format src/
Changelog
See CHANGELOG.md. We use
towncrier to manage changelog
fragments. Add a fragment to changelog.d/ with each PR.
License
Apache-2.0. See LICENSE.
Metadata
Release files for zabbix-argus-glue 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| zabbix_argus_glue-0.1.0.tar.gz | 145.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| zabbix_argus_glue-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 171.6 kB
Release files / zabbix_argus_glue-0.1.0.tar.gz
| Download URL | zabbix_argus_glue-0.1.0.tar.gz |
|---|---|
| Size | 145.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6d4bc1a8fa6b744b1a9cd41da18b6faa3a724cdb966100dcce721bdcc0ea834a
|
|
BLAKE2b-256 checksum How to use checksums |
0feee4b8ba0104273c152b5d19322735fd08a663ba9d5d30312ea7bfdcaec085
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.05","id":"yarara","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / zabbix_argus_glue-0.1.0-py3-none-any.whl
| Download URL | zabbix_argus_glue-0.1.0-py3-none-any.whl |
|---|---|
| Size | 26.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0c57f889241ae8cd67da77a036db627119e3f4390c7efe3ecd8430f188fee909
|
|
BLAKE2b-256 checksum How to use checksums |
b7406d413eaf116c6070f51bdd6b6d77db66638dfc1b4d54559e7a149e45c00b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.05","id":"yarara","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|