ITSkillsCenter
Business Digital

API Zabbix JSON-RPC et automatisation Python avec pyzabbix

14 دقائق للقراءة

📍 Lecture connexe : Zabbix 7 LTS en 2026 : supervision open-source en production — pour la vue d’ensemble et les arbitrages.

Tout ce qu’on fait dans le frontend Zabbix est accessible par l’API JSON-RPC : créer un hôte, lier un template, déclencher une maintenance, exporter une configuration, lire une métrique. C’est cette ouverture qui permet d’intégrer Zabbix dans une CI/CD, de provisionner via Terraform, ou de générer dynamiquement la supervision à partir d’un inventaire CMDB. Ce tutoriel construit un script Python avec pyzabbix qui crée 50 hôtes en une commande, leur applique des templates, et expose le pattern qui rend l’API utilisable au quotidien.

Prérequis

  • Une instance Zabbix 7 fonctionnelle accessible en HTTPS depuis votre poste
  • Python 3.12 ou supérieur, vérifier avec python --version
  • Un utilisateur Zabbix avec droits Super Admin (ou rôle dédié API avec les privilèges nécessaires)
  • Niveau attendu : intermédiaire
  • Temps estimé : environ 70 minutes

Étape 1 — Comprendre l’API Zabbix

L’API Zabbix expose un seul endpoint HTTP : https://zabbix.example.com/api_jsonrpc.php. Toutes les opérations passent par des requêtes POST avec un payload JSON-RPC 2.0. Chaque requête identifie une method (par exemple host.create), des params, un id de corrélation.

L’authentification a évolué entre les versions. Avant 6.4, on appelait user.login qui retournait un token de session qu’on passait dans le champ auth de chaque requête suivante. Depuis 6.4, l’authentification se fait via un header HTTP Authorization: Bearer <token>, et le champ auth dans le JSON est obsolète. Pour Zabbix 7, on privilégie les API tokens nommés générés depuis le frontend, qui sont stables et révocables individuellement.

Étape 2 — Générer un API token

Dans le frontend, Users → API tokens → Create API token. On nomme le token (par exemple provisioning-cicd), on choisit l’utilisateur cible, on définit éventuellement une expiration. Au clic Save, le token est affiché une seule fois — on le copie immédiatement dans un coffre (Vault, Doppler, secret manager). Si on le perd, on en regénère un nouveau et on révoque l’ancien.

Le token a la forme d’une chaîne hexadécimale longue. On le stocke dans la variable d’environnement ZABBIX_TOKEN sur le poste qui exécutera les scripts.

Étape 3 — Installer pyzabbix

pyzabbix est le client Python le plus utilisé pour l’API Zabbix. Maintenu par Luke Cyca depuis 2010, il est compatible avec toutes les versions modernes de Zabbix.

python -m venv .venv
source .venv/bin/activate  # Windows : .venv\Scripts\activate
pip install pyzabbix python-dotenv

La bibliothèque enveloppe l’API JSON-RPC dans une syntaxe Python idiomatique : z.host.create(...) au lieu de construire manuellement le payload JSON-RPC. C’est ce qui rend les scripts lisibles et maintenables.

Étape 4 — Premier script d’authentification

On commence par valider la connexion à l’API et lister les hôtes.

# scripts/list_hosts.py
import os
from pyzabbix import ZabbixAPI
from dotenv import load_dotenv
load_dotenv()

z = ZabbixAPI(os.environ['ZABBIX_URL'])
z.login(api_token=os.environ['ZABBIX_TOKEN'])

print(f"Connecté à Zabbix version {z.api_version()}")
hosts = z.host.get(output=['hostid', 'host', 'name'], limit=10)
for h in hosts:
    print(f"  {h['hostid']:>8}  {h['host']}")

Si le script imprime « Connecté à Zabbix version 7.0.x » suivi de la liste de 10 hôtes, l’authentification fonctionne. Si l’erreur est « Login name or password is incorrect », le token est invalide ou expiré ; on vérifie qu’il est bien copié sans espaces parasites.

Étape 5 — Créer un hôte par API

L’opération de création d’un hôte tient en une méthode. On choisit le groupe d’appartenance (par son ID), les templates à lier, l’IP de l’agent, et le nom.

# scripts/create_host.py
import os
from pyzabbix import ZabbixAPI
from dotenv import load_dotenv
load_dotenv()

z = ZabbixAPI(os.environ['ZABBIX_URL'])
z.login(api_token=os.environ['ZABBIX_TOKEN'])

# Récupérer les IDs nécessaires
group = z.hostgroup.get(filter={'name': 'Linux servers'})[0]
tpl = z.template.get(filter={'host': 'Linux by Zabbix agent'})[0]

# Créer l'hôte
result = z.host.create(
    host='web02.example.com',
    name='web02',
    interfaces=[{
        'type': 1,        # 1=Zabbix agent
        'main': 1,
        'useip': 1,
        'ip': '10.0.0.22',
        'dns': '',
        'port': '10050',
    }],
    groups=[{'groupid': group['groupid']}],
    templates=[{'templateid': tpl['templateid']}],
)

print(f"Hôte créé, hostid = {result['hostids'][0]}")

Quelques détails. Le champ type dans interfaces accepte 1 (Zabbix agent), 2 (SNMP), 3 (IPMI), 4 (JMX). L’usage des IDs (groupid, templateid) plutôt que des noms est obligatoire pour la création — c’est pour ça qu’on récupère d’abord les références. Si l’hôte existe déjà, l’API renvoie une erreur ; on gère ce cas en encapsulant dans un try/except et en faisant un host.update en alternative.

Étape 6 — Bulk provisioning depuis un CSV

Le cas d’usage le plus fréquent de l’API : provisionner 50 ou 500 hôtes d’un coup à partir d’un fichier d’inventaire. On part d’un CSV avec les colonnes hostname, ip, group, template, on parcourt et on crée.

# scripts/bulk_provision.py
import csv, os, sys
from pyzabbix import ZabbixAPI
from dotenv import load_dotenv
load_dotenv()

z = ZabbixAPI(os.environ['ZABBIX_URL'])
z.login(api_token=os.environ['ZABBIX_TOKEN'])

# Cache pour éviter N requêtes à chaque ligne
groups_cache = {g['name']: g['groupid'] for g in z.hostgroup.get(output=['name', 'groupid'])}
tpls_cache = {t['host']: t['templateid'] for t in z.template.get(output=['host', 'templateid'])}

with open(sys.argv[1]) as f:
    reader = csv.DictReader(f)
    for row in reader:
        try:
            z.host.create(
                host=row['hostname'],
                interfaces=[{
                    'type': 1, 'main': 1, 'useip': 1,
                    'ip': row['ip'], 'dns': '', 'port': '10050',
                }],
                groups=[{'groupid': groups_cache[row['group']]}],
                templates=[{'templateid': tpls_cache[row['template']]}],
            )
            print(f"OK  {row['hostname']}")
        except Exception as e:
            print(f"ERR {row['hostname']}: {e}")

Le pattern cache des références est indispensable dès qu’on monte au-dessus de 10 hôtes : chaque appel API a un coût de 50-200 ms ; remplir un dictionnaire en mémoire au démarrage évite des centaines d’allers-retours.

Pour 500 hôtes, ce script termine en moins de deux minutes typiquement, contre plusieurs heures de clics manuels dans le frontend.

Étape 7 — Déclencher une maintenance par API

Avant un patch ou une intervention planifiée, on crée une fenêtre de maintenance pour silencer les alertes pendant l’opération. L’API supporte cette création.

import time

now = int(time.time())
z.maintenance.create(
    name='Patch sécurité - mai 2026',
    active_since=now,
    active_till=now + 3600,  # 1 heure
    tags_evaltype=0,
    timeperiods=[{
        'timeperiod_type': 0,
        'start_date': now,
        'period': 3600,
    }],
    groups=[{'groupid': groups_cache['Linux servers']}],
)
print("Maintenance créée")

Toutes les notifications pour les hôtes de ce groupe sont suspendues pendant l’heure suivante. À la fin, la maintenance expire automatiquement et les alertes reprennent. L’intégration courante : un workflow Jira « Change Approved » déclenche un job qui crée la maintenance via API, le change est exécuté, à la clôture du ticket la maintenance est supprimée.

Étape 8 — Lire une métrique en historique

Pour exporter des données vers un outil tiers (BI, dashboard custom, rapport mensuel), on utilise history.get. La méthode demande l’itemid de l’item ciblé et une fenêtre temporelle.

# Trouver l'item CPU de web01
item = z.item.get(
    host='web01',
    search={'key_': 'system.cpu.util'},
    output=['itemid', 'name'],
    limit=1,
)[0]

# Récupérer 24h d'historique
import time
end = int(time.time())
start = end - 86400

values = z.history.get(
    itemids=item['itemid'],
    history=0,         # 0=numeric float, 3=numeric unsigned, 1=character, etc.
    time_from=start,
    time_till=end,
    sortfield='clock',
    sortorder='ASC',
)

for v in values[:10]:
    print(time.strftime('%Y-%m-%d %H:%M', time.localtime(int(v['clock']))), v['value'])

Le paramètre history est essentiel : il indique le type de stockage de l’item (0 pour les nombres décimaux, 3 pour les entiers non signés, 1 pour les chaînes de caractères, 2 pour les logs, 4 pour les chaînes longues). Erreur classique : passer le mauvais type retourne un tableau vide sans message d’erreur.

Pour un volume important (plusieurs millions de points), on pagine avec limit et on itère par fenêtres temporelles plus courtes. L’API gère sans difficulté quelques dizaines de milliers de points par requête.

Étape 9 — Importer/exporter des templates

Pour le GitOps de la supervision, on automatise l’export/import des templates en YAML. Export :

tpl = z.template.get(filter={'host': 'API métier'}, output=['templateid'])[0]

dump = z.configuration.export(
    format='yaml',
    options={'templates': [tpl['templateid']]},
)
with open('templates/api_metier.yaml', 'w') as f:
    f.write(dump)
print("Template exporté")

L’inverse pour importer :

with open('templates/api_metier.yaml') as f:
    payload = f.read()

z.configuration.import_(
    format='yaml',
    source=payload,
    rules={
        'templates': {'createMissing': True, 'updateExisting': True},
        'items': {'createMissing': True, 'updateExisting': True},
        'triggers': {'createMissing': True, 'updateExisting': True},
    },
)
print("Template importé")

Note : le nom de méthode est import_ (avec underscore final) en Python parce que import est un mot-clé. C’est une particularité de pyzabbix qui surprend la première fois.

Étape 10 — Gérer les erreurs API

Les erreurs côté API sont retournées sous forme d’exceptions ZabbixAPIException par pyzabbix. Le message contient un code et une explication.

from pyzabbix import ZabbixAPIException

try:
    z.host.create(host='web01.example.com', ...)
except ZabbixAPIException as e:
    if 'already exists' in str(e):
        # Logique de fallback : update existant
        existing = z.host.get(filter={'host': 'web01.example.com'})[0]
        z.host.update(hostid=existing['hostid'], ...)
    else:
        raise

Cette discipline d’idempotence rend les scripts CI/CD ré-exécutables : que l’hôte existe ou non, le script termine en succès. Sans elle, chaque ré-exécution échoue et nécessite intervention manuelle.

Étape 11 — Sécuriser les scripts en CI

Quelques règles pour intégrer ces scripts dans une pipeline GitHub Actions ou GitLab CI. Le token API est stocké comme secret CI (jamais dans le repo). On utilise un compte Zabbix dédié à la CI avec des droits limités au strict nécessaire (par exemple Manage host configuration mais pas Super Admin). On loggue les opérations effectuées pour la traçabilité, sans logger le token. Et on ajoute un dry-run mode déclenché par variable d’environnement, qui affiche les opérations sans les exécuter — utile pour valider une PR avant le merge.

Étape 12 — Patterns avancés

Trois patterns récurrents valent la peine d’être connus. Le provisioning Terraform-driven : un module Terraform qui pilote l’API Zabbix via un provider tiers (claranet/zabbix) ou via local-exec qui appelle un script Python. Le sync from CMDB : un cron qui interroge la CMDB métier (Servicenow, Jira Insight, NetBox) et synchronise les hôtes Zabbix correspondants — ajout des nouveaux, retrait des décommissionnés. Le self-service via API gateway : exposer une partie de l’API Zabbix derrière une API gateway interne pour permettre aux équipes produit de créer leurs propres alertes sans passer par le frontend admin.

Étape 13 — Limites et alternatives

L’API Zabbix a deux limites pratiques. La rate limit n’existe pas par défaut côté serveur ; un script qui boucle peut saturer le serveur. À ajouter côté script : un time.sleep(0.1) entre opérations sensibles, ou utiliser le batch (host.massadd, host.massupdate) qui groupe plusieurs opérations en un seul appel. Le second point est que certaines opérations ne sont pas exposées via l’API : configuration globale du serveur (zabbix_server.conf), chargement de modules custom, certaines opérations de housekeeping. Pour ces cas, l’automation passe par Ansible ou la modification directe des fichiers de config.

Étape 14 — Patterns d’intégration GitHub Actions

L’intégration la plus fréquente est de pousser les modifications de templates depuis Git vers Zabbix à chaque merge sur main. Un workflow GitHub Actions tient en quelques lignes : checkout du repo, installation des dépendances Python, exécution d’un script Python qui parcourt les fichiers YAML modifiés et appelle configuration.import_ via pyzabbix.

name: zabbix-templates-deploy
on:
  push:
    branches: [main]
    paths: ['templates/**.yaml']
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: '3.12' }
      - run: pip install pyzabbix python-dotenv
      - run: python scripts/sync_templates.py
        env:
          ZABBIX_URL: ${{ secrets.ZABBIX_URL }}
          ZABBIX_TOKEN: ${{ secrets.ZABBIX_TOKEN }}

Le script sync_templates.py liste les fichiers YAML, les importe un par un avec gestion d’erreur. La beauté de cette approche : toute modification de template passe par une PR, est revue, mergée, et l’environnement Zabbix se met à jour automatiquement. La désynchronisation entre Git et Zabbix devient impossible.

Étape 15 — Patterns d’intégration Terraform

Pour les organisations qui pratiquent l’Infrastructure as Code complète, Terraform est une bonne porte d’entrée pour Zabbix. Plusieurs providers tiers existent (claranet/zabbix est le plus mature en 2026). On déclare hôtes, hostgroups, templates et utilisateurs en HCL, on plan/apply, et Terraform synchronise l’état Zabbix avec le code.

L’avantage par rapport au scripting Python : la gestion automatique du diff (Terraform sait ce qui doit être créé, modifié, supprimé), la cohérence d’état (le state Terraform est le miroir de la réalité Zabbix), et la cohabitation avec le reste de l’IaC (un même terraform apply peut créer une VM AWS, l’enregistrer dans Route53, et la déclarer dans Zabbix).

L’inconvénient : la maintenance d’un provider tiers, qui peut prendre du retard sur l’API Zabbix. Pour les usages avancés ou les versions très récentes, le scripting Python direct reste plus flexible.

Erreurs fréquentes

Erreur Cause Solution
« Login name or password is incorrect » Token invalide ou révoqué Régénérer un token et vérifier qu’il est bien copié sans espaces
« Application not authorized » sur certains appels L’utilisateur du token n’a pas les droits Promouvoir l’utilisateur au rôle Admin ou créer un rôle ad-hoc avec les privilèges précis
Tableau vide retourné par history.get Mauvais paramètre history (type de stockage de l’item) Vérifier le type via item.get et passer la valeur correspondante (0,1,2,3,4)
configuration.import qui échoue silencieusement Méthode appelée import au lieu de import_ Toujours utiliser import_ avec underscore en Python
Latence de bulk provisioning très lente Pas de cache des références, requête à chaque ligne Précharger groups_cache et tpls_cache au démarrage du script

Cette discipline de documentation et de monitoring transforme l’API Zabbix d’un outil de bricolage en infrastructure d’automation fiable, transmissible, et auditable.

Étape 16 — Documenter ses scripts

Un script API Zabbix sans documentation est une bombe à retardement de turnover. Quand l’auteur quitte l’équipe, plus personne ne sait à quoi sert provisioning_v3.py ni quels paramètres lui passer. Trois éléments incompressibles à documenter dans chaque script.

D’abord, un docstring de tête qui explique l’objectif métier (par exemple « Synchronise les hôtes Zabbix avec l’inventaire Servicenow toutes les heures »), les variables d’environnement attendues, et un exemple d’invocation. Ensuite, un README dans le repo qui liste tous les scripts avec leur fréquence d’exécution et leur dépendance. Enfin, un changelog qui trace les modifications majeures, particulièrement les changements de comportement qui pourraient surprendre.

Pour les scripts critiques (qui tournent en production sur des cron), on ajoute un mécanisme de health check : le script écrit un fichier marqueur ou pousse une métrique Zabbix après chaque exécution réussie. Une alerte se déclenche si le marqueur n’est pas mis à jour depuis trop longtemps, ce qui détecte les scripts cassés silencieusement.

Étape 17 — Sécurité des tokens API

Quelques bonnes pratiques opérationnelles autour des tokens API. Un token par usage : un pour le provisioning CI/CD, un pour le sync CMDB, un pour les exports BI. Chaque token a son propre rôle restreint avec uniquement les privilèges dont il a besoin. Une rotation programmée tous les six à douze mois : on génère le nouveau, on le déploie, on révoque l’ancien après vérification. Et un monitoring du dernier usage : Reports → Audit log filtré sur le user du token montre quand il a été utilisé pour la dernière fois ; un token jamais utilisé depuis trois mois est probablement obsolète et peut être révoqué.

Ressources

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité