Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
0b47afa
custom hostname and displayname for zabbix
rds-hinz Apr 30, 2026
5208a1c
Update installation.md
bhinz Apr 30, 2026
f25e15d
custom_fields added
bhinz Apr 30, 2026
de62bf9
Merge branch 'OpensourceICTSolutions:main' into main
bhinz May 4, 2026
d5dcb58
Update pydantic dependency version constraints
qwerin Jun 1, 2026
29c9ec7
Add optional trigger dependency synchronization
Jun 24, 2026
c1826b0
Merge pull request #105 from OpensourceICTSolutions/main
bvbaekel Jun 24, 2026
8894b57
Update docs to include the changelog for 1.0.4
bvbaekel Jun 21, 2026
ced03a9
Fixed issue where syncing to multiple Zabbix Servers failed ([#90])
bvbaekel Jun 21, 2026
59b77f9
ixed issue where local_address was cleared, even when the proxy is pa…
bvbaekel Jun 21, 2026
0b2865e
prep
bvbaekel Jun 24, 2026
e752a17
Trigger fix
bvbaekel Jun 24, 2026
e6227fc
Merge pull request #106 from OpensourceICTSolutions/test
bvbaekel Jun 24, 2026
82af117
Merge pull request #99 from qwerin/patch-1
bvbaekel Jun 24, 2026
148c8dc
Fix test
bvbaekel Jun 28, 2026
3543ffe
Fix missing zabbixserver attribute + invalid day parameter for non-MO…
bvbaekel Jun 28, 2026
e9f3458
Merge pull request #87 from bhinz/main
bvbaekel Jul 7, 2026
4f56004
Fix typo in SyncMaintenceJob
bvbaekel Jul 8, 2026
da7c122
Fix issue where only 1 ZabbixServer would be synced
bvbaekel Jul 8, 2026
3569115
Fix validation error on Zabbix maintenance object assignment
bvbaekel Jul 8, 2026
4e8e929
Ruff cleanup
bvbaekel Jul 8, 2026
9d7816d
Fix path label for configuration group
bvbaekel Jul 8, 2026
249a99f
Fixed hostinfo details
bvbaekel Jul 8, 2026
0fc4b3a
Clean feature PR scope
Jul 8, 2026
a9f05d8
Replaced gettext with gettext_lazy
bvbaekel Jul 8, 2026
0c5555e
Removed duplicate ordering on model
bvbaekel Jul 8, 2026
b240b37
Removed duplicate imports
bvbaekel Jul 8, 2026
f425a3f
Removed dead file
bvbaekel Jul 8, 2026
b82e4ed
Fix typos in Zabbix Host Interface
bvbaekel Jul 8, 2026
6bc0fe1
Fix typo
bvbaekel Jul 8, 2026
d241148
Fix typo and cleanup code
bvbaekel Jul 8, 2026
fbe992e
Fix constants import; fix typo; fix proxy ip validation
bvbaekel Jul 8, 2026
df29dfa
Address trigger dependency review feedback
Jul 10, 2026
0494d3c
Merge branch 'development' into trigger-dependency-sync
bvbaekel Aug 10, 2026
17063d1
Merge pull request #100 from benjofalanga/trigger-dependency-sync
bvbaekel Aug 10, 2026
b33ae50
Fix test
bvbaekel Aug 10, 2026
d07b6e5
Cleanup tests
bvbaekel Aug 10, 2026
e437ad3
Remove dead code
bvbaekel Aug 10, 2026
aa62a44
Fix code and tests to handle multi-server
bvbaekel Aug 10, 2026
7c0b534
(1) Reject role tokens that are only a whitespace; (2) duplicate trig…
bvbaekel Aug 10, 2026
3c194d8
Add changelog
bvbaekel Aug 10, 2026
cdc0c06
Update readme
bvbaekel Aug 10, 2026
d42c344
Ruff cleanup
bvbaekel Aug 10, 2026
b34a8f1
Add AI Policy
bvbaekel Aug 10, 2026
ebb15f8
Update query counts file
bvbaekel Aug 11, 2026
0599e96
Pin CI to specific NB version and not main
bvbaekel Aug 11, 2026
0cffa18
Fix yaml
bvbaekel Aug 11, 2026
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: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
uses: actions/checkout@v5
with:
repository: "netbox-community/netbox"
ref: "main"
ref: "v4.6.7"
path: "netbox"

- name: Check out repo
Expand Down
33 changes: 33 additions & 0 deletions AI_POLICY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# nbxSync - AI Policy

We support using AI (i.e., LLMs) as tools when contributing to nbxSync. However, you are responsible for any contributions you submit, and we are responsible for any contributions we merge and release. We hold a high bar for all contributions to nbxSync.

Our maintainers dedicate their time and expertise to reviewing contributions. Submitting AI-generated content that you have not personally reviewed and understood wastes that time and will not be accepted.

## Autonomous agents

**We do not allow autonomous agents to be used for contributing to our projects.** We will close any pull requests or issues that we believe were created autonomously, and may mark automated comments as spam. This includes contributions that bypass the provided issue or pull request templates.

## Communication on issues, pull requests, and code reviews

We don't mind if you use AI tools to help you write. However, do not have tools post unreviewed content on your behalf. Keep responses to the minimum needed to communicate your intent. We may hide any comments that we believe are unreviewed AI output.

If you are opening a pull request, we expect you to be able to explain the proposed changes in your own words. This includes the pull request description and responses to questions. If you use AI to help generate the pull request summary, you must review it for technical accuracy.

**Do not use AI to generate answers to questions from maintainers.** You should understand and be able to explain your own work. Using AI to improve grammar or clarity is fine, but the substance of your responses must be your own.

If you wish to include context from an interaction with AI in your comments, it must be in a quote block (e.g., using `>`) and disclosed as such. It must be accompanied by your own commentary explaining the relevance and implications of the context. Do not share long snippets.

## Non-native English speakers

We understand that AI is useful when communicating as a non-native English speaker. Using AI to improve the grammar or clarity of text you have written yourself is fine. If you are using AI to translate your comments, please ensure the translation accurately reflects your intent. Including your original text in a details block shows the effort behind your contribution, helps maintainers verify the translation if needed, and keeps the conversation readable.

## Code and documentation contributions

AI can be a helpful tool for writing code and documentation. However, due to the foundational open source nature of our projects, we require a human in the loop who understands the work produced by AI.

All contributions must be reviewed and understood by the contributor before submission. You should be able to explain every change in a pull request you submit. Pull requests that appear to be unreviewed AI output will be closed without review.

## Enforcement

Contributions that do not follow this policy will be closed. Repeated violations may result in being blocked from contributing to nbxSync. If you believe your contribution was closed in error, you are welcome to reach out to a maintainer to discuss.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ This plugin bridges the gap between network/source-of-truth documentation and in

| Release | Minimum NetBox Version | Maximum NetBox Version |
| ------- | ---------------------- | ---------------------- |
| 1.0.5 | 4.2.6 | 4.6.x |
| 1.0.4 | 4.2.0 | 4.5.x |
| 1.0.3 | 4.2.0 | 4.5.x |
| 1.0.2 | 4.2.0 | 4.5.x |
| 1.0.1 | 4.2.0 | 4.4.x |
Expand Down
56 changes: 55 additions & 1 deletion docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,48 @@ None

None

## [1.0.4] - Minor update

- Updated the documentation

### New features

- Updated the Zabbix Template Assignment and Zabbix Tag Assignment forms so no duplicate templates/tags can't be assigned ([#78])
- Zabbix Macro's now support Jinja2 templated values ([#83])

### Bug fixes

- Fixed issue with internationalization of field set names on forms ([#39])
- Fixed typo in last_sync_message ([#77])
- Fixed issue with API Schema not being able to generated ([#79])
- Manual device sync fails for templated Zabbix hostgroups when the rendered local hostgroup does not already exist ([#81])
- Ensure that the worker doesn't crash on certain race conditions with regards to the hostinterfacesync job ([#86])
- Fix issue with DeleteHost so it now actually removed the device/object from Zabbix when its deleted from NetBox ([#88])

## [1.0.5] - Minor update

### New features

- Allow configuring a custom hostname and displayname for Zabbix, thanks @bhinz ([#87])
- Implemented 'Trigger dependency sync', thanks to @benjofalanga ([#100])

### Bug fixes

- Fixed issue where syncing to multiple Zabbix Servers failed ([#90])
- Fixed issue where local_address was cleared, even when the proxy is part of a ProxyGroup ([#91])
- Removed duplicate line in ProxySync ([#91])
- Fixed typo (`acept` vs `accept`) in ProxySync ([#91])
- Two bugs in syncmaintenance: missing zabbixserver attribute + invalid "day" parameter for non-MONTHLY timeperiods ([#107])
- Fixed typo in SyncMaintenceJob
- Fixed issue where only 1 ZabbixServer would be synced
- Fixed the resolution of the pathlabel of a Zabbix Configuration Group
- Fixed issues with HostEvent when multiple ZabbixServers are configured
- Replaced 'gettext' with 'gettext_lazy'


### Breaking changes

- Dropped support for NetBox < 4.2.6 in order to support NetBox 4.6.X ([#98])

[#5]: https://github.com/OpensourceICTSolutions/nbxsync/issues/5
[#20]: https://github.com/OpensourceICTSolutions/nbxsync/issues/20
Expand All @@ -105,4 +147,16 @@ None
[#66]: https://github.com/OpensourceICTSolutions/nbxsync/issues/66
[#68]: https://github.com/OpensourceICTSolutions/nbxsync/issues/68
[#71]: https://github.com/OpensourceICTSolutions/nbxsync/issues/71
[#74]: https://github.com/OpensourceICTSolutions/nbxsync/issues/74
[#74]: https://github.com/OpensourceICTSolutions/nbxsync/issues/74
[#77]: https://github.com/OpensourceICTSolutions/nbxsync/issues/77
[#78]: https://github.com/OpensourceICTSolutions/nbxsync/issues/78
[#79]: https://github.com/OpensourceICTSolutions/nbxsync/issues/79
[#81]: https://github.com/OpensourceICTSolutions/nbxsync/issues/81
[#86]: https://github.com/OpensourceICTSolutions/nbxsync/issues/86
[#87]: https://github.com/OpensourceICTSolutions/nbxsync/issues/87
[#88]: https://github.com/OpensourceICTSolutions/nbxsync/issues/88
[#90]: https://github.com/OpensourceICTSolutions/nbxsync/issues/90
[#91]: https://github.com/OpensourceICTSolutions/nbxsync/issues/91
[#98]: https://github.com/OpensourceICTSolutions/nbxsync/issues/98
[#100]: https://github.com/OpensourceICTSolutions/nbxsync/issues/100
[#107]: https://github.com/OpensourceICTSolutions/nbxsync/issues/107
66 changes: 64 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,38 @@ The plugin is configuration to do exactly what you want, by means of the plugin
'interval': 15, # 15 minutes
},
},
'trigger_dependencies': {
'enabled': False,
'levels': [
{
'name': 'access_point',
'roles': ['access point', 'access-point', 'ap'],
'trigger_description': 'AP status',
},
{
'name': 'switch',
'roles': ['switch', 'sw'],
'trigger_description': 'Switch status',
},
{
'name': 'gateway',
'roles': [
'gateway',
'gw',
'firewall',
'router',
],
'trigger_description': 'Gateway status',
},
],
},
'no_alerting_tag': 'NO_ALERTING',
'no_alerting_tag_value': '1',
'attach_objtag': True,
'objtag_type': 'nb_type',
'objtag_id': 'nb_id'
'objtag_id': 'nb_id',
'custom_field_hostname':'',
'custom_field_display_name':''
}
```

Expand Down Expand Up @@ -165,6 +192,38 @@ This runs as the `Zabbix Sync Maintenance job` system job. Only maintenance
windows that have at least one period and one object assignment are included.
See [Zabbix Maintenance](zabbixmaintenance.md) for details.

### trigger_dependencies

When enabled, nbxSync updates Zabbix trigger dependencies after a successful device host sync. The feature uses NetBox cabling and ordered dependency levels to build dependency chains such as:

```text
access point trigger -> switch trigger -> gateway/firewall trigger
```

This feature is disabled by default. Enable it only when the configured role tokens match your NetBox device role names or slugs and the configured trigger descriptions match your Zabbix trigger names.

Both pieces are required:

- Role matching decides which dependency level a NetBox device belongs to. Role names and slugs are compared case-insensitively.
- Interface cabling decides which directly connected devices are considered.
- The order of `levels` decides dependency direction. Lower levels depend on directly connected higher levels.

For example, an access point role named `Wireless AP` will not match the defaults unless you add `wireless ap` or the role slug to the access point level's `roles`. A device with a matching role but no connected higher-level neighbor is skipped because nbxSync cannot determine its upstream dependency.

| Key | Default | Description |
|------------|---------|-------------|
| `enabled` | `False` | Enable trigger dependency updates after host sync |
| `levels` | AP, switch, gateway/firewall | Ordered from lowest child to highest parent |
| `name` | Level-specific | Human-readable level name used for configuration clarity |
| `roles` | Level-specific role tokens | NetBox device role names/slugs that belong to this level |
| `trigger_description` | Level-specific trigger name | Zabbix trigger description on hosts in this level |

The default levels are ordered as access point, switch, gateway/firewall. With those defaults, a connected access point depends on its connected switch, and a connected switch depends on its connected gateway or firewall. Cable direction does not matter; nbxSync looks at directly connected devices and uses the level order to decide which device is the child and which device is the parent.

To support more device types or vendor-specific role names, add their NetBox role names or slugs to the appropriate level. To support a different hierarchy, add or reorder levels from lowest child to highest parent.

Existing Zabbix dependencies whose descriptions do not match the managed parent trigger descriptions are preserved. Dependencies matching the managed parent trigger descriptions are replaced with the current cabling-derived parent triggers.

### no_alerting_tag

This defines the tag to be set when a host has the 'enabled_no_alerting' status. Use just a string value with no ${ } around the tag. Defaults to 'NO_ALERTING'.
Expand Down Expand Up @@ -208,6 +267,9 @@ These tags allow you to navigate from a Zabbix host back to the corresponding N
| `objtag_type` | `nb_type` | Tag name for the NetBox object type |
| `objtag_id` | `nb_id` | Tag name for the NetBox object ID |

### 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.

## Enabling and Disabling Synchronization

Two separate `sync_enabled` flags control whether synchronization to Zabbix is active.
Expand All @@ -216,4 +278,4 @@ Two separate `sync_enabled` flags control whether synchronization to Zabbix is a

**On `ZabbixServerAssignment`**: disabling this stops synchronization for that specific device/VM assignment only. Other assignments to the same or different Zabbix servers are unaffected.

Both flags must be `True` for a sync to proceed. The "Sync Status" column on the Zabbix Server Assignments list shows a green check only when both the assignment and its server are enabled.
Both flags must be `True` for a sync to proceed. The "Sync Status" column on the Zabbix Server Assignments list shows a green check only when both the assignment and its server are enabled.
12 changes: 7 additions & 5 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ If you want to change the default configuration, can add the following configura
```python title="netbox/configuration.py"
PLUGINS = ['nbxsync']
PLUGINS_CONFIG = {
"nbxsync": {
'nbxsync': {
'sot': {
'proxygroup': 'netbox',
'proxy': 'netbox',
Expand Down Expand Up @@ -89,19 +89,19 @@ PLUGINS_CONFIG = {
'backgroundsync': {
'objects': {
'enabled': True,
'interval': 60, # 1 hour
'interval': 60, # 1 hour
},
'templates': {
'enabled': True,
'interval': 1440, # 24 hours
'interval': 1440, # 24 hours
},
'proxies': {
'enabled': True,
'interval': 1440, # 24 hours
'interval': 1440, # 24 hours
},
'maintenance': {
'enabled': True,
'interval': 15, # 15 minutes
'interval': 15, # 15 minutes
},
},
'no_alerting_tag': 'NO_ALERTING',
Expand All @@ -110,6 +110,8 @@ PLUGINS_CONFIG = {
'attach_objtag': True,
'objtag_type': 'nb_type',
'objtag_id': 'nb_id',
'custom_field_hostname': '',
'custom_field_display_name': '',
}
}
```
Expand Down
12 changes: 6 additions & 6 deletions docs/zabbixconfigurationgroup.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Think of it as a "profile": you attach Zabbix servers, templates, tags, host gro

```python
class ZabbixConfigurationGroup(NetBoxModel):
name = CharField(max_length=512)
name = CharField(max_length=512)
description = CharField(max_length=1024, blank=True)
```

Expand Down Expand Up @@ -42,11 +42,11 @@ The important distinction: this is **not** about Zabbix config per se — it is

The existing nbxsync assignment models (`ZabbixServerAssignment`, `ZabbixTemplateAssignment`, `ZabbixTagAssignment`, `ZabbixHostgroupAssignment`, `ZabbixMacroAssignment`, `ZabbixHostInterface`) all have two distinct modes of operation:

| Mode | `assigned_object` points to | `zabbixconfigurationgroup` field |
|---|---|---|
| **Direct assignment** | A Device / VM / VDC | `NULL` |
| **Group-level definition** | A `ZabbixConfigurationGroup` | `NULL` |
| **Group-cloned copy** | A Device / VM / VDC | FK to the originating group |
| Mode | `assigned_object` points to | `zabbixconfigurationgroup` field |
| -------------------------- | ---------------------------- | -------------------------------- |
| **Direct assignment** | A Device / VM / VDC | `NULL` |
| **Group-level definition** | A `ZabbixConfigurationGroup` | `NULL` |
| **Group-cloned copy** | A Device / VM / VDC | FK to the originating group |

The `zabbixconfigurationgroup` FK on each assignment model is the "provenance" marker: a non-null value means this record was **created by the group propagation system**, not by a human directly. This matters for the "don't overwrite manual assignments" logic (described below).

Expand Down
29 changes: 28 additions & 1 deletion nbxsync/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class nbxSync(PluginConfig):
author = name
author_email = email
base_url = 'nbxsync'
min_version = '4.2.4'
min_version = '4.2.6'
required_settings = []
default_settings = {
'sot': {
Expand Down Expand Up @@ -111,12 +111,39 @@ class nbxSync(PluginConfig):
'interval': 15, # 15 minutes
},
},
'trigger_dependencies': {
'enabled': False,
'levels': [
{
'name': 'access_point',
'roles': ['access point', 'access-point', 'ap'],
'trigger_description': 'AP status',
},
{
'name': 'switch',
'roles': ['switch', 'sw'],
'trigger_description': 'Switch status',
},
{
'name': 'gateway',
'roles': [
'gateway',
'gw',
'firewall',
'router',
],
'trigger_description': 'Gateway status',
},
],
},
'no_alerting_tag': 'NO_ALERTING',
'no_alerting_tag_value': '1',
'maintenance_window_duration': 3600,
'attach_objtag': False,
'objtag_type': 'nb_type',
'objtag_id': 'nb_id',
'custom_field_hostname': '',
'custom_field_display_name': '',
}
queues = []
validated_config = None
Expand Down
2 changes: 1 addition & 1 deletion nbxsync/api/views/zabbixsync.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from django.shortcuts import get_object_or_404
from drf_spectacular.utils import extend_schema

from nbxsync.constants import OBJECT_TYPE_MODEL_MAP
from nbxsync.constants.assignment_type_to_field import OBJECT_TYPE_MODEL_MAP


class ZabbixSyncViewSet(ViewSet):
Expand Down
14 changes: 8 additions & 6 deletions nbxsync/constants/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from .assignment_models import *
from .assignment_type_to_field import *
from .inheritance_source_colors import *
from .path_labels import *
from .itemtype import *
from .add_hostinterface_button import *
# from .assignment_models import *
# from .assignment_type_to_field import *

from .template_pattern import * # noqa: F401,F403
from .inheritance_source_colors import * # noqa: F401,F403
from .path_labels import * # noqa: F401,F403
from .itemtype import * # noqa: F401,F403
from .add_hostinterface_button import * # noqa: F401,F403
1 change: 0 additions & 1 deletion nbxsync/constants/assignment_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,5 @@
DEVICE_OR_VM_ASSIGNMENT_MODELS = Q(Q(app_label='dcim', model='device') | Q(app_label='dcim', model='virtualdevicecontext') | Q(app_label='virtualization', model='virtualmachine'))
MACRO_ASSIGNMENT_MODELS = Q(Q(app_label='nbxsync', model='zabbixserver') | Q(app_label='nbxsync', model='zabbixtemplate'))
MAINTENANCE_ASSIGNMENT_OBJECTS = Q(Q(Q(app_label='nbxsync', model='zabbixhostgroup')) | DEVICE_OR_VM_ASSIGNMENT_MODELS)
MAINTENANCE_ASSIGNMENT_TAGS = Q(app_label='nbxsync', model='zabbixtag')

CONFIGGROUP_OBJECTS = Q(app_label='nbxsync', model='zabbixconfigurationgroup')
2 changes: 1 addition & 1 deletion nbxsync/constants/path_labels.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH_LABELS = {
('device_type',): 'Device Type',
('device_type', 'manufacturer'): 'Manufacturer',
('zabbixconfigurationgroup'): 'Zabbix Configuration Group',
('zabbixconfigurationgroup',): 'Zabbix Configuration Group',
('platform',): 'Platform',
('role',): 'Role',
('cluster',): 'Cluster',
Expand Down
3 changes: 3 additions & 0 deletions nbxsync/constants/template_pattern.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import re

TEMPLATE_PATTERN = re.compile(r'({{.*?}}|{%-?\s*.*?\s*-?%}|{#.*?#})')
Loading