mirror of
https://github.com/TheNetworkGuy/netbox-zabbix-sync.git
synced 2025-07-14 01:41:25 -06:00
Fixed hostgroup generation issues, added proxygroup support.
This commit is contained in:
parent
6f044cb228
commit
d1e864c75b
@ -5,8 +5,7 @@ Device specific handeling for Netbox to Zabbix
|
||||
"""
|
||||
from os import sys
|
||||
from logging import getLogger
|
||||
from pyzabbix import ZabbixAPIException
|
||||
from packaging import version
|
||||
from zabbix_utils import APIRequestError
|
||||
from modules.exceptions import (SyncInventoryError, TemplateError, SyncExternalError,
|
||||
InterfaceConfigError, JournalError)
|
||||
from modules.interface import ZabbixInterface
|
||||
@ -314,10 +313,7 @@ class NetworkDevice():
|
||||
e = f"Found group {group['name']} for host {self.name}."
|
||||
self.logger.debug(e)
|
||||
return True
|
||||
e = (f"Unable to find group '{self.hostgroup}' "
|
||||
f"for host {self.name} in Zabbix.")
|
||||
self.logger.warning(e)
|
||||
raise SyncInventoryError(e)
|
||||
return False
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
@ -332,7 +328,7 @@ class NetworkDevice():
|
||||
e = f"Deleted host {self.name} from Zabbix."
|
||||
self.logger.info(e)
|
||||
self.create_journal_entry("warning", "Deleted host from Zabbix")
|
||||
except ZabbixAPIException as e:
|
||||
except APIRequestError as e:
|
||||
e = f"Zabbix returned the following error: {str(e)}."
|
||||
self.logger.error(e)
|
||||
raise SyncExternalError(e) from e
|
||||
@ -371,23 +367,6 @@ class NetworkDevice():
|
||||
self.logger.warning(e)
|
||||
raise SyncInventoryError(e) from e
|
||||
|
||||
# def setProxy(self, proxy_list):
|
||||
# """ check if Zabbix Proxy has been defined in config context """
|
||||
# if "zabbix" in self.nb.config_context:
|
||||
# if "proxy" in self.nb.config_context["zabbix"]:
|
||||
# proxy = self.nb.config_context["zabbix"]["proxy"]
|
||||
# # Try matching proxy
|
||||
# for px in proxy_list:
|
||||
# if px["name"] == proxy:
|
||||
# self.zbxproxy = px["proxyid"]
|
||||
# self.logger.debug(f"Found proxy {proxy}"
|
||||
# f" for {self.name}.")
|
||||
# return True
|
||||
# e = f"{self.name}: Defined proxy {proxy} not found."
|
||||
# self.logger.warning(e)
|
||||
# return False
|
||||
return True
|
||||
|
||||
def setProxy(self, proxy_list):
|
||||
"""
|
||||
Sets proxy or proxy group if this
|
||||
@ -400,7 +379,12 @@ class NetworkDevice():
|
||||
return False
|
||||
# Proxy group takes priority over a proxy due
|
||||
# to it being HA and therefore being more reliable
|
||||
for proxy_type in ('proxy_group', 'proxy'):
|
||||
# Includes proxy group fix since Zabbix <= 6 should ignore this
|
||||
proxy_types = ["proxy"]
|
||||
if str(self.zabbix.version).startswith('7'):
|
||||
# Only insert groups in front of list for Zabbix7
|
||||
proxy_types.insert(0, "proxy_group")
|
||||
for proxy_type in proxy_types:
|
||||
# Check if the key exists in Netbox CC
|
||||
if proxy_type in self.nb.config_context["zabbix"]:
|
||||
proxy_name = self.nb.config_context["zabbix"][proxy_type]
|
||||
@ -413,6 +397,9 @@ class NetworkDevice():
|
||||
if proxy["name"] == proxy_name:
|
||||
self.zbxproxy = proxy
|
||||
return True
|
||||
else:
|
||||
self.logger.warning(f"Device {self.name}: unable to find proxy {proxy_name}")
|
||||
break
|
||||
return False
|
||||
|
||||
def createInZabbix(self, groups, templates, proxies,
|
||||
@ -424,7 +411,10 @@ class NetworkDevice():
|
||||
if not self._zabbixHostnameExists():
|
||||
# Get group and template ID's for host
|
||||
if not self.getZabbixGroup(groups):
|
||||
raise SyncInventoryError()
|
||||
e = (f"Unable to find group '{self.hostgroup}' "
|
||||
f"for host {self.name} in Zabbix.")
|
||||
self.logger.warning(e)
|
||||
raise SyncInventoryError(e)
|
||||
self.zbxTemplatePrepper(templates)
|
||||
templateids = []
|
||||
for template in self.zbx_templates:
|
||||
@ -449,7 +439,7 @@ class NetworkDevice():
|
||||
if self.zbxproxy:
|
||||
# If a lower version than 7 is used, we can assume that
|
||||
# the proxy is a normal proxy and not a proxy group
|
||||
if version.parse(self.zabbix.version) < version.parse("7.0.0"):
|
||||
if not str(self.zabbix.version).startswith('7'):
|
||||
create_data["proxy_hostid"] = self.zbxproxy["id"]
|
||||
else:
|
||||
# Configure either a proxy or proxy group
|
||||
@ -459,7 +449,7 @@ class NetworkDevice():
|
||||
try:
|
||||
host = self.zabbix.host.create(**create_data)
|
||||
self.zabbix_id = host["hostids"][0]
|
||||
except ZabbixAPIException as e:
|
||||
except APIRequestError as e:
|
||||
e = f"Couldn't add {self.name}, Zabbix returned {str(e)}."
|
||||
self.logger.error(e)
|
||||
raise SyncExternalError(e) from e
|
||||
@ -483,7 +473,7 @@ class NetworkDevice():
|
||||
self.logger.info(e)
|
||||
data = {'groupid': groupid["groupids"][0], 'name': self.hostgroup}
|
||||
return data
|
||||
except ZabbixAPIException as e:
|
||||
except APIRequestError as e:
|
||||
e = f"Couldn't add hostgroup, Zabbix returned {str(e)}."
|
||||
self.logger.error(e)
|
||||
raise SyncExternalError(e) from e
|
||||
@ -495,19 +485,30 @@ class NetworkDevice():
|
||||
"""
|
||||
try:
|
||||
self.zabbix.host.update(hostid=self.zabbix_id, **kwargs)
|
||||
except ZabbixAPIException as e:
|
||||
except APIRequestError as e:
|
||||
e = f"Zabbix returned the following error: {str(e)}."
|
||||
self.logger.error(e)
|
||||
raise SyncExternalError(e) from e
|
||||
raise SyncExternalError(e) from None
|
||||
self.logger.info(f"Updated host {self.name} with data {kwargs}.")
|
||||
self.create_journal_entry("info", "Updated host in Zabbix with latest NB data.")
|
||||
|
||||
def ConsistencyCheck(self, groups, templates, proxies, proxy_power):
|
||||
def ConsistencyCheck(self, groups, templates, proxies, proxy_power, create_hostgroups):
|
||||
# pylint: disable=too-many-branches, too-many-statements
|
||||
"""
|
||||
Checks if Zabbix object is still valid with Netbox parameters.
|
||||
"""
|
||||
self.getZabbixGroup(groups)
|
||||
# Check if the hostgroup exists.
|
||||
# If not, create the hostgroup and try finding the group again
|
||||
if not self.getZabbixGroup(groups):
|
||||
if create_hostgroups:
|
||||
new_group = self.createZabbixHostgroup()
|
||||
groups.append(new_group)
|
||||
self.getZabbixGroup(groups)
|
||||
else:
|
||||
e = (f"Device {self.name}: different hostgroup is required but "
|
||||
"unable to create hostgroup without generation permission.")
|
||||
self.logger.warning(e)
|
||||
raise SyncInventoryError(e)
|
||||
self.zbxTemplatePrepper(templates)
|
||||
self.setProxy(proxies)
|
||||
host = self.zabbix.host.get(filter={'hostid': self.zabbix_id},
|
||||
@ -566,39 +567,56 @@ class NetworkDevice():
|
||||
else:
|
||||
self.logger.warning(f"Device {self.name}: status OUT of sync.")
|
||||
self.updateZabbixHost(status=str(self.zabbix_state))
|
||||
### CHANGE THIS
|
||||
# Check if a proxy has been defined
|
||||
if self.zbxproxy:
|
||||
# Check if expected proxyID matches with configured proxy
|
||||
if (("proxy_hostid" in host and host["proxy_hostid"] == self.zbxproxy) or
|
||||
("proxyid" in host and host["proxyid"] == self.zbxproxy)):
|
||||
# Check if proxy or proxy group is defined
|
||||
if (self.zbxproxy["idtype"] in host and
|
||||
host[self.zbxproxy["idtype"]] == self.zbxproxy["id"]):
|
||||
self.logger.debug(f"Device {self.name}: proxy in-sync.")
|
||||
# Backwards compatibility for Zabbix <= 6
|
||||
elif "proxy_hostid" in host and host["proxy_hostid"] == self.zbxproxy["id"]:
|
||||
self.logger.debug(f"Device {self.name}: proxy in-sync.")
|
||||
# Proxy does not match, update Zabbix
|
||||
else:
|
||||
# Proxy diff, update value
|
||||
self.logger.warning(f"Device {self.name}: proxy OUT of sync.")
|
||||
if version.parse(self.zabbix.api_version()) < version.parse("7.0.0"):
|
||||
self.updateZabbixHost(proxy_hostid=self.zbxproxy)
|
||||
# Zabbix <= 6 patch
|
||||
if not str(self.zabbix.version).startswith('7'):
|
||||
self.updateZabbixHost(proxy_hostid=self.zbxproxy['id'])
|
||||
# Zabbix 7+
|
||||
else:
|
||||
self.updateZabbixHost(proxyid=self.zbxproxy)
|
||||
# Prepare data structure for updating either proxy or group
|
||||
update_data = {self.zbxproxy["idtype"]: self.zbxproxy["id"],
|
||||
"monitored_by": self.zbxproxy['monitored_by']}
|
||||
self.updateZabbixHost(**update_data)
|
||||
else:
|
||||
if (("proxy_hostid" in host and not host["proxy_hostid"] == "0")
|
||||
or ("proxyid" in host and not host["proxyid"] == "0")):
|
||||
if proxy_power:
|
||||
# Variable full_proxy_sync has been enabled
|
||||
# delete the proxy link in Zabbix
|
||||
if version.parse(self.zabbix.api_version()) < version.parse("7.0.0"):
|
||||
self.updateZabbixHost(proxy_hostid=self.zbxproxy)
|
||||
else:
|
||||
self.updateZabbixHost(proxyid=self.zbxproxy)
|
||||
else:
|
||||
# Instead of deleting the proxy config in zabbix and
|
||||
# forcing potential data loss,
|
||||
# an error message is displayed.
|
||||
self.logger.error(f"Device {self.name} is configured "
|
||||
f"with proxy in Zabbix but not in Netbox. The"
|
||||
" -p flag was ommited: no "
|
||||
"changes have been made.")
|
||||
|
||||
# No proxy is defined in Netbox
|
||||
proxy_set = False
|
||||
# Check if a proxy is defined. Uses the proxy_hostid key for backwards compatibility
|
||||
for key in ("proxy_hostid", "proxyid", "proxy_groupid"):
|
||||
if key in host:
|
||||
if bool(int(host[key])):
|
||||
proxy_set = True
|
||||
if proxy_power and proxy_set:
|
||||
# Zabbix <= 6 fix
|
||||
self.logger.warning(f"Device {self.name}: no proxy is configured in Netbox "
|
||||
"but is configured in Zabbix. Removing proxy config in Zabbix")
|
||||
if "proxy_hostid" in host and bool(host["proxy_hostid"]):
|
||||
self.updateZabbixHost(proxy_hostid=0)
|
||||
# Zabbix 7 proxy
|
||||
elif "proxyid" in host and bool(host["proxyid"]):
|
||||
self.updateZabbixHost(proxyid=0, monitored_by=0)
|
||||
# Zabbix 7 proxy group
|
||||
elif "proxy_groupid" in host and bool(host["proxy_groupid"]):
|
||||
self.updateZabbixHost(proxy_groupid=0, monitored_by=0)
|
||||
# Checks if a proxy has been defined in Zabbix and if proxy_power config has been set
|
||||
if proxy_set and not proxy_power:
|
||||
# Display error message
|
||||
self.logger.error(f"Device {self.name} is configured "
|
||||
f"with proxy in Zabbix but not in Netbox. The"
|
||||
" -p flag was ommited: no "
|
||||
"changes have been made.")
|
||||
if not proxy_set:
|
||||
self.logger.debug(f"Device {self.name}: proxy in-sync.")
|
||||
# Check host inventory
|
||||
if inventory_sync:
|
||||
# check inventory mode first, as we need it set to parse
|
||||
@ -665,7 +683,7 @@ class NetworkDevice():
|
||||
e = f"Solved {self.name} interface conflict."
|
||||
self.logger.info(e)
|
||||
self.create_journal_entry("info", e)
|
||||
except ZabbixAPIException as e:
|
||||
except APIRequestError as e:
|
||||
e = f"Zabbix returned the following error: {str(e)}."
|
||||
self.logger.error(e)
|
||||
raise SyncExternalError(e) from e
|
||||
|
@ -5,10 +5,8 @@
|
||||
import logging
|
||||
import argparse
|
||||
from os import environ, path, sys
|
||||
from packaging import version
|
||||
from pynetbox import api
|
||||
#from pyzabbix import ZabbixAPI, ZabbixAPIException
|
||||
from zabbix_utils import ZabbixAPI, APIRequestError, ProcessingError
|
||||
from zabbix_utils import ZabbixAPI, APIRequestError
|
||||
from modules.device import NetworkDevice
|
||||
from modules.tools import convert_recordset, proxy_prepper
|
||||
from modules.exceptions import EnvironmentVarError, HostgroupError, SyncError
|
||||
@ -92,7 +90,7 @@ def main(arguments):
|
||||
raise HostgroupError(e)
|
||||
# Set Zabbix API
|
||||
try:
|
||||
zabbix = ZabbixAPI(zabbix_host)
|
||||
zabbix = ZabbixAPI(zabbix_host, password=zabbix_pass)
|
||||
if "ZABBIX_TOKEN" in env_vars:
|
||||
zabbix.login(token=zabbix_token)
|
||||
else:
|
||||
@ -104,7 +102,7 @@ def main(arguments):
|
||||
e = f"Zabbix returned the following error: {str(e)}."
|
||||
logger.error(e)
|
||||
# Set API parameter mapping based on API version
|
||||
if version.parse(zabbix.version) < version.parse("7.0.0"):
|
||||
if not str(zabbix.version).startswith('7'):
|
||||
proxy_name = "host"
|
||||
else:
|
||||
proxy_name = "name"
|
||||
@ -116,7 +114,10 @@ def main(arguments):
|
||||
zabbix_groups = zabbix.hostgroup.get(output=['groupid', 'name'])
|
||||
zabbix_templates = zabbix.template.get(output=['templateid', 'name'])
|
||||
zabbix_proxies = zabbix.proxy.get(output=['proxyid', proxy_name])
|
||||
zabbix_proxygroups = zabbix.proxygroup.get(output=["proxy_groupid", "name"])
|
||||
# Set empty list for proxy processing Zabbix <= 6
|
||||
zabbix_proxygroups = []
|
||||
if str(zabbix.version).startswith('7'):
|
||||
zabbix_proxygroups = zabbix.proxygroup.get(output=["proxy_groupid", "name"])
|
||||
# Sanitize proxy data
|
||||
if proxy_name == "host":
|
||||
for proxy in zabbix_proxies:
|
||||
@ -170,7 +171,8 @@ def main(arguments):
|
||||
# Check if device is already in Zabbix
|
||||
if device.zabbix_id:
|
||||
device.ConsistencyCheck(zabbix_groups, zabbix_templates,
|
||||
zabbix_proxy_list, full_proxy_sync)
|
||||
zabbix_proxy_list, full_proxy_sync,
|
||||
create_hostgroups)
|
||||
continue
|
||||
# Add hostgroup is config is set
|
||||
# and Hostgroup is not present in Zabbix
|
||||
|
Loading…
Reference in New Issue
Block a user