Inviare dati al server o al proxy Zabbix

zabbix_utils consente di inviare valori di item a un item trapper sul server o proxy Zabbix (in modo simile a Zabbix sender).

È possibile inviare un singolo valore, più valori o persino indirizzare più cluster Zabbix.

I dati possono essere inviati in modalità sincrona o asincrona:

  • In modalità sincrona, lo script Python invia i valori e attende una risposta prima di continuare; questa modalità è adatta per operazioni semplici, sequenziali e prevedibili.
  • In modalità asincrona, lo script invia i valori senza attendere ogni risposta, consentendo ad altre operazioni di procedere in parallelo; questa modalità è più efficiente per richieste lente o grandi quantità di dati.

Gli esempi in questa pagina si concentrano sulla modalità sincrona, sebbene la modalità asincrona segua schemi simili. Ulteriori esempi sono disponibili nel repository GitHub zabbix_utils.

Importazione

Per utilizzare zabbix_utils per l'invio dei valori degli item, importa la classe Sender nel tuo script:

from zabbix_utils import Sender

Per inviare più valori, puoi anche importare la classe ItemValue:

from zabbix_utils import Sender, ItemValue

Inviare un singolo valore

Per inviare un valore di un item:

  1. Creare un'istanza di Sender, specificando l'indirizzo IP e la porta del server o proxy Zabbix.
  2. Chiamare il metodo send_value() sull'istanza Sender utilizzando il seguente formato:
sender_instance.send_value('host', 'item.key', 'value', optional_timestamp, optional_nanoseconds)

Ad esempio, per inviare 1 al trapper item service.status del host Linux server:

sender = Sender(server='127.0.0.1', port=10051)
response = sender.send_value('Linux server', 'service.status', 1)
Utilizzo di un IP non predefinito

Se il server che esegue lo script dispone di più indirizzi IP, è possibile specificare un source_ip che Sender utilizzerà durante l'invio dei valori al server o al proxy Zabbix:

sender = Sender(
    server='127.0.0.1',
    port=10051,
    source_ip='10.10.7.1'
)
Uso del timeout

Puoi impostare un timeout di risposta per Sender per controllare per quanto tempo il tuo script deve attendere una risposta dal server o dal proxy Zabbix prima di interrompere il tentativo:

sender = Sender(
    server='127.0.0.1',
    port=10051,
    timeout=30
)
Utilizzo del file di configurazione dell'agent

Puoi fare in modo che zabbix_utils legga i parametri Server o ServerActive da un file di configurazione locale di Zabbix agent o agent 2. In questi casi, non è necessario specificare i parametri di connessione quando si crea un'istanza di Sender:

sender = Sender(
    use_config=True,
    config_path='/etc/zabbix/zabbix_agent2.conf'
)

Se ServerActive contiene uno o più cluster Zabbix con più istanze server, Sender invia i dati al primo server disponibile in ciascun cluster. Se ServerActive non è impostato, viene utilizzato l'indirizzo di Server con la porta predefinita (10051).

Utilizzo della crittografia

Sender non include il supporto integrato per la crittografia, ma è possibile fornirlo creando un wrapper tramite librerie di terze parti:

def psk_wrapper(sock, tls):
    # ...
    # Implementazione del wrapper TLS PSK per il socket
    # ...

sender = Sender(
    server='127.0.0.1',
    port=10051,
    socket_wrapper=psk_wrapper
)
Risposta per valore singolo

La risposta restituita da Zabbix server o proxy viene elaborata dalla libreria e restituita come oggetto TrapperResponse:

print(response)
# {"processed": 1, "failed": 0, "total": 1, "time": "0.000123", "chunk": 1}

print(response.processed)
# 1

print(response.failed)
# 0

print(response.total)
# 1
Modalità asincrona

La modalità asincrona consente al tuo script Python di inviare valori senza attendere una risposta dal server o dal proxy Zabbix. Questo può rendere lo script più efficiente quando deve inviare molti valori o quando alcuni valori richiedono molto tempo per essere inviati.

Quando si utilizza la modalità asincrona, ci sono alcune differenze importanti rispetto alla modalità sincrona:

  • Importa il modulo asyncio di Python (devi prima installare le dipendenze richieste).
  • Importa AsyncSender invece di Sender.
  • Scrivi il codice all'interno di una funzione async.
  • Usa await quando chiami il metodo send_value().

Ad esempio, per inviare un singolo valore utilizzando la modalità asincrona:

# 1. Importa asyncio per la modalità asincrona e AsyncSender da zabbix_utils:
import asyncio
from zabbix_utils import AsyncSender

# 2. Definisci la funzione async principale in cui verranno eseguite tutte le operazioni di invio dei dati (è necessario usare await):
async def main():
    sender = AsyncSender(server='127.0.0.1', port=10051)
    response = await sender.send_value('Linux server', 'service.status', 1)

    # 3. Stampa la risposta restituita dal server o dal proxy Zabbix:
    print(response)

# 4. Esegui la funzione async main() utilizzando il ciclo di eventi di asyncio:
asyncio.run(main())

Inviare più valori

Per inviare più valori:

  1. Preparare un array di oggetti ItemValue, ciascuno utilizzando lo stesso formato del metodo send_value().
  2. Creare un'istanza di Sender, specificando l'indirizzo IP e la porta del proprio server o proxy Zabbix.
  3. Chiamare il metodo send() (invece di send_value()) sull'istanza Sender, specificando l'array di oggetti con i valori da inviare.

Ad esempio, per inviare cinque valori a host diversi:

items = [
    ItemValue('server-de', 'service.status', 'up', 1770887205, 100),
    ItemValue('server-fr', 'service.status', 'up', 1770887205, 100),
    ItemValue('server-uk', 'service.status', 'up', 1770887205, 100),
    ItemValue('server-nl', 'service.status', 'up', 1770887205, 100),
    ItemValue('server-pl', 'service.status', 'up', 1770887205, 100),
]

sender = Sender(server='127.0.0.1', port=10051)
response = sender.send(items)
Utilizzo di una dimensione personalizzata dei blocchi

Se devi inviare più valori di quanti un item trapper possa accettare in una singola richiesta, puoi suddividerli in blocchi.

Per impostazione predefinita, la dimensione del blocco è di 250 valori. Puoi modificarla impostando il parametro chunk_size durante la creazione di un'istanza di Sender.

Ad esempio, per inviare cinque valori in tre blocchi (2-2-1), imposta il parametro chunk_size su 2:

items = [
    ItemValue('server-de', 'service.status', 'up'),
    ItemValue('server-fr', 'service.status', 'up'),
    ItemValue('server-uk', 'service.status', 'up'),
    ItemValue('server-nl', 'service.status', 'up'),
    ItemValue('server-pl', 'service.status', 'up'),
]

sender = Sender(server='127.0.0.1', port=10051, chunk_size=2)
response = sender.send(items)
Inviare valori a più cluster Zabbix

Per inviare valori a più cluster Zabbix:

  1. Preparare un array di cluster Zabbix. Se un cluster ha più nodi, il valore verrà inviato al primo nodo disponibile di ciascun cluster.
  2. Creare un Sender, specificando il proprio array di cluster Zabbix.
  3. Chiamare il metodo send_value() sull'istanza Sender utilizzando lo stesso formato del metodo send_value().

Ad esempio, per inviare un valore al primo nodo disponibile in ciascun cluster:

zabbix_clusters = [
    ['zabbix.cluster1.node1', 'zabbix.cluster1.node2:10051'],
    ['zabbix.cluster2.node1:10051', 'zabbix.cluster2.node2', 'zabbix.cluster2.node3']
]

sender = Sender(clusters=zabbix_clusters)
response = sender.send_value('Linux server', 'service.status', 1)
Risposta per più valori

Per impostazione predefinita, Sender restituisce un risultato aggregato dell'invio dei valori tra tutti gli host o cluster:

print(response)
# {"processed": 2, "failed": 0, "total": 2, "time": "0.000108", "chunk": 2}

Se hai bisogno di informazioni più dettagliate, puoi esaminare i risultati per ciascun cluster e ciascun chunk utilizzando l'attributo response.details:

print(response)
# {"processed": 2, "failed": 0, "total": 2, "time": "0.000108", "chunk": 2}

if response.failed == 0:
    print(f"Valore inviato con successo in {response.time}")
else:
    print(response.details)
    # {
    #     127.0.0.1:10051: [
    #         {
    #             "processed": 1,
    #             "failed": 0,
    #             "total": 1,
    #             "time": "0.000051",
    #             "chunk": 1
    #         }
    #     ],
    #     zabbix.example.local:10051: [
    #         {
    #             "processed": 1,
    #             "failed": 0,
    #             "total": 1,
    #             "time": "0.000057",
    #             "chunk": 1
    #         }
    #     ]
    # }

    for node, chunks in response.details.items():
        for resp in chunks:
            print(f"Elaborati {resp.processed} di {resp.total} su {node.address}:{node.port}")
            # Elaborati 1 di 1 su 127.0.0.1:10051
            # Elaborati 1 di 1 su zabbix.example.local:10051