Programmatic Zabbix template generation — Monitoring as Code
Project description
zbxtemplar
A Pythonic framework for programmatic Zabbix configuration generation (Monitoring as Code).
Define templates, hosts, user groups, and users as Python code. Generate Zabbix-native YAML (importable via UI or API) and decree YAML (applied by the executor). The goal is to cover the essential Zabbix configuration primitives — not every possible option. If you need a field that isn't exposed, raw dicts and string expressions give you an escape hatch.
Installation
pip install .
Core Architecture
The project follows the src-layout:
zbxtemplar.zabbix— Domain models: Template, Host, Item, Trigger, Graph, Dashboard.zbxtemplar.core— Module contracts (TemplarModule,DecreeModule) and entity registry (Context).zbxtemplar.decree— Decree domain classes:DecreeEntity,UserGroup,User,UserMedia,Action,TriggerAction, conditions, operations, and predefined constants.zbxtemplar.main— CLI entry point and module loader.zbxtemplar.executor— Applies generated artifacts to a live Zabbix instance.
Module Contract
Configuration is defined as Python classes that inherit from TemplarModule (monitoring) or DecreeModule (users/groups). The constructor is the contract — all configuration logic lives in __init__.
Constructor arguments become CLI parameters via --param KEY=VALUE. The loader inspects the __init__ signature and performs type coercion based on annotations (str, int, float, bool).
from zbxtemplar.core import TemplarModule
from zbxtemplar.zabbix import Template, Item, Host, TriggerPriority
from zbxtemplar.zabbix.Template import TemplateGroup
from zbxtemplar.zabbix.Host import HostGroup, AgentInterface
class MyModule(TemplarModule):
def __init__(self, alert_threshold: int = 90):
super().__init__()
template = Template(name="My Service", groups=[TemplateGroup("Custom Templates")])
template.add_tag("Service", "MyApp")
template.add_macro("THRESHOLD", alert_threshold, "Alert threshold")
item = Item("CPU Usage", "system.cpu.util", template.name)
item.add_trigger("High CPU", "last", ">",
template.get_macro("THRESHOLD"),
priority=TriggerPriority.HIGH)
template.add_item(item)
host = Host("My Server", groups=[HostGroup("Linux Servers")])
host.add_template(template)
host.add_interface(AgentInterface(ip="192.168.1.10"))
self.add_template(template)
self.add_host(host)
The loader discovers all TemplarModule and DecreeModule subclasses in the file by class name.
Running standalone
Add a __main__ guard to run the module directly:
if __name__ == "__main__":
import yaml
module = MyModule()
print(yaml.dump(module.to_export(), default_flow_style=False, sort_keys=False))
CLI
Single command, auto-detects module type:
# Combined output (templates + hosts)
zbxtemplar module.py -o output.yml
# Separate outputs
zbxtemplar module.py --templates-output templates.yml --hosts-output hosts.yml
# With UUID namespace
zbxtemplar module.py -o output.yml --namespace "My Company"
# With parameters
zbxtemplar module.py -o output.yml --param ENV=prod --param ALERT_THRESHOLD=5
# Decree module with context
zbxtemplar decree_module.py -o decree.yml --context templates.yml --context hosts.yml
| Argument | Description |
|---|---|
module |
Path to a .py file with TemplarModule/DecreeModule subclass(es) |
-o, --output |
Combined output YAML file path |
--templates-output |
Output YAML for templates only (TemplarModule) |
--hosts-output |
Output YAML for hosts only (TemplarModule) |
--user-groups-output |
Output YAML for user groups only (DecreeModule) |
--users-output |
Output YAML for users only (DecreeModule) |
--actions-output |
Output YAML for actions only (DecreeModule) |
--namespace |
UUID namespace for deterministic ID generation |
--param KEY=VALUE |
Parameter passed to the module constructor (repeatable) |
--context FILE |
Context YAML file for decree validation (repeatable) |
At least one output flag is required.
Programmatic Loading
from zbxtemplar.main import load_module
modules = load_module("path/to/module.py", params={"ENV": "prod"})
# Returns {"ClassName": <instance>, ...}
for name, mod in modules.items():
export = mod.to_export() # Full zabbix_export or decree dict
Entities Reference
Template
template = Template(name="My Template", groups=[TemplateGroup("Custom Group")])
template.add_tag("Service", "MyApp")
template.add_macro("TIMEOUT", 30, "Connection timeout")
template.add_item(item)
Host
from zbxtemplar.zabbix import Host
from zbxtemplar.zabbix.Host import HostGroup, AgentInterface
host = Host("My Host", groups=[HostGroup("Linux Servers")])
host.add_tag("Environment", "Production")
host.add_macro("HOST_PORT", 8080, "Application port")
# Link a template
host.add_template(template)
# Add an interface (first interface becomes the default)
iface = AgentInterface(ip="192.168.1.10", port="10050")
host.add_interface(iface)
# Host-level items, triggers, graphs work the same as on templates
item = Item("Host Uptime", "system.uptime", host.name)
item.set_interface(iface)
host.add_item(item)
# Macro lookup walks linked templates when not found on the host
host.get_macro("TEMPLATE_MACRO") # falls back to template macros
Hosts produce UUID-free YAML (matching Zabbix export format). Dashboards are template-only and cannot be added to hosts.
AgentInterface is the built-in interface type (type: ZABBIX). Custom interface types can be created by subclassing HostInterface.
HostGroup
from zbxtemplar.zabbix.Host import HostGroup
group = HostGroup("Linux Servers")
Works the same as TemplateGroup — name-based identity with a deterministic UUID.
Item
item = Item("CPU Usage", "system.cpu.util")
# Expression helper — builds Zabbix function strings
item.expr("last") # last(/host/key)
item.expr("min", "10m") # min(/host/key,10m)
item.expr("count", "#10") # count(/host/key,#10)
# Single-item trigger shorthand
item.add_trigger("High CPU", "last", ">", 90,
priority=TriggerPriority.HIGH,
description="CPU threshold exceeded")
# With function args
item.add_trigger("Sustained high", "min", ">", 100,
fn_args=("10m",), priority=TriggerPriority.WARNING)
All enum values (ItemType, ValueType, TriggerPriority, GraphType, DrawType, CalcFnc, etc.) follow the Zabbix export format documentation.
Trigger
# Standalone (multi-item) trigger — raw expression string
Trigger(name="Complex alert",
expression=item1.expr("last") + ">0 and " + item2.expr("min", "5m") + "<100",
priority=TriggerPriority.WARNING,
description="Multi-item condition")
Macro
Macros work seamlessly in string contexts:
template.add_macro("MY_MACRO", 1, "Description")
macro = template.get_macro("MY_MACRO")
str(macro) # {$MY_MACRO}
item.expr("last") + ">" + macro # last(/host/key)>{$MY_MACRO}
item.add_trigger("Alert", "last", ">", macro) # works as threshold
Graph
graph = Graph("CPU Graph",
graph_type=GraphType.STACKED,
y_min_type=YAxisType.FIXED, y_min=0,
y_max_type=YAxisType.FIXED, y_max=100)
graph.add_item(item1, "FF0000")
graph.add_item(item2, "00FF00",
drawtype=DrawType.BOLD_LINE,
calc_fnc=CalcFnc.MAX,
yaxisside=YAxisSide.RIGHT)
Dashboard
from zbxtemplar.zabbix import Dashboard, DashboardPage
from zbxtemplar.zabbix.DashboardWidget import ClassicGraph
page = DashboardPage(name="Overview", display_period=120)
page.add_widget(ClassicGraph(template=template.name, graph=graph, width=36, height=5))
dashboard = Dashboard("My Dashboard", display_period=60, auto_start=YesNo.NO)
dashboard.add_page(page)
template.add_dashboard(dashboard)
Widgets are concrete subclasses of Widget (abstract). Each widget type lives in zbxtemplar.zabbix.DashboardWidget. Creating custom widgets is straightforward — subclass Widget, define type and widget_fields().
DecreeModule
Decree modules generate user groups, users, and actions as decree YAML (consumed by the executor).
from zbxtemplar.core import DecreeModule
from zbxtemplar.decree import UserGroup, User, UserMedia, MediaType, UserRole, GuiAccess, Permission, Severity
class MyDecree(DecreeModule):
def __init__(self, alert_email: str = "alerts@example.com"):
super().__init__()
group = UserGroup("Operations", gui_access=GuiAccess.INTERNAL)
group.add_host_group("Linux servers", Permission.READ)
group.add_template_group("Custom Templates", Permission.READ_WRITE)
self.add_user_group(group)
admin = User("zbx-admin", role=UserRole.SUPER_ADMIN)
admin.set_password("${ZBX_ADMIN_PASSWORD}")
admin.add_group(group)
email = UserMedia(MediaType.EMAIL, alert_email)
email.set_severity([Severity.AVERAGE, Severity.HIGH, Severity.DISASTER])
admin.add_media(email)
self.add_user(admin)
Context files provide known names for cross-reference validation:
zbxtemplar decree_module.py -o decree.yml --context templates.yml --context hosts.yml
Actions
Actions define automated responses to events. Currently supported: TriggerAction (eventsource 0).
from zbxtemplar.decree.Action import TriggerAction
from zbxtemplar.decree.action_conditions import (
HostGroupCondition, SeverityCondition, HostTemplateCondition,
TagCondition, ConditionList, EvalType,
)
action = TriggerAction("Notify on production problems")
# Conditions — use & (and), | (or), ~ (not) operators
action.set_conditions(
HostGroupCondition("Production") & SeverityCondition(Severity.HIGH)
)
# Or use a ConditionList for simpler AND/OR/AND_OR evaluation
conditions = ConditionList(EvalType.AND_OR)
conditions.add(HostGroupCondition("Production"))
conditions.add(SeverityCondition(Severity.HIGH))
action.set_conditions(conditions)
# Operations — escalation with send_message
action.operations.send_message(
groups=["Operations"], step_from=1, step_to=3,
subject="Problem: {EVENT.NAME}", message="Host: {HOST.NAME}"
)
# Recovery and update operations (no escalation)
action.recovery_operations.send_message(groups=["Operations"])
action.update_operations.send_message(groups=["Operations"])
self.add_action(action)
Condition expressions
Bare expressions are auto-wrapped into ConditionExpression (evaltype 3 with formula):
a = HostGroupCondition("Production")
b = HostGroupCondition("Staging")
c = SeverityCondition(Severity.HIGH)
action.set_conditions((a | b) & c) # formula: "(A or B) and C"
action.set_conditions(a & ~b) # formula: "A and not B"
Python's &, |, ~ operator precedence matches Zabbix's and, or, not — parentheses are generated automatically when needed.
Safety: Using Python's and/or/not keywords instead of &/|/~ raises TypeError immediately (conditions override __bool__).
Available condition types
All 26 Zabbix condition types are supported (conditiontype 0–28). Each has a typed Op enum restricting to valid operators only. Common ones:
| Class | conditiontype | Default operator |
|---|---|---|
HostGroupCondition |
0 | EQUALS |
HostCondition |
1 | EQUALS |
TriggerCondition |
2 | EQUALS |
EventNameCondition |
3 | CONTAINS |
SeverityCondition |
4 | GREATER_OR_EQUAL |
TriggerValueCondition |
5 | EQUALS |
HostTemplateCondition |
13 | EQUALS |
TagCondition |
25 | EQUALS |
TagValueCondition |
26 | EQUALS |
All condition classes are in zbxtemplar.decree.action_conditions.
Predefined Constants
Commonly referenced Zabbix objects are available as typed constants with IDE autocomplete:
from zbxtemplar.decree import MediaType, UserRole, GuiAccess, Permission, Severity
MediaType.EMAIL # "Email"
MediaType.SLACK # "Slack"
MediaType.PAGERDUTY # "PagerDuty"
UserRole.SUPER_ADMIN # "Super admin role"
| Class | Values |
|---|---|
MediaType |
41 built-in media types (Zabbix 7.4) |
UserRole |
SUPER_ADMIN, ADMIN, USER, GUEST |
GuiAccess |
DEFAULT, INTERNAL, LDAP, DISABLED |
Permission |
NONE, READ, READ_WRITE |
Severity |
NOT_CLASSIFIED, INFORMATION, WARNING, AVERAGE, HIGH, DISASTER |
MacroType |
TEXT, SECRET, VAULT |
Constants are a convenience, not a requirement — plain strings work anywhere a constant is expected.
Global Configuration
from zbxtemplar.zabbix.ZbxEntity import set_uuid_namespace
set_uuid_namespace("My Company") # Deterministic UUIDs scoped to namespace
Executor
The executor is a separate tool that applies generated YAML and other configuration to a live Zabbix instance. Install with the executor extra:
pip install ".[executor]"
Commands
# Bootstrap or rotate super admin password
zbxtemplar-exec set_super_admin --new-password $ZBX_ADMIN_PASSWORD \
--user Admin --password zabbix --url http://localhost
# Set global macros
zbxtemplar-exec set_macro SNMP_COMMUNITY public --token $ZBX_TOKEN
zbxtemplar-exec set_macro macros.yml --token $ZBX_TOKEN
# Import Zabbix-native YAML (templates, hosts, media types, etc.)
zbxtemplar-exec apply zabbix-native.yml --token $ZBX_TOKEN
# Apply state configuration (user groups, users, actions)
zbxtemplar-exec decree state.yml --token $ZBX_TOKEN
# Create service accounts (shorthand — feeds into decree)
zbxtemplar-exec add_user users.yml --token $ZBX_TOKEN
Connection credentials can be passed via CLI flags (--url, --token, --user, --password) or environment variables (ZABBIX_URL, ZABBIX_TOKEN, ZABBIX_USER, ZABBIX_PASSWORD).
Decree
A decree is zbxtemplar's declarative YAML format for live-state configuration that has no Zabbix-native import format. A single decree file can contain any combination of supported sections, processed in dependency order: user_group → add_user → actions.
user_group:
- name: Templar Users
gui_access: INTERNAL
host_groups:
- name: Linux servers
permission: READ
template_groups:
- name: Custom Templates
permission: READ_WRITE
add_user:
- username: zbx-service
role: Super admin role
password: ${ZBX_SERVICE_PASSWORD}
groups:
- Templar Users
actions:
- name: Notify on problems
eventsource: 0
operations:
- operationtype: 0
opmessage_grp:
- usrgrpid: Templar Users
esc_step_from: 1
esc_step_to: 1
esc_period: 0
filter:
evaltype: 3
formula: A and B
conditions:
- conditiontype: 0
operator: 0
value: Linux servers
formulaid: A
- conditiontype: 4
operator: 5
value: HIGH
formulaid: B
All references are by name — the executor resolves IDs at runtime (host groups, templates, user groups, users, media types in conditions and operations). In a scroll, decree accepts a file path, an inline dict, or a list mixing both.
Named constants for gui_access: DEFAULT, INTERNAL, LDAP, DISABLED.
Named constants for permission: NONE, READ, READ_WRITE.
Severity uses comma-separated names instead of bitmasks: NOT_CLASSIFIED, INFORMATION, WARNING, AVERAGE, HIGH, DISASTER.
If a user has token defined and the token already exists, the executor raises an error. Set force_token: true to delete and recreate the token.
The add_user CLI command is a shorthand that feeds a file containing add_user: into the decree pipeline.
Scroll
A scroll is a static YAML file describing a full deployment sequence. Stages execute in a fixed pipeline order: bootstrap → templates → state.
stages:
- stage: bootstrap
set_super_admin:
password: ${ZBX_ADMIN_PASSWORD}
set_macro:
- name: SNMP_COMMUNITY
value: public
- name: DB_PASSWORD
value: ${DB_PASSWORD}
type: secret
- stage: templates
apply:
- templates.yml
- media-types.yml
- stage: state
decree:
user_group:
- name: Templar Users
gui_access: INTERNAL
add_user:
- username: zbx-service
role: Super admin role
password: ${ZBX_SERVICE_PASSWORD}
zbxtemplar-exec scroll deploy.scroll.yml --token $ZBX_TOKEN
zbxtemplar-exec scroll deploy.scroll.yml --from-stage state
zbxtemplar-exec scroll deploy.scroll.yml --only-stage bootstrap
File paths in scroll actions resolve relative to the scroll file's directory, not the working directory. String values may contain ${ENV_VAR} references, resolved from the OS environment before any API calls. Missing variables cause a pre-flight failure — no partial execution.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zbxtemplar-0.7.0.tar.gz.
File metadata
- Download URL: zbxtemplar-0.7.0.tar.gz
- Upload date:
- Size: 47.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f4df4c384bf3383e321e245e2faf55c659423b35fa578786fe89f5f589c04156
|
|
| MD5 |
47849ea81b9e9352694cb4a2f637690a
|
|
| BLAKE2b-256 |
7a0617e5ab5b0b6acffc35687e255a00c388bc85efd6ce1c477cddd3361592db
|
File details
Details for the file zbxtemplar-0.7.0-py3-none-any.whl.
File metadata
- Download URL: zbxtemplar-0.7.0-py3-none-any.whl
- Upload date:
- Size: 42.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c79473379f1b9bde6aad74ef25e8a4c17b09dfb063533c03ce6e370b6395c71f
|
|
| MD5 |
c3b0effc43e6848cbd8806c6bc60ebf5
|
|
| BLAKE2b-256 |
1836f03e073d9f790514bbe629b03faa72b9860adfa51aced7868f441039d2c5
|