
Zabbix Api
- 81 installs
- 6 repo stars
- Updated July 22, 2026
- julianobarbosa/claude-code-skills
Zabbix monitoring system automation via API and Python. Manage hosts, templates, items, triggers, automate config, send data, query historical data.
About
Zabbix monitoring system automation via API and Python.. Manage hosts, templates, items, triggers, automate config, send data, query history.
- advanced skill
- core: devops & ci/cd
Zabbix Api by the numbers
- 81 all-time installs (skills.sh)
- +5 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #587 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/julianobarbosa/claude-code-skills --skill zabbix-apiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 81 |
|---|---|
| repo stars | ★ 6 |
| Last updated | July 22, 2026 |
| Repository | julianobarbosa/claude-code-skills ↗ |
What it does
Zabbix monitoring system automation via API and Python. Manage hosts, templates, items, triggers, automate config, send data, query historical data.
Files
Zabbix Automation Skill
Overview
This skill provides guidance for automating Zabbix monitoring operations via the API and official Python library zabbix_utils.
Quick Start
Installation
pip install zabbix-utils --break-system-packagesAuthentication
from zabbix_utils import ZabbixAPI
# Option 1: Username/password
api = ZabbixAPI(url="https://zabbix.example.com")
api.login(user="Admin", password="zabbix")
# Option 2: API token (Zabbix 5.4+, preferred)
api = ZabbixAPI(url="https://zabbix.example.com")
api.login(token="your_api_token")
# Verify connection
print(api.api_version())Environment Variables Pattern
import os
from zabbix_utils import ZabbixAPI
api = ZabbixAPI(url=os.environ.get("ZABBIX_URL", "http://localhost/zabbix"))
api.login(token=os.environ["ZABBIX_TOKEN"])Core API Methods
All APIs follow pattern: api.<object>.<method>() with methods: get, create, update, delete.
Host Operations
# Get hosts
hosts = api.host.get(output=["hostid", "host", "name"],
selectInterfaces=["ip"])
# Create host
api.host.create(
host="server01",
groups=[{"groupid": "2"}], # Linux servers
interfaces=[{
"type": 1, # 1=agent, 2=SNMP, 3=IPMI, 4=JMX
"main": 1,
"useip": 1,
"ip": "192.168.1.100",
"dns": "",
"port": "10050"
}],
templates=[{"templateid": "10001"}]
)
# Update host
api.host.update(hostid="10084", status=0) # 0=enabled, 1=disabled
# Delete host
api.host.delete("10084")Template Operations
# Get templates
templates = api.template.get(output=["templateid", "host", "name"],
selectHosts=["hostid", "name"])
# Link template to host
api.host.update(hostid="10084",
templates=[{"templateid": "10001"}])
# Import template from XML
with open("template.xml") as f:
api.configuration.import_(
source=f.read(),
format="xml",
rules={
"templates": {"createMissing": True, "updateExisting": True},
"items": {"createMissing": True, "updateExisting": True},
"triggers": {"createMissing": True, "updateExisting": True}
}
)Item Operations
# Get items
items = api.item.get(hostids="10084",
output=["itemid", "name", "key_"],
search={"key_": "system.cpu"})
# Create item
api.item.create(
name="CPU Load",
key_="system.cpu.load[percpu,avg1]",
hostid="10084",
type=0, # 0=Zabbix agent
value_type=0, # 0=float, 3=integer, 4=text
delay="30s",
interfaceid="1"
)Trigger Operations
# Get triggers
triggers = api.trigger.get(hostids="10084",
output=["triggerid", "description", "priority"],
selectFunctions="extend")
# Create trigger
api.trigger.create(
description="High CPU on {HOST.NAME}",
expression="last(/server01/system.cpu.load[percpu,avg1])>5",
priority=3 # 0=not classified, 1=info, 2=warning, 3=average, 4=high, 5=disaster
)Host Group Operations
# Get groups
groups = api.hostgroup.get(output=["groupid", "name"])
# Create group
api.hostgroup.create(name="Production/Web Servers")
# Add hosts to group
api.hostgroup.massadd(groups=[{"groupid": "5"}],
hosts=[{"hostid": "10084"}])Maintenance Windows
import time
# Create maintenance
api.maintenance.create(
name="Server Maintenance",
active_since=int(time.time()),
active_till=int(time.time()) + 3600, # 1 hour
hostids=["10084"],
timeperiods=[{
"timeperiod_type": 0, # One-time
"period": 3600
}]
)Events and Problems
# Get current problems
problems = api.problem.get(output=["eventid", "name", "severity"],
recent=True)
# Get events
events = api.event.get(hostids="10084",
time_from=int(time.time()) - 86400,
output="extend")History Data
# Get history (value_type must match item's value_type)
# 0=float, 1=character, 2=log, 3=integer, 4=text
history = api.history.get(
itemids="28269",
history=0, # float
time_from=int(time.time()) - 3600,
output="extend",
sortfield="clock",
sortorder="DESC"
)Zabbix Sender (Trapper Items)
from zabbix_utils import Sender
sender = Sender(server="zabbix.example.com", port=10051)
# Send single value
response = sender.send_value("hostname", "trap.key", "value123")
print(response) # {"processed": 1, "failed": 0, "total": 1}
# Send multiple values
from zabbix_utils import ItemValue
values = [
ItemValue("host1", "key1", "value1"),
ItemValue("host2", "key2", 42),
]
response = sender.send(values)Zabbix Getter (Agent Query)
from zabbix_utils import Getter
agent = Getter(host="192.168.1.100", port=10050)
response = agent.get("system.uname")
print(response.value)Common Patterns
Bulk Host Creation from CSV
import csv
from zabbix_utils import ZabbixAPI
api = ZabbixAPI(url="https://zabbix.example.com")
api.login(token="your_token")
with open("hosts.csv") as f:
for row in csv.DictReader(f):
try:
api.host.create(
host=row["hostname"],
groups=[{"groupid": row["groupid"]}],
interfaces=[{
"type": 1, "main": 1, "useip": 1,
"ip": row["ip"], "dns": "", "port": "10050"
}]
)
print(f"Created: {row['hostname']}")
except Exception as e:
print(f"Failed {row['hostname']}: {e}")Find Hosts Without Template
# Get all hosts
all_hosts = api.host.get(output=["hostid", "host"],
selectParentTemplates=["templateid"])
# Filter hosts without specific template
template_id = "10001"
hosts_without = [h for h in all_hosts
if not any(t["templateid"] == template_id
for t in h.get("parentTemplates", []))]Disable Triggers by Pattern
triggers = api.trigger.get(
search={"description": "test"},
output=["triggerid"]
)
for t in triggers:
api.trigger.update(triggerid=t["triggerid"], status=1) # 1=disabledItem Types Reference
| Type | Value | Description |
|---|---|---|
| Zabbix agent | 0 | Active checks |
| Zabbix trapper | 2 | Passive, data pushed via sender |
| Simple check | 3 | ICMP, TCP, etc. |
| Zabbix internal | 5 | Server internal metrics |
| Zabbix agent (active) | 7 | Agent-initiated |
| HTTP agent | 19 | HTTP/REST API monitoring |
| Dependent item | 18 | Derived from master item |
| Script | 21 | Custom scripts |
Value Types Reference
| Type | Value | Description |
|---|---|---|
| Float | 0 | Numeric (float) |
| Character | 1 | Character string |
| Log | 2 | Log file |
| Unsigned | 3 | Numeric (integer) |
| Text | 4 | Text |
Trigger Severity Reference
| Severity | Value | Color |
|---|---|---|
| Not classified | 0 | Gray |
| Information | 1 | Light blue |
| Warning | 2 | Yellow |
| Average | 3 | Orange |
| High | 4 | Light red |
| Disaster | 5 | Red |
Error Handling
from zabbix_utils import ZabbixAPI
from zabbix_utils.exceptions import APIRequestError
try:
api.host.create(host="duplicate_host", groups=[{"groupid": "2"}])
except APIRequestError as e:
print(f"API Error: {e.message}")
print(f"Code: {e.code}")Debugging
import logging
logging.basicConfig(level=logging.DEBUG)
# Now all API calls will be loggedScripts Reference
See scripts/ directory for ready-to-use automation:
zabbix-bulk-hosts.py- Bulk host management from CSVzabbix-maintenance.py- Create/manage maintenance windowszabbix-export.py- Export hosts/templates to JSON/XML
Best Practices
1. Use API tokens over username/password when possible 2. Limit output fields - Always specify output=["field1", "field2"] instead of output="extend" 3. Use search/filter - Never fetch all objects and filter in Python 4. Handle pagination - Large result sets may need limit and offset 5. Batch operations - Use massadd, massupdate for bulk changes 6. Error handling - Always wrap API calls in try/except 7. Idempotency - Check if object exists before creating
---
Gotchas
- `api.history.get` requires the correct `history` value_type or returns empty: Passing
history=0(float) on an integer item silently returns[]instead of an error. Always read the item'svalue_typefirst; the four-way mismatch (0/1/3/4) is the most common "no data" cause. - `output="extend"` on large queries melts the server: Fetching every field for thousands of hosts or items causes multi-second responses and OOMs the API frontend. Always pass
output=["field1","field2"]with only the columns you need — the API has no implicit pagination protection. - Trigger expressions reference host+key, not item IDs: Renaming a host or key breaks every trigger expression that references it, with no warning until evaluation. Use templates and macros (
{HOST.HOST}) instead of hardcoded names in expressions. - API token vs session token confusion in `zabbix_utils`:
api.login(token=...)uses a permanent API token (Zabbix 5.4+);api.login(user=..., password=...)issues a session token. Mixing token auth withapi.logout()invalidates the permanent token for everyone using it. - `massadd` does not deduplicate — `massupdate` replaces:
hostgroup.massaddhappily adds the same host to a group twice in some versions;hostgroup.massupdatesilently removes hosts not in the payload. Read the verb carefully before bulk operations or you'll detach hosts you meant to keep. - `maintenance.create` with past `active_since` is accepted but ignored: Backdating a maintenance window does not retroactively suppress alerts that already fired. Set
active_sinceslightly in the future and verify withmaintenance.getbefore assuming alerts are muted.
MIT License
Copyright (c) 2024
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Zabbix API Reference
API Endpoint
All API calls go to: https://<zabbix-server>/api_jsonrpc.php
Authentication Methods
API Token (Zabbix 5.4+, Recommended)
api.login(token="your_api_token")Username/Password
api.login(user="Admin", password="zabbix")
api.logout() # Required when using user/passwordComplete API Class Reference
Host Management
| Method | Description |
|---|---|
host.get | Retrieve hosts |
host.create | Create new host |
host.update | Update host properties |
host.delete | Delete hosts |
host.massadd | Add templates/groups to multiple hosts |
host.massremove | Remove templates/groups from multiple hosts |
host.massupdate | Update multiple hosts |
Key host.get parameters:
output- Fields to returnhostids- Filter by host IDsgroupids- Filter by group IDstemplateids- Filter by linked template IDsselectInterfaces- Include interface dataselectGroups- Include group dataselectParentTemplates- Include linked templatesselectItems- Include itemsselectTriggers- Include triggersselectMacros- Include host macrosfilter- Exact match filterssearch- Pattern matchingsearchWildcardsEnabled- Enable wildcards in search
Host Groups
| Method | Description |
|---|---|
hostgroup.get | Retrieve groups |
hostgroup.create | Create group |
hostgroup.update | Update group |
hostgroup.delete | Delete group |
hostgroup.massadd | Add hosts to groups |
hostgroup.massremove | Remove hosts from groups |
Templates
| Method | Description |
|---|---|
template.get | Retrieve templates |
template.create | Create template |
template.update | Update template |
template.delete | Delete template |
template.massadd | Link templates to hosts |
template.massremove | Unlink templates |
Items
| Method | Description |
|---|---|
item.get | Retrieve items |
item.create | Create item |
item.update | Update item |
item.delete | Delete item |
Item types:
| Type | Value | Description |
|---|---|---|
| Zabbix agent | 0 | Passive agent checks |
| Zabbix trapper | 2 | Items for sender data |
| Simple check | 3 | ICMP/TCP checks |
| Zabbix internal | 5 | Internal metrics |
| Zabbix agent (active) | 7 | Active agent checks |
| Zabbix aggregate | 8 | Aggregate calculations |
| Web item | 9 | Web scenario items |
| External check | 10 | External scripts |
| Database monitor | 11 | Database queries |
| IPMI agent | 12 | IPMI sensors |
| SSH agent | 13 | SSH checks |
| Telnet agent | 14 | Telnet checks |
| Calculated | 15 | Calculated items |
| JMX agent | 16 | JMX monitoring |
| SNMP trap | 17 | SNMP traps |
| Dependent item | 18 | Master item derivatives |
| HTTP agent | 19 | HTTP/REST API |
| SNMP agent | 20 | SNMP polling |
| Script | 21 | Custom scripts |
Value types:
| Type | Value | Description |
|---|---|---|
| Float | 0 | Numeric (float) |
| Character | 1 | Short text (up to 255) |
| Log | 2 | Log data |
| Unsigned | 3 | Numeric (unsigned 64-bit) |
| Text | 4 | Long text |
Triggers
| Method | Description |
|---|---|
trigger.get | Retrieve triggers |
trigger.create | Create trigger |
trigger.update | Update trigger |
trigger.delete | Delete trigger |
trigger.adddependencies | Add trigger dependencies |
trigger.deletedependencies | Remove dependencies |
Trigger severities:
| Severity | Value |
|---|---|
| Not classified | 0 |
| Information | 1 |
| Warning | 2 |
| Average | 3 |
| High | 4 |
| Disaster | 5 |
Events and Problems
| Method | Description |
|---|---|
event.get | Retrieve events |
event.acknowledge | Acknowledge events |
problem.get | Get current problems |
Event sources:
- 0: Trigger
- 1: Discovery rule
- 2: Autoregistration
- 3: Internal
History
| Method | Description |
|---|---|
history.get | Retrieve historical data |
Important: The history parameter must match the item's value_type.
Maintenance
| Method | Description |
|---|---|
maintenance.get | Retrieve maintenance windows |
maintenance.create | Create maintenance |
maintenance.update | Update maintenance |
maintenance.delete | Delete maintenance |
Timeperiod types:
- 0: One-time
- 2: Daily
- 3: Weekly
- 4: Monthly
Actions
| Method | Description |
|---|---|
action.get | Retrieve actions |
action.create | Create action |
action.update | Update action |
action.delete | Delete action |
Users
| Method | Description |
|---|---|
user.get | Retrieve users |
user.create | Create user |
user.update | Update user |
user.delete | Delete user |
user.login | Authenticate |
user.logout | End session |
Configuration
| Method | Description |
|---|---|
configuration.export | Export to XML/JSON |
configuration.import | Import from XML/JSON |
Common Query Patterns
Filtering
# Exact match
api.host.get(filter={"host": "server01"})
# Multiple values
api.host.get(filter={"host": ["server01", "server02"]})
# Pattern search
api.host.get(search={"host": "server"}, searchWildcardsEnabled=True)Pagination
# First page
api.host.get(limit=100)
# Next page
api.host.get(limit=100, offset=100)Sorting
api.host.get(sortfield="host", sortorder="ASC")
api.trigger.get(sortfield=["priority", "lastchange"], sortorder=["DESC", "DESC"])Output Control
# Specific fields only
api.host.get(output=["hostid", "host", "name"])
# All fields
api.host.get(output="extend")
# Count only
api.host.get(countOutput=True)Error Codes
| Code | Description |
|---|---|
| -32700 | Parse error (invalid JSON) |
| -32600 | Invalid request |
| -32601 | Method not found |
| -32602 | Invalid params |
| -32603 | Internal error |
| -32500 | Application error |
| -32400 | System error |
| -32300 | Transport error |
Rate Limiting
Zabbix API does not have built-in rate limiting, but consider:
- Use batch operations (arrays) when possible
- Limit
outputto needed fields - Use
countOutputwhen only count is needed - Implement client-side rate limiting for bulk operations
Zabbix Trigger Expressions Reference
Expression Syntax (Zabbix 5.4+)
function(/host/key,parameter)<operator><constant>Common Functions
Value Functions
| Function | Description | Example |
|---|---|---|
last() | Last value | last(/host/key)>100 |
avg(period) | Average over period | avg(/host/key,5m)>80 |
min(period) | Minimum over period | min(/host/key,1h)<10 |
max(period) | Maximum over period | max(/host/key,1h)>95 |
sum(period) | Sum over period | sum(/host/key,1h)>1000 |
count(period) | Count values | count(/host/key,1h)>100 |
percentile(period,p) | Percentile value | percentile(/host/key,1h,95)>90 |
Change Functions
| Function | Description | Example |
|---|---|---|
change() | Absolute change | change(/host/key)>10 |
diff() | Value changed (0/1) | diff(/host/key)=1 |
abschange() | Absolute change value | abschange(/host/key)>100 |
Time Functions
| Function | Description | Example |
|---|---|---|
nodata(period) | No data received | nodata(/host/key,5m)=1 |
fuzzytime(sec) | Time difference | fuzzytime(/host/system.time,60)=0 |
now() | Current timestamp | N/A |
time() | Current time (HHMMSS) | time()>220000 |
dayofweek() | Day (1=Mon, 7=Sun) | dayofweek()>=6 |
dayofmonth() | Day of month (1-31) | dayofmonth()=1 |
String Functions
| Function | Description | Example |
|---|---|---|
strlen() | String length | strlen(last(/host/key))>100 |
find(pattern) | String contains | find(/host/key,,"like","error")=1 |
regexp(pattern) | Regex match | regexp(/host/key,,".*error.*")=1 |
Comparison Functions
| Function | Description | Example |
|---|---|---|
between(min,max) | Value in range | between(10,last(/host/key),90)=0 |
in(v1,v2,...) | Value in list | in(1,last(/host/key),2,3)=0 |
Operators
| Operator | Description |
|---|---|
= | Equal |
<> | Not equal |
< | Less than |
> | Greater than |
<= | Less or equal |
>= | Greater or equal |
and | Logical AND |
or | Logical OR |
not | Logical NOT |
Time Suffixes
| Suffix | Meaning |
|---|---|
s | Seconds |
m | Minutes |
h | Hours |
d | Days |
w | Weeks |
Common Expression Examples
CPU Monitoring
# High CPU load
last(/host/system.cpu.load[percpu,avg1])>5
# CPU utilization over 90% for 5 minutes
avg(/host/system.cpu.util,5m)>90
# CPU spike detection
change(/host/system.cpu.util)>30Memory Monitoring
# Low available memory (less than 10%)
last(/host/vm.memory.size[pavailable])<10
# Memory usage trend increasing
avg(/host/vm.memory.size[used],1h)>avg(/host/vm.memory.size[used],24h)*1.2Disk Monitoring
# Disk space low (less than 10% free)
last(/host/vfs.fs.size[/,pfree])<10
# Disk space critically low
last(/host/vfs.fs.size[/,pfree])<5 and last(/host/vfs.fs.size[/,free])<1073741824
# Disk I/O high
avg(/host/vfs.dev.read.rate[sda],5m)>10000000Network Monitoring
# Interface down
last(/host/net.if.status[eth0])=2
# High network traffic
avg(/host/net.if.in[eth0],5m)>100000000
# Packet loss detected
last(/host/icmppingloss)>10Service Monitoring
# Process not running
last(/host/proc.num[nginx])=0
# Too many processes
last(/host/proc.num[])>300
# Service port down
last(/host/net.tcp.service[http,,80])=0Log Monitoring
# Error in log
find(/host/log[/var/log/app.log],1h,"like","ERROR")=1
# Multiple errors
count(/host/log[/var/log/app.log],1h,"ERROR")>10
# Specific pattern
regexp(/host/log[/var/log/app.log],,"Exception.*timeout")=1Availability
# Agent unreachable for 5 minutes
nodata(/host/agent.ping,5m)=1
# Host unreachable
last(/host/icmpping)=0
# Multiple failures
count(/host/icmpping,10m,,"eq","0")>3Time-Based
# Only during business hours
last(/host/key)>100 and time()>=090000 and time()<=180000
# Weekday only
last(/host/key)>100 and dayofweek()<6
# Not during maintenance window
last(/host/key)>100 and time()<020000Recovery Expressions
Set separate recovery condition:
api.trigger.create(
description="High CPU",
expression="last(/host/system.cpu.util)>90",
recovery_mode=1, # 0=expression, 1=recovery_expression, 2=none
recovery_expression="last(/host/system.cpu.util)<70"
)Trigger Dependencies
Prevent alert storms with dependencies:
# Child trigger won't fire if parent is in problem state
api.trigger.adddependencies(
triggerid="child_trigger_id",
dependsOnTriggerid="parent_trigger_id"
)Macros in Expressions
| Macro | Description |
|---|---|
{HOST.HOST} | Technical hostname |
{HOST.NAME} | Visible hostname |
{HOST.IP} | Host IP address |
{TRIGGER.VALUE} | Trigger state (0/1) |
{$MACRO} | User macro |
#!/usr/bin/env python3
"""
Bulk host management for Zabbix via API.
Supports create, update, delete, and export operations from CSV.
Usage:
python zabbix-bulk-hosts.py create hosts.csv
python zabbix-bulk-hosts.py update hosts.csv
python zabbix-bulk-hosts.py delete hosts.csv
python zabbix-bulk-hosts.py export output.csv [--group GROUP_NAME]
Environment variables:
ZABBIX_URL - Zabbix frontend URL (default: http://localhost/zabbix)
ZABBIX_TOKEN - API token (preferred)
ZABBIX_USER - Username (fallback)
ZABBIX_PASSWORD - Password (fallback)
CSV format for create/update:
hostname,ip,groups,templates,description
server01,192.168.1.100,Linux servers,Linux by Zabbix agent,Web server
"""
import os
import sys
import csv
import argparse
from zabbix_utils import ZabbixAPI
def get_api():
url = os.environ.get("ZABBIX_URL", "http://localhost/zabbix")
api = ZabbixAPI(url=url)
if "ZABBIX_TOKEN" in os.environ:
api.login(token=os.environ["ZABBIX_TOKEN"])
elif "ZABBIX_USER" in os.environ:
api.login(user=os.environ["ZABBIX_USER"],
password=os.environ.get("ZABBIX_PASSWORD", ""))
else:
print("Error: Set ZABBIX_TOKEN or ZABBIX_USER/ZABBIX_PASSWORD")
sys.exit(1)
return api
def resolve_groups(api, group_names):
"""Convert group names to group IDs."""
groups = []
for name in group_names.split(","):
name = name.strip()
result = api.hostgroup.get(filter={"name": name}, output=["groupid"])
if result:
groups.append({"groupid": result[0]["groupid"]})
else:
# Create group if not exists
result = api.hostgroup.create(name=name)
groups.append({"groupid": result["groupids"][0]})
return groups
def resolve_templates(api, template_names):
"""Convert template names to template IDs."""
templates = []
for name in template_names.split(","):
name = name.strip()
if not name:
continue
result = api.template.get(filter={"host": name}, output=["templateid"])
if result:
templates.append({"templateid": result[0]["templateid"]})
else:
print(f"Warning: Template '{name}' not found")
return templates
def create_hosts(api, csv_file):
"""Create hosts from CSV file."""
with open(csv_file) as f:
reader = csv.DictReader(f)
for row in reader:
hostname = row.get("hostname", "").strip()
ip = row.get("ip", "").strip()
if not hostname or not ip:
print(f"Skipping row: missing hostname or ip")
continue
# Check if host exists
existing = api.host.get(filter={"host": hostname}, output=["hostid"])
if existing:
print(f"Skip: {hostname} already exists")
continue
try:
groups = resolve_groups(api, row.get("groups", "Discovered hosts"))
templates = resolve_templates(api, row.get("templates", ""))
params = {
"host": hostname,
"groups": groups,
"interfaces": [{
"type": 1,
"main": 1,
"useip": 1,
"ip": ip,
"dns": "",
"port": "10050"
}]
}
if templates:
params["templates"] = templates
if row.get("description"):
params["description"] = row["description"]
result = api.host.create(**params)
print(f"Created: {hostname} (hostid={result['hostids'][0]})")
except Exception as e:
print(f"Error creating {hostname}: {e}")
def update_hosts(api, csv_file):
"""Update existing hosts from CSV file."""
with open(csv_file) as f:
reader = csv.DictReader(f)
for row in reader:
hostname = row.get("hostname", "").strip()
if not hostname:
continue
existing = api.host.get(filter={"host": hostname}, output=["hostid"])
if not existing:
print(f"Skip: {hostname} not found")
continue
hostid = existing[0]["hostid"]
try:
params = {"hostid": hostid}
if row.get("groups"):
params["groups"] = resolve_groups(api, row["groups"])
if row.get("templates"):
params["templates"] = resolve_templates(api, row["templates"])
if row.get("description"):
params["description"] = row["description"]
api.host.update(**params)
print(f"Updated: {hostname}")
except Exception as e:
print(f"Error updating {hostname}: {e}")
def delete_hosts(api, csv_file):
"""Delete hosts from CSV file."""
with open(csv_file) as f:
reader = csv.DictReader(f)
for row in reader:
hostname = row.get("hostname", "").strip()
if not hostname:
continue
existing = api.host.get(filter={"host": hostname}, output=["hostid"])
if not existing:
print(f"Skip: {hostname} not found")
continue
try:
api.host.delete(existing[0]["hostid"])
print(f"Deleted: {hostname}")
except Exception as e:
print(f"Error deleting {hostname}: {e}")
def export_hosts(api, csv_file, group_name=None):
"""Export hosts to CSV file."""
params = {
"output": ["host", "name", "description"],
"selectInterfaces": ["ip"],
"selectGroups": ["name"],
"selectParentTemplates": ["host"]
}
if group_name:
groups = api.hostgroup.get(filter={"name": group_name}, output=["groupid"])
if groups:
params["groupids"] = [groups[0]["groupid"]]
hosts = api.host.get(**params)
with open(csv_file, "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["hostname", "ip", "groups", "templates", "description"])
for host in hosts:
ip = host["interfaces"][0]["ip"] if host.get("interfaces") else ""
groups = ",".join(g["name"] for g in host.get("groups", []))
templates = ",".join(t["host"] for t in host.get("parentTemplates", []))
writer.writerow([
host["host"],
ip,
groups,
templates,
host.get("description", "")
])
print(f"Exported {len(hosts)} hosts to {csv_file}")
def main():
parser = argparse.ArgumentParser(description="Bulk host management for Zabbix")
parser.add_argument("action", choices=["create", "update", "delete", "export"])
parser.add_argument("csv_file", help="CSV file path")
parser.add_argument("--group", help="Filter by group name (for export)")
args = parser.parse_args()
api = get_api()
if args.action == "create":
create_hosts(api, args.csv_file)
elif args.action == "update":
update_hosts(api, args.csv_file)
elif args.action == "delete":
delete_hosts(api, args.csv_file)
elif args.action == "export":
export_hosts(api, args.csv_file, args.group)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Export and import Zabbix configuration.
Usage:
python zabbix-export.py templates --output templates.json [--name "Template Name"]
python zabbix-export.py hosts --output hosts.json [--group "Group Name"]
python zabbix-export.py all --output config.json
python zabbix-export.py import config.json
Environment variables:
ZABBIX_URL - Zabbix frontend URL
ZABBIX_TOKEN - API token
"""
import os
import sys
import json
import argparse
from zabbix_utils import ZabbixAPI
def get_api():
url = os.environ.get("ZABBIX_URL", "http://localhost/zabbix")
api = ZabbixAPI(url=url)
if "ZABBIX_TOKEN" in os.environ:
api.login(token=os.environ["ZABBIX_TOKEN"])
elif "ZABBIX_USER" in os.environ:
api.login(user=os.environ["ZABBIX_USER"],
password=os.environ.get("ZABBIX_PASSWORD", ""))
else:
print("Error: Set ZABBIX_TOKEN or ZABBIX_USER/ZABBIX_PASSWORD")
sys.exit(1)
return api
def export_templates(api, output_file, template_name=None):
"""Export templates to JSON."""
params = {
"output": "extend",
"selectItems": "extend",
"selectTriggers": "extend",
"selectGraphs": "extend",
"selectDiscoveryRules": "extend",
"selectMacros": "extend",
"selectTags": "extend"
}
if template_name:
params["filter"] = {"host": template_name}
templates = api.template.get(**params)
with open(output_file, "w") as f:
json.dump({"templates": templates}, f, indent=2)
print(f"Exported {len(templates)} templates to {output_file}")
def export_hosts(api, output_file, group_name=None):
"""Export hosts to JSON."""
params = {
"output": "extend",
"selectInterfaces": "extend",
"selectGroups": ["groupid", "name"],
"selectParentTemplates": ["templateid", "host"],
"selectMacros": "extend",
"selectTags": "extend",
"selectInventory": "extend"
}
if group_name:
groups = api.hostgroup.get(filter={"name": group_name}, output=["groupid"])
if groups:
params["groupids"] = [groups[0]["groupid"]]
else:
print(f"Warning: Group '{group_name}' not found")
hosts = api.host.get(**params)
with open(output_file, "w") as f:
json.dump({"hosts": hosts}, f, indent=2)
print(f"Exported {len(hosts)} hosts to {output_file}")
def export_all(api, output_file):
"""Export all configuration."""
config = {
"version": api.api_version(),
"host_groups": api.hostgroup.get(output="extend"),
"templates": api.template.get(
output="extend",
selectItems=["itemid", "name", "key_"],
selectTriggers=["triggerid", "description"],
selectMacros="extend"
),
"hosts": api.host.get(
output="extend",
selectInterfaces="extend",
selectGroups=["groupid", "name"],
selectParentTemplates=["templateid", "host"],
selectMacros="extend"
),
"actions": api.action.get(
output="extend",
selectOperations="extend",
selectFilter="extend"
),
"media_types": api.mediatype.get(output="extend"),
"users": api.user.get(output=["userid", "username", "name", "surname"])
}
with open(output_file, "w") as f:
json.dump(config, f, indent=2)
print(f"Exported configuration to {output_file}")
print(f" Host groups: {len(config['host_groups'])}")
print(f" Templates: {len(config['templates'])}")
print(f" Hosts: {len(config['hosts'])}")
print(f" Actions: {len(config['actions'])}")
def import_config(api, input_file):
"""Import configuration from JSON (hosts only for safety)."""
with open(input_file) as f:
config = json.load(f)
if "hosts" in config:
for host_data in config["hosts"]:
hostname = host_data.get("host")
# Check if exists
existing = api.host.get(filter={"host": hostname}, output=["hostid"])
if existing:
print(f"Skip: {hostname} already exists")
continue
try:
# Prepare minimal host creation
groups = [{"groupid": g["groupid"]} for g in host_data.get("groups", [])]
if not groups:
# Use default group
groups = [{"groupid": "2"}]
interfaces = host_data.get("interfaces", [])
if interfaces:
# Clean interface data
interfaces = [{
"type": int(i.get("type", 1)),
"main": int(i.get("main", 1)),
"useip": int(i.get("useip", 1)),
"ip": i.get("ip", ""),
"dns": i.get("dns", ""),
"port": i.get("port", "10050")
} for i in interfaces]
params = {
"host": hostname,
"groups": groups,
"interfaces": interfaces
}
templates = host_data.get("parentTemplates", [])
if templates:
params["templates"] = [{"templateid": t["templateid"]} for t in templates]
api.host.create(**params)
print(f"Imported: {hostname}")
except Exception as e:
print(f"Error importing {hostname}: {e}")
print("Import complete")
def main():
parser = argparse.ArgumentParser(description="Export/import Zabbix configuration")
subparsers = parser.add_subparsers(dest="command", required=True)
# Templates export
tpl_parser = subparsers.add_parser("templates", help="Export templates")
tpl_parser.add_argument("--output", "-o", required=True, help="Output file")
tpl_parser.add_argument("--name", help="Template name filter")
# Hosts export
host_parser = subparsers.add_parser("hosts", help="Export hosts")
host_parser.add_argument("--output", "-o", required=True, help="Output file")
host_parser.add_argument("--group", help="Group name filter")
# All export
all_parser = subparsers.add_parser("all", help="Export all configuration")
all_parser.add_argument("--output", "-o", required=True, help="Output file")
# Import
import_parser = subparsers.add_parser("import", help="Import configuration")
import_parser.add_argument("file", help="Input file")
args = parser.parse_args()
api = get_api()
if args.command == "templates":
export_templates(api, args.output, args.name)
elif args.command == "hosts":
export_hosts(api, args.output, args.group)
elif args.command == "all":
export_all(api, args.output)
elif args.command == "import":
import_config(api, args.file)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Maintenance window management for Zabbix.
Usage:
python zabbix-maintenance.py create --name "Weekly Maintenance" --hosts host1,host2 --duration 3600
python zabbix-maintenance.py create --name "Patching" --groups "Linux servers" --start "2024-01-15 02:00" --duration 7200
python zabbix-maintenance.py list [--active]
python zabbix-maintenance.py delete --name "Weekly Maintenance"
python zabbix-maintenance.py delete --id 123
Environment variables:
ZABBIX_URL - Zabbix frontend URL
ZABBIX_TOKEN - API token
"""
import os
import sys
import argparse
import time
from datetime import datetime
from zabbix_utils import ZabbixAPI
def get_api():
url = os.environ.get("ZABBIX_URL", "http://localhost/zabbix")
api = ZabbixAPI(url=url)
if "ZABBIX_TOKEN" in os.environ:
api.login(token=os.environ["ZABBIX_TOKEN"])
elif "ZABBIX_USER" in os.environ:
api.login(user=os.environ["ZABBIX_USER"],
password=os.environ.get("ZABBIX_PASSWORD", ""))
else:
print("Error: Set ZABBIX_TOKEN or ZABBIX_USER/ZABBIX_PASSWORD")
sys.exit(1)
return api
def parse_datetime(dt_str):
"""Parse datetime string to Unix timestamp."""
if dt_str is None:
return int(time.time())
for fmt in ["%Y-%m-%d %H:%M", "%Y-%m-%d %H:%M:%S", "%Y-%m-%dT%H:%M"]:
try:
return int(datetime.strptime(dt_str, fmt).timestamp())
except ValueError:
continue
raise ValueError(f"Cannot parse datetime: {dt_str}")
def resolve_host_ids(api, host_names):
"""Convert host names to host IDs."""
host_ids = []
for name in host_names.split(","):
name = name.strip()
result = api.host.get(filter={"host": name}, output=["hostid"])
if result:
host_ids.append(result[0]["hostid"])
else:
print(f"Warning: Host '{name}' not found")
return host_ids
def resolve_group_ids(api, group_names):
"""Convert group names to group IDs."""
group_ids = []
for name in group_names.split(","):
name = name.strip()
result = api.hostgroup.get(filter={"name": name}, output=["groupid"])
if result:
group_ids.append(result[0]["groupid"])
else:
print(f"Warning: Group '{name}' not found")
return group_ids
def create_maintenance(api, args):
"""Create a maintenance window."""
start_time = parse_datetime(args.start)
duration = int(args.duration)
end_time = start_time + duration
params = {
"name": args.name,
"active_since": start_time,
"active_till": end_time,
"timeperiods": [{
"timeperiod_type": 0, # One-time
"start_date": start_time,
"period": duration
}]
}
# Add hosts or groups
if args.hosts:
host_ids = resolve_host_ids(api, args.hosts)
if host_ids:
params["hostids"] = host_ids
if args.groups:
group_ids = resolve_group_ids(api, args.groups)
if group_ids:
params["groupids"] = group_ids
if not params.get("hostids") and not params.get("groupids"):
print("Error: Must specify --hosts or --groups")
sys.exit(1)
# Maintenance type
if args.no_data:
params["maintenance_type"] = 1 # No data collection
else:
params["maintenance_type"] = 0 # With data collection
# Description
if args.description:
params["description"] = args.description
try:
result = api.maintenance.create(**params)
print(f"Created maintenance: {args.name} (id={result['maintenanceids'][0]})")
print(f" Start: {datetime.fromtimestamp(start_time)}")
print(f" End: {datetime.fromtimestamp(end_time)}")
print(f" Duration: {duration}s ({duration//3600}h {(duration%3600)//60}m)")
except Exception as e:
print(f"Error: {e}")
sys.exit(1)
def list_maintenance(api, args):
"""List maintenance windows."""
params = {
"output": ["maintenanceid", "name", "active_since", "active_till",
"maintenance_type", "description"],
"selectHosts": ["host"],
"selectGroups": ["name"]
}
maintenances = api.maintenance.get(**params)
now = int(time.time())
for m in maintenances:
start = int(m["active_since"])
end = int(m["active_till"])
# Filter active only if requested
if args.active and (now < start or now > end):
continue
status = "ACTIVE" if start <= now <= end else ("PENDING" if now < start else "EXPIRED")
mtype = "No data" if m["maintenance_type"] == "1" else "With data"
print(f"\n[{m['maintenanceid']}] {m['name']} ({status})")
print(f" Type: {mtype}")
print(f" Start: {datetime.fromtimestamp(start)}")
print(f" End: {datetime.fromtimestamp(end)}")
if m.get("hosts"):
hosts = [h["host"] for h in m["hosts"]]
print(f" Hosts: {', '.join(hosts)}")
if m.get("groups"):
groups = [g["name"] for g in m["groups"]]
print(f" Groups: {', '.join(groups)}")
def delete_maintenance(api, args):
"""Delete maintenance window."""
if args.id:
maintenance_id = args.id
elif args.name:
result = api.maintenance.get(filter={"name": args.name},
output=["maintenanceid"])
if not result:
print(f"Error: Maintenance '{args.name}' not found")
sys.exit(1)
maintenance_id = result[0]["maintenanceid"]
else:
print("Error: Must specify --id or --name")
sys.exit(1)
try:
api.maintenance.delete(maintenance_id)
print(f"Deleted maintenance: {maintenance_id}")
except Exception as e:
print(f"Error: {e}")
sys.exit(1)
def main():
parser = argparse.ArgumentParser(description="Zabbix maintenance management")
subparsers = parser.add_subparsers(dest="command", required=True)
# Create command
create_parser = subparsers.add_parser("create", help="Create maintenance window")
create_parser.add_argument("--name", required=True, help="Maintenance name")
create_parser.add_argument("--hosts", help="Comma-separated host names")
create_parser.add_argument("--groups", help="Comma-separated group names")
create_parser.add_argument("--start", help="Start time (YYYY-MM-DD HH:MM), default: now")
create_parser.add_argument("--duration", required=True, help="Duration in seconds")
create_parser.add_argument("--description", help="Description")
create_parser.add_argument("--no-data", action="store_true",
help="Disable data collection during maintenance")
# List command
list_parser = subparsers.add_parser("list", help="List maintenance windows")
list_parser.add_argument("--active", action="store_true", help="Show only active")
# Delete command
delete_parser = subparsers.add_parser("delete", help="Delete maintenance window")
delete_parser.add_argument("--id", help="Maintenance ID")
delete_parser.add_argument("--name", help="Maintenance name")
args = parser.parse_args()
api = get_api()
if args.command == "create":
create_maintenance(api, args)
elif args.command == "list":
list_maintenance(api, args)
elif args.command == "delete":
delete_maintenance(api, args)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Zabbix environment diagnostics and status check.
Usage:
python zabbix-status.py # Full status report
python zabbix-status.py problems # Current problems only
python zabbix-status.py hosts # Host status summary
python zabbix-status.py queue # Queue status
Environment variables:
ZABBIX_URL - Zabbix frontend URL
ZABBIX_TOKEN - API token
"""
import os
import sys
import argparse
from datetime import datetime
from zabbix_utils import ZabbixAPI
def get_api():
url = os.environ.get("ZABBIX_URL", "http://localhost/zabbix")
api = ZabbixAPI(url=url)
if "ZABBIX_TOKEN" in os.environ:
api.login(token=os.environ["ZABBIX_TOKEN"])
elif "ZABBIX_USER" in os.environ:
api.login(user=os.environ["ZABBIX_USER"],
password=os.environ.get("ZABBIX_PASSWORD", ""))
else:
print("Error: Set ZABBIX_TOKEN or ZABBIX_USER/ZABBIX_PASSWORD")
sys.exit(1)
return api
SEVERITY_NAMES = {
"0": "Not classified",
"1": "Information",
"2": "Warning",
"3": "Average",
"4": "High",
"5": "Disaster"
}
SEVERITY_COLORS = {
"0": "\033[90m", # Gray
"1": "\033[94m", # Blue
"2": "\033[93m", # Yellow
"3": "\033[33m", # Orange
"4": "\033[91m", # Light red
"5": "\033[31m", # Red
}
RESET = "\033[0m"
def show_problems(api, limit=50):
"""Show current problems."""
problems = api.problem.get(
output=["eventid", "name", "severity", "clock", "acknowledged"],
selectHosts=["host"],
recent=True,
sortfield=["severity", "clock"],
sortorder=["DESC", "DESC"],
limit=limit
)
if not problems:
print("✓ No active problems")
return
print(f"\n{'='*60}")
print(f"ACTIVE PROBLEMS ({len(problems)})")
print(f"{'='*60}")
# Group by severity
by_severity = {}
for p in problems:
sev = p["severity"]
if sev not in by_severity:
by_severity[sev] = []
by_severity[sev].append(p)
for sev in sorted(by_severity.keys(), reverse=True):
color = SEVERITY_COLORS.get(sev, "")
sev_name = SEVERITY_NAMES.get(sev, "Unknown")
print(f"\n{color}[{sev_name}]{RESET}")
for p in by_severity[sev]:
host = p["hosts"][0]["host"] if p.get("hosts") else "Unknown"
time_str = datetime.fromtimestamp(int(p["clock"])).strftime("%Y-%m-%d %H:%M")
ack = "✓" if p["acknowledged"] == "1" else " "
print(f" {ack} [{time_str}] {host}: {p['name']}")
def show_hosts_status(api):
"""Show host status summary."""
hosts = api.host.get(
output=["hostid", "host", "name", "status", "available"],
selectInterfaces=["ip", "available"]
)
total = len(hosts)
enabled = sum(1 for h in hosts if h["status"] == "0")
disabled = total - enabled
available = sum(1 for h in hosts if h.get("available") == "1")
unavailable = sum(1 for h in hosts if h.get("available") == "2")
unknown = total - available - unavailable
print(f"\n{'='*40}")
print("HOST STATUS")
print(f"{'='*40}")
print(f"Total hosts: {total}")
print(f" Enabled: {enabled}")
print(f" Disabled: {disabled}")
print(f"\nAgent availability:")
print(f" Available: {available}")
print(f" Unavailable: {unavailable}")
print(f" Unknown: {unknown}")
# Show unavailable hosts
unavailable_hosts = [h for h in hosts if h.get("available") == "2"]
if unavailable_hosts:
print(f"\nUnavailable hosts ({len(unavailable_hosts)}):")
for h in unavailable_hosts[:10]:
ip = h["interfaces"][0]["ip"] if h.get("interfaces") else "N/A"
print(f" - {h['host']} ({ip})")
if len(unavailable_hosts) > 10:
print(f" ... and {len(unavailable_hosts) - 10} more")
def show_queue(api):
"""Show item queue status."""
# Get items not yet processed
try:
# This requires specific permissions
queue = api.queue.get(output="extend")
if not queue:
print("✓ Queue is empty")
return
print(f"\n{'='*40}")
print("QUEUE STATUS")
print(f"{'='*40}")
# Group by delay
delays = {}
for item in queue:
delay = int(item.get("delay", 0))
if delay not in delays:
delays[delay] = 0
delays[delay] += 1
for delay in sorted(delays.keys()):
print(f" {delay}s+ delay: {delays[delay]} items")
except Exception as e:
print(f"Queue status unavailable: {e}")
def show_full_status(api):
"""Show full environment status."""
print(f"\n{'='*60}")
print("ZABBIX ENVIRONMENT STATUS")
print(f"{'='*60}")
# API info
version = api.api_version()
print(f"API Version: {version}")
print(f"URL: {os.environ.get('ZABBIX_URL', 'http://localhost/zabbix')}")
# Counts
hosts = api.host.get(countOutput=True)
templates = api.template.get(countOutput=True)
items = api.item.get(countOutput=True, monitored=True)
triggers = api.trigger.get(countOutput=True, monitored=True)
print(f"\nObject counts:")
print(f" Hosts: {hosts}")
print(f" Templates: {templates}")
print(f" Items: {items}")
print(f" Triggers: {triggers}")
# Problems summary
problems = api.problem.get(countOutput=True, recent=True)
print(f"\nActive problems: {problems}")
# Show details
show_hosts_status(api)
show_problems(api, limit=20)
def main():
parser = argparse.ArgumentParser(description="Zabbix status check")
parser.add_argument("command", nargs="?", default="full",
choices=["full", "problems", "hosts", "queue"],
help="Status type (default: full)")
parser.add_argument("--limit", type=int, default=50,
help="Limit results (for problems)")
args = parser.parse_args()
api = get_api()
if args.command == "full":
show_full_status(api)
elif args.command == "problems":
show_problems(api, args.limit)
elif args.command == "hosts":
show_hosts_status(api)
elif args.command == "queue":
show_queue(api)
if __name__ == "__main__":
main()