mirror of
https://github.com/TheNetworkGuy/netbox-zabbix-sync.git
synced 2025-12-18 19:32:22 -06:00
🎨 Formatted codebase
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
"""
|
||||
Module for parsing configuration from the top level config.py file
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
from importlib import util
|
||||
from os import environ, path
|
||||
from logging import getLogger
|
||||
from os import environ, path
|
||||
from pathlib import Path
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
@@ -44,40 +45,40 @@ DEFAULT_CONFIG = {
|
||||
"serial": "serialno_a",
|
||||
"device_type/model": "type",
|
||||
"device_type/manufacturer/name": "vendor",
|
||||
"oob_ip/address": "oob_ip"
|
||||
"oob_ip/address": "oob_ip",
|
||||
},
|
||||
"vm_inventory_map": {
|
||||
"status/label": "deployment_status",
|
||||
"comments": "notes",
|
||||
"name": "name"
|
||||
"name": "name",
|
||||
},
|
||||
"usermacro_sync": False,
|
||||
"device_usermacro_map": {
|
||||
"serial": "{$HW_SERIAL}",
|
||||
"role/name": "{$DEV_ROLE}",
|
||||
"url": "{$NB_URL}",
|
||||
"id": "{$NB_ID}"
|
||||
"id": "{$NB_ID}",
|
||||
},
|
||||
"vm_usermacro_map": {
|
||||
"memory": "{$TOTAL_MEMORY}",
|
||||
"role/name": "{$DEV_ROLE}",
|
||||
"url": "{$NB_URL}",
|
||||
"id": "{$NB_ID}"
|
||||
"id": "{$NB_ID}",
|
||||
},
|
||||
"tag_sync": False,
|
||||
"tag_lower": True,
|
||||
"tag_name": 'NetBox',
|
||||
"tag_name": "NetBox",
|
||||
"tag_value": "name",
|
||||
"device_tag_map": {
|
||||
"site/name": "site",
|
||||
"rack/name": "rack",
|
||||
"platform/name": "target"
|
||||
"platform/name": "target",
|
||||
},
|
||||
"vm_tag_map": {
|
||||
"site/name": "site",
|
||||
"cluster/name": "cluster",
|
||||
"platform/name": "target"
|
||||
}
|
||||
"platform/name": "target",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,12 +5,13 @@ Device specific handeling for NetBox to Zabbix
|
||||
|
||||
from copy import deepcopy
|
||||
from logging import getLogger
|
||||
from re import search
|
||||
from operator import itemgetter
|
||||
from re import search
|
||||
|
||||
from zabbix_utils import APIRequestError
|
||||
from pynetbox import RequestError as NetboxRequestError
|
||||
from zabbix_utils import APIRequestError
|
||||
|
||||
from modules.config import load_config
|
||||
from modules.exceptions import (
|
||||
InterfaceConfigError,
|
||||
SyncExternalError,
|
||||
@@ -22,10 +23,10 @@ from modules.interface import ZabbixInterface
|
||||
from modules.tags import ZabbixTags
|
||||
from modules.tools import field_mapper, remove_duplicates, sanatize_log_output
|
||||
from modules.usermacros import ZabbixUsermacros
|
||||
from modules.config import load_config
|
||||
|
||||
config = load_config()
|
||||
|
||||
|
||||
class PhysicalDevice:
|
||||
# pylint: disable=too-many-instance-attributes, too-many-arguments, too-many-positional-arguments
|
||||
"""
|
||||
@@ -125,8 +126,8 @@ class PhysicalDevice:
|
||||
self.nb,
|
||||
self.nb_api_version,
|
||||
logger=self.logger,
|
||||
nested_sitegroup_flag=config['traverse_site_groups'],
|
||||
nested_region_flag=config['traverse_regions'],
|
||||
nested_sitegroup_flag=config["traverse_site_groups"],
|
||||
nested_region_flag=config["traverse_regions"],
|
||||
nb_groups=nb_site_groups,
|
||||
nb_regions=nb_regions,
|
||||
)
|
||||
@@ -177,8 +178,6 @@ class PhysicalDevice:
|
||||
self.logger.warning(e)
|
||||
raise TemplateError(e)
|
||||
|
||||
|
||||
|
||||
def get_templates_context(self):
|
||||
"""Get Zabbix templates from the device context"""
|
||||
if "zabbix" not in self.config_context:
|
||||
@@ -203,9 +202,11 @@ class PhysicalDevice:
|
||||
# Set inventory mode. Default is disabled (see class init function).
|
||||
if config["inventory_mode"] == "disabled":
|
||||
if config["inventory_sync"]:
|
||||
self.logger.error(f"Host {self.name}: Unable to map NetBox inventory to Zabbix. "
|
||||
"Inventory sync is enabled in "
|
||||
"config but inventory mode is disabled.")
|
||||
self.logger.error(
|
||||
f"Host {self.name}: Unable to map NetBox inventory to Zabbix. "
|
||||
"Inventory sync is enabled in "
|
||||
"config but inventory mode is disabled."
|
||||
)
|
||||
return True
|
||||
if config["inventory_mode"] == "manual":
|
||||
self.inventory_mode = 0
|
||||
@@ -403,7 +404,7 @@ class PhysicalDevice:
|
||||
macros = ZabbixUsermacros(
|
||||
self.nb,
|
||||
self._usermacro_map(),
|
||||
config['usermacro_sync'],
|
||||
config["usermacro_sync"],
|
||||
logger=self.logger,
|
||||
host=self.name,
|
||||
)
|
||||
@@ -421,10 +422,10 @@ class PhysicalDevice:
|
||||
tags = ZabbixTags(
|
||||
self.nb,
|
||||
self._tag_map(),
|
||||
config['tag_sync'],
|
||||
config['tag_lower'],
|
||||
tag_name=config['tag_name'],
|
||||
tag_value=config['tag_value'],
|
||||
config["tag_sync"],
|
||||
config["tag_lower"],
|
||||
tag_name=config["tag_name"],
|
||||
tag_value=config["tag_value"],
|
||||
logger=self.logger,
|
||||
host=self.name,
|
||||
)
|
||||
@@ -604,7 +605,9 @@ class PhysicalDevice:
|
||||
)
|
||||
self.logger.error(e)
|
||||
raise SyncExternalError(e) from None
|
||||
self.logger.info(f"Host {self.name}: updated with data {sanatize_log_output(kwargs)}.")
|
||||
self.logger.info(
|
||||
f"Host {self.name}: updated with data {sanatize_log_output(kwargs)}."
|
||||
)
|
||||
self.create_journal_entry("info", "Updated host in Zabbix with latest NB data.")
|
||||
|
||||
def ConsistencyCheck(
|
||||
@@ -615,7 +618,7 @@ class PhysicalDevice:
|
||||
Checks if Zabbix object is still valid with NetBox parameters.
|
||||
"""
|
||||
# If group is found or if the hostgroup is nested
|
||||
if not self.setZabbixGroupID(groups): # or len(self.hostgroups.split("/")) > 1:
|
||||
if not self.setZabbixGroupID(groups): # or len(self.hostgroups.split("/")) > 1:
|
||||
if create_hostgroups:
|
||||
# Script is allowed to create a new hostgroup
|
||||
new_groups = self.createZabbixHostgroup(groups)
|
||||
@@ -632,7 +635,7 @@ class PhysicalDevice:
|
||||
)
|
||||
self.logger.warning(e)
|
||||
raise SyncInventoryError(e)
|
||||
#if self.group_ids:
|
||||
# if self.group_ids:
|
||||
# self.group_ids.append(self.pri_group_id)
|
||||
|
||||
# Prepare templates and proxy config
|
||||
@@ -704,8 +707,9 @@ class PhysicalDevice:
|
||||
if str(self.zabbix.version).startswith(("6", "5")):
|
||||
group_dictname = "groups"
|
||||
# Check if hostgroups match
|
||||
if (sorted(host[group_dictname], key=itemgetter('groupid')) ==
|
||||
sorted(self.group_ids, key=itemgetter('groupid'))):
|
||||
if sorted(host[group_dictname], key=itemgetter("groupid")) == sorted(
|
||||
self.group_ids, key=itemgetter("groupid")
|
||||
):
|
||||
self.logger.debug(f"Host {self.name}: hostgroups in-sync.")
|
||||
else:
|
||||
self.logger.warning(f"Host {self.name}: hostgroups OUT of sync.")
|
||||
@@ -720,8 +724,10 @@ class PhysicalDevice:
|
||||
# Check if a proxy has been defined
|
||||
if self.zbxproxy:
|
||||
# Check if proxy or proxy group is defined
|
||||
if (self.zbxproxy["idtype"] in host and
|
||||
host[self.zbxproxy["idtype"]] == self.zbxproxy["id"]):
|
||||
if (
|
||||
self.zbxproxy["idtype"] in host
|
||||
and host[self.zbxproxy["idtype"]] == self.zbxproxy["id"]
|
||||
):
|
||||
self.logger.debug(f"Host {self.name}: proxy in-sync.")
|
||||
# Backwards compatibility for Zabbix <= 6
|
||||
elif "proxy_hostid" in host and host["proxy_hostid"] == self.zbxproxy["id"]:
|
||||
@@ -788,21 +794,23 @@ class PhysicalDevice:
|
||||
self.updateZabbixHost(inventory=self.inventory)
|
||||
|
||||
# Check host usermacros
|
||||
if config['usermacro_sync']:
|
||||
if config["usermacro_sync"]:
|
||||
# Make a full copy synce we dont want to lose the original value
|
||||
# of secret type macros from Netbox
|
||||
netbox_macros = deepcopy(self.usermacros)
|
||||
# Set the sync bit
|
||||
full_sync_bit = bool(str(config['usermacro_sync']).lower() == "full")
|
||||
full_sync_bit = bool(str(config["usermacro_sync"]).lower() == "full")
|
||||
for macro in netbox_macros:
|
||||
# If the Macro is a secret and full sync is NOT activated
|
||||
if macro["type"] == str(1) and not full_sync_bit:
|
||||
# Remove the value as the Zabbix api does not return the value key
|
||||
# This is required when you want to do a diff between both lists
|
||||
macro.pop("value")
|
||||
|
||||
# Sort all lists
|
||||
def filter_with_macros(macro):
|
||||
return macro["macro"]
|
||||
|
||||
host["macros"].sort(key=filter_with_macros)
|
||||
netbox_macros.sort(key=filter_with_macros)
|
||||
# Check if both lists are the same
|
||||
@@ -814,7 +822,7 @@ class PhysicalDevice:
|
||||
self.updateZabbixHost(macros=self.usermacros)
|
||||
|
||||
# Check host tags
|
||||
if config['tag_sync']:
|
||||
if config["tag_sync"]:
|
||||
if remove_duplicates(host["tags"], sortkey="tag") == self.tags:
|
||||
self.logger.debug(f"Host {self.name}: tags in-sync.")
|
||||
else:
|
||||
@@ -870,8 +878,10 @@ class PhysicalDevice:
|
||||
try:
|
||||
# API call to Zabbix
|
||||
self.zabbix.hostinterface.update(updates)
|
||||
e = (f"Host {self.name}: updated interface "
|
||||
f"with data {sanatize_log_output(updates)}.")
|
||||
e = (
|
||||
f"Host {self.name}: updated interface "
|
||||
f"with data {sanatize_log_output(updates)}."
|
||||
)
|
||||
self.logger.info(e)
|
||||
self.create_journal_entry("info", e)
|
||||
except APIRequestError as e:
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"""A collection of tools used by several classes"""
|
||||
|
||||
from modules.exceptions import HostgroupError
|
||||
|
||||
|
||||
def convert_recordset(recordset):
|
||||
"""Converts netbox RedcordSet to list of dicts."""
|
||||
recordlist = []
|
||||
@@ -101,7 +103,9 @@ def remove_duplicates(input_list, sortkey=None):
|
||||
return output_list
|
||||
|
||||
|
||||
def verify_hg_format(hg_format, device_cfs=None, vm_cfs=None, hg_type="dev", logger=None):
|
||||
def verify_hg_format(
|
||||
hg_format, device_cfs=None, vm_cfs=None, hg_type="dev", logger=None
|
||||
):
|
||||
"""
|
||||
Verifies hostgroup field format
|
||||
"""
|
||||
@@ -109,44 +113,51 @@ def verify_hg_format(hg_format, device_cfs=None, vm_cfs=None, hg_type="dev", log
|
||||
device_cfs = []
|
||||
if not vm_cfs:
|
||||
vm_cfs = []
|
||||
allowed_objects = {"dev": ["location",
|
||||
"rack",
|
||||
"role",
|
||||
"manufacturer",
|
||||
"region",
|
||||
"site",
|
||||
"site_group",
|
||||
"tenant",
|
||||
"tenant_group",
|
||||
"platform",
|
||||
"cluster"]
|
||||
,"vm": ["cluster_type",
|
||||
"role",
|
||||
"manufacturer",
|
||||
"region",
|
||||
"site",
|
||||
"site_group",
|
||||
"tenant",
|
||||
"tenant_group",
|
||||
"cluster",
|
||||
"device",
|
||||
"platform"]
|
||||
,"cfs": {"dev": [], "vm": []}
|
||||
}
|
||||
allowed_objects = {
|
||||
"dev": [
|
||||
"location",
|
||||
"rack",
|
||||
"role",
|
||||
"manufacturer",
|
||||
"region",
|
||||
"site",
|
||||
"site_group",
|
||||
"tenant",
|
||||
"tenant_group",
|
||||
"platform",
|
||||
"cluster",
|
||||
],
|
||||
"vm": [
|
||||
"cluster_type",
|
||||
"role",
|
||||
"manufacturer",
|
||||
"region",
|
||||
"site",
|
||||
"site_group",
|
||||
"tenant",
|
||||
"tenant_group",
|
||||
"cluster",
|
||||
"device",
|
||||
"platform",
|
||||
],
|
||||
"cfs": {"dev": [], "vm": []},
|
||||
}
|
||||
for cf in device_cfs:
|
||||
allowed_objects['cfs']['dev'].append(cf.name)
|
||||
allowed_objects["cfs"]["dev"].append(cf.name)
|
||||
for cf in vm_cfs:
|
||||
allowed_objects['cfs']['vm'].append(cf.name)
|
||||
allowed_objects["cfs"]["vm"].append(cf.name)
|
||||
hg_objects = []
|
||||
if isinstance(hg_format,list):
|
||||
if isinstance(hg_format, list):
|
||||
for f in hg_format:
|
||||
hg_objects = hg_objects + f.split("/")
|
||||
else:
|
||||
hg_objects = hg_format.split("/")
|
||||
hg_objects = sorted(set(hg_objects))
|
||||
for hg_object in hg_objects:
|
||||
if (hg_object not in allowed_objects[hg_type] and
|
||||
hg_object not in allowed_objects['cfs'][hg_type]):
|
||||
if (
|
||||
hg_object not in allowed_objects[hg_type]
|
||||
and hg_object not in allowed_objects["cfs"][hg_type]
|
||||
):
|
||||
e = (
|
||||
f"Hostgroup item {hg_object} is not valid. Make sure you"
|
||||
" use valid items and separate them with '/'."
|
||||
|
||||
@@ -57,8 +57,10 @@ class ZabbixUsermacros:
|
||||
macro["macro"] = str(macro_name)
|
||||
if isinstance(macro_properties, dict):
|
||||
if not "value" in macro_properties:
|
||||
self.logger.warning(f"Host {self.name}: Usermacro {macro_name} has "
|
||||
"no value in Netbox, skipping.")
|
||||
self.logger.warning(
|
||||
f"Host {self.name}: Usermacro {macro_name} has "
|
||||
"no value in Netbox, skipping."
|
||||
)
|
||||
return False
|
||||
macro["value"] = macro_properties["value"]
|
||||
|
||||
@@ -83,8 +85,10 @@ class ZabbixUsermacros:
|
||||
macro["description"] = ""
|
||||
|
||||
else:
|
||||
self.logger.warning(f"Host {self.name}: Usermacro {macro_name} "
|
||||
"has no value, skipping.")
|
||||
self.logger.warning(
|
||||
f"Host {self.name}: Usermacro {macro_name} "
|
||||
"has no value, skipping."
|
||||
)
|
||||
return False
|
||||
else:
|
||||
self.logger.error(
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# pylint: disable=duplicate-code
|
||||
"""Module that hosts all functions for virtual machine processing"""
|
||||
from modules.config import load_config
|
||||
from modules.device import PhysicalDevice
|
||||
from modules.exceptions import InterfaceConfigError, SyncInventoryError, TemplateError
|
||||
from modules.hostgroups import Hostgroup
|
||||
from modules.interface import ZabbixInterface
|
||||
from modules.config import load_config
|
||||
|
||||
# Load config
|
||||
config = load_config()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user