Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
__pycache__/
*.py[cod]
34 changes: 34 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
# Changelog

## [Unreleased]
### New features

- Added `exclude_tag` configuration setting to exclude hosts from Zabbix sync entirely via a ZabbixTag assigned to any object in the inheritance chain (`ZabbixTag.tag` name match)
- Added `ZabbixTemplateRule` for regex-based template (and optional hostgroup/tag) assignment by platform name (`re.search`, case-insensitive)
- Template rules support optional conjunctive criteria: `role_pattern`, `require_tags` (NetBox tag slugs) and `manufacturer` (fail-closed when set; `PROTECT` on delete). Optional hostgroup/tag FKs also use `PROTECT`
- Template rules that attach a hostgroup are shown on the Zabbix Hostgroup detail/list views
- Added a REST API endpoint for `ZabbixTemplateRule` (`/api/plugins/nbxsync/zabbixtemplaterule/`)
- Added Site/SiteGroup/Region inheritance paths (appended after role/platform so upgrades do not change Role/Platform precedence); cluster site uses `cluster._site` (available since NetBox 4.2; plugin requires ≥4.2.6)
- Added `ZabbixHostBinding`: a durable record of the Zabbix host owned by each NetBox object, so a host can still be retired after its (inherited) assignment disappears
- Added a background sync job that enumerates Devices/VMs inheriting a Zabbix server assignment, providing zero-touch provisioning for newly created inventory
- Added `allow_inherited_deletion` (default `False`) so inheritance-driven host deletions are reported with their impact before any Zabbix history is discarded
- Added `adopt_existing_hosts` (default `False`) so binding to a pre-existing Zabbix host is an explicit decision instead of a silent takeover. Requires `attach_objtag=True` (identity tags)

### Improvements

- Nested hostgroups: missing path segments (`A/B/C`) are created parent-first in Zabbix so permissions can inherit into subgroups
- Nested hostgroup rename: editing a static group's `ZabbixHostgroup.value` renames the Zabbix group in place via the stored `groupid`
- Configuration Group interfaces are deduplicated by interface identity (type, connect mode, port, DNS, OOB flag), so a second interface of the same Zabbix type is no longer dropped
- A failing host interface no longer hides the failure: per-interface and template-linkage failures are recorded on the assignment and reported as an aggregated job error
- Background host reconciliation collects host primary keys with queryset iterators instead of materialising full Device/VM lists
- Plugin requires NetBox ≥4.2.6 (`PluginConfig.min_version`)
- Inherited sync status on the Zabbix tab uses a neutral indicator (distinct from a direct local assignment)
- Default `backgroundsync.objects.interval` is 360 minutes so a full reconcile is less likely to overlap the next run

### Bug fixes

- Jinja2 tag and hostgroup values are rendered against the Device/VM being synchronised, not against the inheritance source (Role, Platform, Site, …)
- Tag/hostgroup Jinja context exposes `device`, `site`, `tenant`, `role`, `device_type`, and `manufacturer` aliases from the render object (covers #102; aliases follow the host during sync)
- UI previews for hierarchy assignments use a device-shaped view of the target object instead of borrowing a sample descendant device
- UI previews skip Devices/VMs carrying the configured `exclude_tag` when selecting a representative host
- VirtualMachines no longer inherit assignments via `device`-prefixed `inheritance_chain` paths (NetBox ≥4.3 `VirtualMachine.device`). Host manufacturer/role/device-type templates no longer leak onto guest VMs; Virtual Device Contexts still walk those paths
- Deleting a Device/VM in NetBox always retires its Zabbix host (via `ZabbixHostBinding`) even when `sync_enabled` is False on the assignment or server — inventory deletion is intentional retirement, not a background sync

## [1.0.0] - Initial Release

- Loads of features, :)
Expand Down
107 changes: 103 additions & 4 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,17 @@ The plugin is configuration to do exactly what you want, by means of the plugin
['cluster'],
['cluster', 'type'],
['type'],
# Hierarchy appended after device/role/platform (first-seen wins)
['device', 'site'],
['site'],
['site', 'group'],
['site', 'region'],
['cluster', '_site'],
],
'backgroundsync': {
'objects': {
'enabled': True,
'interval': 60, # 1 hour
'interval': 360, # 6 hours
},
'templates': {
'enabled': True,
Expand Down Expand Up @@ -105,10 +111,64 @@ The plugin is configuration to do exactly what you want, by means of the plugin
'objtag_type': 'nb_type',
'objtag_id': 'nb_id',
'custom_field_hostname':'',
'custom_field_display_name':''
'custom_field_display_name':'',
'exclude_tag': '',
'allow_inherited_deletion': False,
'adopt_existing_hosts': False,
}
```

## Inheritance Chain

The `inheritance_chain` setting defines which NetBox objects are traversed when resolving Zabbix assignments. Assignments (templates, tags, hostgroups, macros, proxy/server, inventory, configuration groups) made on any object in the chain are inherited by the device or VM being synced, with direct assignments taking priority. Within inherited sources, **first path wins** (leaf-first order as listed).

Host interfaces are the exception: they are defined on a Device/VM directly, on a `ZabbixConfigurationGroup`, or on a NetBox Tag (as a reusable interface template), because an interface needs a per-device endpoint. To apply interfaces to a whole Site, SiteGroup or Region, assign a Configuration Group at that level — its interfaces are then cloned onto every inheriting device with that device's primary IP.

### VirtualMachine and `device`-prefixed paths

Paths that start with `device` (for example `['device']`, `['device', 'role']`, `['device', 'device_type', 'manufacturer']`) describe the associated physical device.

Virtual Device Contexts keep these paths (a VDC is part of its parent device). VirtualMachines skip them: since NetBox 4.3, `VirtualMachine.device` links a guest to its hosting device, and walking that path would leak host hardware assignments onto the guest. VMs still inherit via cluster, site, role, platform and tag paths that apply to the VM itself.

### Site, SiteGroup, and Region Inheritance

Hierarchy paths are appended after device/role/platform/manufacturer/cluster paths so upgrading into Site inheritance does not silently override existing Role or Platform assignments. SiteGroup and Region ancestors are walked automatically when a group or region is reached.

| Path | Description |
|------|-------------|
| `['device', 'site']` | The device's site (also VDC → device → site; not walked for VirtualMachines) |
| `['site']` | Site (direct) |
| `['site', 'group']` | The site's SiteGroup (parents walked) |
| `['site', 'region']` | The site's region (parents walked) |
| `['cluster', '_site']` | The cluster's scoped site for VMs (`CachedScopeMixin._site`, NetBox 4.2+; plugin requires ≥4.2.6) |

If you previously customized `inheritance_chain` with Site paths ahead of Role/Platform, review hosts that have both a Site-level and a Role/Platform-level assignment — effective winners may change. Prefer appending hierarchy paths.

For example, assigning a `ZabbixServerAssignment` (proxy) to a `SiteGroup` means every device at every site in that SiteGroup inherits the proxy — no per-device assignment needed.

## Zabbix Template Rules

`ZabbixTemplateRule` assigns a Zabbix template (and optionally a hostgroup and tag) when a Device or VM matches the rule. The platform name is matched with case-insensitive `re.search`. Rules run after direct and inherited assignments, so explicit `ZabbixTemplateAssignment` objects always take priority.

Optional hostgroup/tag assignment is useful for OS-family grouping (for example a Windows rule that assigns the agent template, a `Windows` hostgroup and an `os_family=Windows` tag). Hostgroups attached by a rule appear on the Zabbix Hostgroup page under Template rules.

| Field | Description |
|-------|-------------|
| `name` | Human-readable name |
| `pattern` | Regex matched against platform name (`re.search`, case-insensitive). Use `.*` when matching only on role, tags or manufacturer |
| `role_pattern` | Optional regex against the Device/VM role name. Empty = any role |
| `require_tags` | Optional comma-separated NetBox tag slugs (all required). Empty = any. Uses object tags, not DeviceType tags |
| `manufacturer` | Optional Manufacturer. When set, `device_type.manufacturer` must match. Empty = any. Objects without a manufacturer (e.g. VMs) do not match. Uses `PROTECT` on delete |
| `zabbixtemplate` | Template assigned when the rule matches |
| `zabbixhostgroup` | Optional hostgroup assigned on match |
| `zabbixtag` | Optional tag assigned on match |
| `enabled` | Enable/disable without deleting the rule |
| `priority` | Lower value = higher priority |

All non-empty criteria are combined with AND. Patterns are validated on save; common nested-quantifier shapes such as `(a+)+` / `(a*){2,}` are rejected as a ReDoS guard (not a complete regex safety analyser). Platform names are capped at 64 characters (roles at 100). Optional hostgroups must belong to the same Zabbix server as the template.

Example: `pattern=.*`, `role_pattern=^Server$`, `manufacturer=Dell`, template = Dell iDRAC by SNMP — without assigning that template on every Dell Manufacturer object.

## Configuration values

### Source of Truth
Expand Down Expand Up @@ -153,11 +213,13 @@ This key is used to determine if 'objects' (that is: Devices and/or Virtual Mach

##### enabled

Either true or false (default: True)
Either true or false (default: True). When enabled, a periodic job enumerates all Devices and VirtualMachines that inherit a `ZabbixServerAssignment` (direct or from SiteGroup/Site/Region/Role/Platform/etc.) and enqueues each for sync.

##### interval

Used to determine the interval to sync Devices and Virtual Machines to/from Zabbix, in minutes (default: 60)
Used to determine the interval to sync Devices and Virtual Machines to/from Zabbix, in minutes (default: 360 / 6 hours)

Size the interval so a full reconciliation finishes well before the next one starts, otherwise runs queue up behind each other. Throughput depends on your Zabbix server, the number of interfaces and templates per host, and network latency, so measure it on your own installation: the job logs `duration_seconds` and the number of hosts enqueued on every run.

#### templates

Expand Down Expand Up @@ -270,6 +332,43 @@ These tags allow you to navigate from a Zabbix host back to the corresponding N
### custom_field_hostname and custom_field_display_name
You can use these fields to map the connection between NetBox and the Zabbix hostname and display name. The device name is used as the default.

### exclude_tag

When set to a non-empty string (e.g. `'do_not_monitor'`), any `ZabbixTagAssignment` with a tag matching this name — whether assigned directly on a Device/VM or inherited from a Role, Platform, Site, SiteGroup, Region, Manufacturer, or Configuration Group — causes the host to be excluded from Zabbix sync entirely. No Zabbix host is created, and an already synced host is removed from Zabbix. Exclusion is an explicit operator decision, so — like a `statusmapping` entry that maps to `deleted` — it always deletes and is not affected by `allow_inherited_deletion` (see below).

This is useful for excluding device classes that should never be monitored (e.g. desktop PCs, VDI sessions, test lab devices) without removing their Site or Platform assignments.

The tag itself is never pushed to Zabbix — it is only used as a signal during sync resolution and is filtered out before Jinja2 rendering.

Defaults to `''` (empty string = feature disabled).

### allow_inherited_deletion

Controls whether losing every `ZabbixServerAssignment` can delete an existing Zabbix host — for example because a Site was moved into another SiteGroup. Such a deletion can be caused by an edit far away from the device, and deleting a Zabbix host discards its measurement history.

While disabled (the default), nbxsync keeps those hosts and logs each one it would have deleted, with the reason and the Zabbix host ID:

```
Not deleting Zabbix host for switch-01 on Zabbix EU (hostid 10842): no remaining Zabbix server assignment requires
deletion, but allow_inherited_deletion is disabled. Enable it to let nbxsync remove the host and its history.
```

Review those log lines after restructuring the site hierarchy, then set the setting to `True` to let nbxsync reconcile. Explicit deletions are unaffected: a `statusmapping` entry that maps to `deleted`, an `exclude_tag` match, and deleting the Device/VM in NetBox always remove the Zabbix host — including when `sync_enabled` is False (inventory deletion is retirement, not a background sync).

Defaults to `False`.

### adopt_existing_hosts

Controls whether nbxsync may bind to a Zabbix host it did not create. During sync, a host whose technical name matches and that carries the managed identity tags (`nb_type`/`nb_id`) can either be adopted or reported as a conflict.

Adoption requires `attach_objtag=True`: without those identity tags on the Zabbix host, adoption cannot safely prove the host belongs to this NetBox object.

Adoption makes NetBox authoritative over that host immediately: its interfaces, templates, macros, tags and inventory are overwritten on the next sync. While disabled (the default), the sync fails with an actionable message naming the host and the setting, and nothing in Zabbix is changed.

Enable it for a controlled migration of hosts that were provisioned by an earlier tool, then turn it off again.

Defaults to `False`.

## Enabling and Disabling Synchronization

Two separate `sync_enabled` flags control whether synchronization to Zabbix is active.
Expand Down
Loading