From 525904cf43d7f77a7010c73001549e86f8d658db Mon Sep 17 00:00:00 2001 From: Wouter de Bruijn Date: Wed, 26 Feb 2025 10:07:51 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A8=20Linted=20and=20formatted=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_zabbix_sync.py | 175 +++++++++++++++++++++++++----------------- 1 file changed, 104 insertions(+), 71 deletions(-) diff --git a/netbox_zabbix_sync.py b/netbox_zabbix_sync.py index 04a4e07..b355657 100755 --- a/netbox_zabbix_sync.py +++ b/netbox_zabbix_sync.py @@ -2,46 +2,55 @@ # pylint: disable=invalid-name, logging-not-lazy, too-many-locals, logging-fstring-interpolation """NetBox to Zabbix sync script.""" -import logging import argparse +import logging import ssl from os import environ, path, sys + from pynetbox import api from pynetbox.core.query import RequestError as NBRequestError from requests.exceptions import ConnectionError as RequestsConnectionError -from zabbix_utils import ZabbixAPI, APIRequestError, ProcessingError +from zabbix_utils import APIRequestError, ProcessingError, ZabbixAPI + from modules.device import PhysicalDevice -from modules.virtual_machine import VirtualMachine -from modules.tools import convert_recordset, proxy_prepper from modules.exceptions import EnvironmentVarError, HostgroupError, SyncError +from modules.tools import convert_recordset, proxy_prepper +from modules.virtual_machine import VirtualMachine + try: from config import ( + clustering, + create_hostgroups, + create_journal, + full_proxy_sync, + hostgroup_format, + nb_device_filter, + nb_vm_filter, + sync_vms, templates_config_context, templates_config_context_overrule, - clustering, create_hostgroups, - create_journal, full_proxy_sync, - zabbix_device_removal, - zabbix_device_disable, - hostgroup_format, vm_hostgroup_format, - nb_device_filter, - sync_vms, - nb_vm_filter + zabbix_device_disable, + zabbix_device_removal, ) except ModuleNotFoundError: - print("Configuration file config.py not found in main directory." - "Please create the file or rename the config.py.example file to config.py.") + print( + "Configuration file config.py not found in main directory." + "Please create the file or rename the config.py.example file to config.py." + ) sys.exit(1) # Set logging -log_format = logging.Formatter('%(asctime)s - %(name)s - ' - '%(levelname)s - %(message)s') +log_format = logging.Formatter( + "%(asctime)s - %(name)s - " "%(levelname)s - %(message)s" +) lgout = logging.StreamHandler() lgout.setFormatter(log_format) lgout.setLevel(logging.DEBUG) -lgfile = logging.FileHandler(path.join(path.dirname( - path.realpath(__file__)), "sync.log")) +lgfile = logging.FileHandler( + path.join(path.dirname(path.realpath(__file__)), "sync.log") +) lgfile.setFormatter(log_format) lgfile.setLevel(logging.DEBUG) @@ -84,15 +93,26 @@ def main(arguments): netbox = api(netbox_host, token=netbox_token, threading=True) # Check if the provided Hostgroup layout is valid hg_objects = hostgroup_format.split("/") - allowed_objects = ["location", "role", "manufacturer", "region", - "site", "site_group", "tenant", "tenant_group"] + allowed_objects = [ + "location", + "role", + "manufacturer", + "region", + "site", + "site_group", + "tenant", + "tenant_group", + ] # Create API call to get all custom fields which are on the device objects try: - device_cfs = list(netbox.extras.custom_fields.filter( - type="text", content_type_id=23)) + device_cfs = list( + netbox.extras.custom_fields.filter(type="text", content_type_id=23) + ) except RequestsConnectionError: - logger.error(f"Unable to connect to NetBox with URL {netbox_host}." - " Please check the URL and status of NetBox.") + logger.error( + f"Unable to connect to NetBox with URL {netbox_host}." + " Please check the URL and status of NetBox." + ) sys.exit(1) except NBRequestError as e: logger.error(f"NetBox error: {e}") @@ -101,8 +121,10 @@ def main(arguments): allowed_objects.append(cf.name) for hg_object in hg_objects: if hg_object not in allowed_objects: - e = (f"Hostgroup item {hg_object} is not valid. Make sure you" - " use valid items and seperate them with '/'.") + e = ( + f"Hostgroup item {hg_object} is not valid. Make sure you" + " use valid items and seperate them with '/'." + ) logger.error(e) raise HostgroupError(e) # Set Zabbix API @@ -114,18 +136,18 @@ def main(arguments): ssl_ctx.load_verify_locations(environ["REQUESTS_CA_BUNDLE"]) if not zabbix_token: - zabbix = ZabbixAPI(zabbix_host, user=zabbix_user, - password=zabbix_pass, ssl_context=ssl_ctx) - else: zabbix = ZabbixAPI( - zabbix_host, token=zabbix_token, ssl_context=ssl_ctx) + zabbix_host, user=zabbix_user, password=zabbix_pass, ssl_context=ssl_ctx + ) + else: + zabbix = ZabbixAPI(zabbix_host, token=zabbix_token, ssl_context=ssl_ctx) zabbix.check_auth() except (APIRequestError, ProcessingError) as e: e = f"Zabbix returned the following error: {str(e)}" logger.error(e) sys.exit(1) # Set API parameter mapping based on API version - if not str(zabbix.version).startswith('7'): + if not str(zabbix.version).startswith("7"): proxy_name = "host" else: proxy_name = "name" @@ -133,23 +155,21 @@ def main(arguments): netbox_devices = list(netbox.dcim.devices.filter(**nb_device_filter)) netbox_vms = [] if sync_vms: - netbox_vms = list( - netbox.virtualization.virtual_machines.filter(**nb_vm_filter)) + netbox_vms = list(netbox.virtualization.virtual_machines.filter(**nb_vm_filter)) netbox_site_groups = convert_recordset((netbox.dcim.site_groups.all())) netbox_regions = convert_recordset(netbox.dcim.regions.all()) netbox_journals = netbox.extras.journal_entries - 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_groups = zabbix.hostgroup.get(output=["groupid", "name"]) + zabbix_templates = zabbix.template.get(output=["templateid", "name"]) + zabbix_proxies = zabbix.proxy.get(output=["proxyid", proxy_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"]) + 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: - proxy['name'] = proxy.pop('host') + proxy["name"] = proxy.pop("host") # Prepare list of all proxy and proxy_groups zabbix_proxy_list = proxy_prepper(zabbix_proxies, zabbix_proxygroups) @@ -159,15 +179,15 @@ def main(arguments): # Go through all NetBox devices for nb_vm in netbox_vms: try: - vm = VirtualMachine(nb_vm, zabbix, netbox_journals, nb_version, - create_journal, logger) + vm = VirtualMachine( + nb_vm, zabbix, netbox_journals, nb_version, create_journal, logger + ) logger.debug(f"Host {vm.name}: Started operations on VM.") vm.set_vm_template() # Check if a valid template has been found for this VM. if not vm.zbx_template_names: continue - vm.set_hostgroup(vm_hostgroup_format, - netbox_site_groups, netbox_regions) + vm.set_hostgroup(vm_hostgroup_format, netbox_site_groups, netbox_regions) # Check if a valid hostgroup has been found for this VM. if not vm.hostgroup: continue @@ -184,17 +204,23 @@ def main(arguments): continue # Device has been added to NetBox # but is not in Activate state - logger.info(f"VM {vm.name}: skipping since this VM is " - f"not in the active state.") + logger.info( + f"VM {vm.name}: skipping since this VM is " + f"not in the active state." + ) continue # Check if the VM is in the disabled state if vm.status in zabbix_device_disable: vm.zabbix_state = 1 # Check if VM is already in Zabbix if vm.zabbix_id: - vm.ConsistencyCheck(zabbix_groups, zabbix_templates, - zabbix_proxy_list, full_proxy_sync, - create_hostgroups) + vm.ConsistencyCheck( + zabbix_groups, + zabbix_templates, + zabbix_proxy_list, + full_proxy_sync, + create_hostgroups, + ) continue # Add hostgroup is config is set if create_hostgroups: @@ -205,24 +231,24 @@ def main(arguments): # Add new hostgroups to zabbix group list zabbix_groups.append(group) # Add VM to Zabbix - vm.createInZabbix(zabbix_groups, zabbix_templates, - zabbix_proxy_list) + vm.createInZabbix(zabbix_groups, zabbix_templates, zabbix_proxy_list) except SyncError: pass for nb_device in netbox_devices: try: # Set device instance set data such as hostgroup and template information. - device = PhysicalDevice(nb_device, zabbix, netbox_journals, nb_version, - create_journal, logger) + device = PhysicalDevice( + nb_device, zabbix, netbox_journals, nb_version, create_journal, logger + ) logger.debug(f"Host {device.name}: started operations on device.") - device.set_template(templates_config_context, - templates_config_context_overrule) + device.set_template( + templates_config_context, templates_config_context_overrule + ) # Check if a valid template has been found for this VM. if not device.zbx_template_names: continue - device.set_hostgroup( - hostgroup_format, netbox_site_groups, netbox_regions) + device.set_hostgroup(hostgroup_format, netbox_site_groups, netbox_regions) # Check if a valid hostgroup has been found for this VM. if not device.hostgroup: continue @@ -234,14 +260,15 @@ def main(arguments): if device.isCluster() and clustering: # Check if device is primary or secondary if device.promoteMasterDevice(): - e = (f"Device {device.name}: is " - f"part of cluster and primary.") + e = f"Device {device.name}: is " f"part of cluster and primary." logger.info(e) else: # Device is secondary in cluster. # Don't continue with this device. - e = (f"Device {device.name}: is part of cluster " - f"but not primary. Skipping this host...") + e = ( + f"Device {device.name}: is part of cluster " + f"but not primary. Skipping this host..." + ) logger.info(e) continue # Checks if device is in cleanup state @@ -254,17 +281,23 @@ def main(arguments): continue # Device has been added to NetBox # but is not in Activate state - logger.info(f"Device {device.name}: skipping since this device is " - f"not in the active state.") + logger.info( + f"Device {device.name}: skipping since this device is " + f"not in the active state." + ) continue # Check if the device is in the disabled state if device.status in zabbix_device_disable: device.zabbix_state = 1 # Check if device is already in Zabbix if device.zabbix_id: - device.ConsistencyCheck(zabbix_groups, zabbix_templates, - zabbix_proxy_list, full_proxy_sync, - create_hostgroups) + device.ConsistencyCheck( + zabbix_groups, + zabbix_templates, + zabbix_proxy_list, + full_proxy_sync, + create_hostgroups, + ) continue # Add hostgroup is config is set if create_hostgroups: @@ -275,17 +308,17 @@ def main(arguments): # Add new hostgroups to zabbix group list zabbix_groups.append(group) # Add device to Zabbix - device.createInZabbix(zabbix_groups, zabbix_templates, - zabbix_proxy_list) + device.createInZabbix(zabbix_groups, zabbix_templates, zabbix_proxy_list) except SyncError: pass if __name__ == "__main__": parser = argparse.ArgumentParser( - description='A script to sync Zabbix with NetBox device data.' + description="A script to sync Zabbix with NetBox device data." + ) + parser.add_argument( + "-v", "--verbose", help="Turn on debugging.", action="store_true" ) - parser.add_argument("-v", "--verbose", help="Turn on debugging.", - action="store_true") args = parser.parse_args() main(args)