diff --git a/nbxsync/utils/sync/hostsync.py b/nbxsync/utils/sync/hostsync.py index b9efbdfe..2e307d7a 100644 --- a/nbxsync/utils/sync/hostsync.py +++ b/nbxsync/utils/sync/hostsync.py @@ -553,6 +553,29 @@ def check_default_hostinterface(self): continue desired_hostinterfaces.append(params) + # host.update() treats 'interfaces' as the complete, authoritative list: any + # interface on the host that is missing from it gets DELETED, and an interface + # that still carries items cannot be deleted - Zabbix then rejects the whole + # call with 'Invalid params. Interface is linked to item "..." on "..."'. + # Carry interfaces unknown to NetBox along untouched; pruning stale ones is + # verify_hostinterfaces()'s job, not this one. + known_interfaceids = {str(int(params['interfaceid'])) for params in desired_hostinterfaces} + netbox_default_types = {int(params['type']) for params in desired_hostinterfaces if int(params.get('main', 0)) == 1} + + for zabbix_hostinterface in zabbix_hostinterfaces: + if str(int(zabbix_hostinterface['interfaceid'])) in known_interfaceids: + continue + + carried = {key: zabbix_hostinterface[key] for key in ('interfaceid', 'type', 'ip', 'dns', 'port', 'useip') if key in zabbix_hostinterface} + if zabbix_hostinterface.get('details'): + carried['details'] = zabbix_hostinterface['details'] + + # Only one interface per type may be main. Where NetBox supplies the + # default for a type, every other interface of that type has to yield; + # types NetBox knows nothing about keep whatever Zabbix already had. + carried['main'] = 0 if int(zabbix_hostinterface['type']) in netbox_default_types else int(zabbix_hostinterface.get('main', 0)) + desired_hostinterfaces.append(carried) + self.api.host.update(hostid=hostid, interfaces=desired_hostinterfaces) return