mirror of
https://github.com/TheNetworkGuy/netbox-zabbix-sync.git
synced 2025-07-14 01:41:25 -06:00
🚨 Linted and formatted file
This commit is contained in:
parent
1e269780ce
commit
525904cf43
@ -2,46 +2,55 @@
|
|||||||
# pylint: disable=invalid-name, logging-not-lazy, too-many-locals, logging-fstring-interpolation
|
# pylint: disable=invalid-name, logging-not-lazy, too-many-locals, logging-fstring-interpolation
|
||||||
|
|
||||||
"""NetBox to Zabbix sync script."""
|
"""NetBox to Zabbix sync script."""
|
||||||
import logging
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import logging
|
||||||
import ssl
|
import ssl
|
||||||
from os import environ, path, sys
|
from os import environ, path, sys
|
||||||
|
|
||||||
from pynetbox import api
|
from pynetbox import api
|
||||||
from pynetbox.core.query import RequestError as NBRequestError
|
from pynetbox.core.query import RequestError as NBRequestError
|
||||||
from requests.exceptions import ConnectionError as RequestsConnectionError
|
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.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.exceptions import EnvironmentVarError, HostgroupError, SyncError
|
||||||
|
from modules.tools import convert_recordset, proxy_prepper
|
||||||
|
from modules.virtual_machine import VirtualMachine
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from config import (
|
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,
|
||||||
templates_config_context_overrule,
|
templates_config_context_overrule,
|
||||||
clustering, create_hostgroups,
|
|
||||||
create_journal, full_proxy_sync,
|
|
||||||
zabbix_device_removal,
|
|
||||||
zabbix_device_disable,
|
|
||||||
hostgroup_format,
|
|
||||||
vm_hostgroup_format,
|
vm_hostgroup_format,
|
||||||
nb_device_filter,
|
zabbix_device_disable,
|
||||||
sync_vms,
|
zabbix_device_removal,
|
||||||
nb_vm_filter
|
|
||||||
)
|
)
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
print("Configuration file config.py not found in main directory."
|
print(
|
||||||
"Please create the file or rename the config.py.example file to config.py.")
|
"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)
|
sys.exit(1)
|
||||||
|
|
||||||
# Set logging
|
# Set logging
|
||||||
log_format = logging.Formatter('%(asctime)s - %(name)s - '
|
log_format = logging.Formatter(
|
||||||
'%(levelname)s - %(message)s')
|
"%(asctime)s - %(name)s - " "%(levelname)s - %(message)s"
|
||||||
|
)
|
||||||
lgout = logging.StreamHandler()
|
lgout = logging.StreamHandler()
|
||||||
lgout.setFormatter(log_format)
|
lgout.setFormatter(log_format)
|
||||||
lgout.setLevel(logging.DEBUG)
|
lgout.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
lgfile = logging.FileHandler(path.join(path.dirname(
|
lgfile = logging.FileHandler(
|
||||||
path.realpath(__file__)), "sync.log"))
|
path.join(path.dirname(path.realpath(__file__)), "sync.log")
|
||||||
|
)
|
||||||
lgfile.setFormatter(log_format)
|
lgfile.setFormatter(log_format)
|
||||||
lgfile.setLevel(logging.DEBUG)
|
lgfile.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
@ -84,15 +93,26 @@ def main(arguments):
|
|||||||
netbox = api(netbox_host, token=netbox_token, threading=True)
|
netbox = api(netbox_host, token=netbox_token, threading=True)
|
||||||
# Check if the provided Hostgroup layout is valid
|
# Check if the provided Hostgroup layout is valid
|
||||||
hg_objects = hostgroup_format.split("/")
|
hg_objects = hostgroup_format.split("/")
|
||||||
allowed_objects = ["location", "role", "manufacturer", "region",
|
allowed_objects = [
|
||||||
"site", "site_group", "tenant", "tenant_group"]
|
"location",
|
||||||
|
"role",
|
||||||
|
"manufacturer",
|
||||||
|
"region",
|
||||||
|
"site",
|
||||||
|
"site_group",
|
||||||
|
"tenant",
|
||||||
|
"tenant_group",
|
||||||
|
]
|
||||||
# Create API call to get all custom fields which are on the device objects
|
# Create API call to get all custom fields which are on the device objects
|
||||||
try:
|
try:
|
||||||
device_cfs = list(netbox.extras.custom_fields.filter(
|
device_cfs = list(
|
||||||
type="text", content_type_id=23))
|
netbox.extras.custom_fields.filter(type="text", content_type_id=23)
|
||||||
|
)
|
||||||
except RequestsConnectionError:
|
except RequestsConnectionError:
|
||||||
logger.error(f"Unable to connect to NetBox with URL {netbox_host}."
|
logger.error(
|
||||||
" Please check the URL and status of NetBox.")
|
f"Unable to connect to NetBox with URL {netbox_host}."
|
||||||
|
" Please check the URL and status of NetBox."
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except NBRequestError as e:
|
except NBRequestError as e:
|
||||||
logger.error(f"NetBox error: {e}")
|
logger.error(f"NetBox error: {e}")
|
||||||
@ -101,8 +121,10 @@ def main(arguments):
|
|||||||
allowed_objects.append(cf.name)
|
allowed_objects.append(cf.name)
|
||||||
for hg_object in hg_objects:
|
for hg_object in hg_objects:
|
||||||
if hg_object not in allowed_objects:
|
if hg_object not in allowed_objects:
|
||||||
e = (f"Hostgroup item {hg_object} is not valid. Make sure you"
|
e = (
|
||||||
" use valid items and seperate them with '/'.")
|
f"Hostgroup item {hg_object} is not valid. Make sure you"
|
||||||
|
" use valid items and seperate them with '/'."
|
||||||
|
)
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
raise HostgroupError(e)
|
raise HostgroupError(e)
|
||||||
# Set Zabbix API
|
# Set Zabbix API
|
||||||
@ -114,18 +136,18 @@ def main(arguments):
|
|||||||
ssl_ctx.load_verify_locations(environ["REQUESTS_CA_BUNDLE"])
|
ssl_ctx.load_verify_locations(environ["REQUESTS_CA_BUNDLE"])
|
||||||
|
|
||||||
if not zabbix_token:
|
if not zabbix_token:
|
||||||
zabbix = ZabbixAPI(zabbix_host, user=zabbix_user,
|
|
||||||
password=zabbix_pass, ssl_context=ssl_ctx)
|
|
||||||
else:
|
|
||||||
zabbix = ZabbixAPI(
|
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()
|
zabbix.check_auth()
|
||||||
except (APIRequestError, ProcessingError) as e:
|
except (APIRequestError, ProcessingError) as e:
|
||||||
e = f"Zabbix returned the following error: {str(e)}"
|
e = f"Zabbix returned the following error: {str(e)}"
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
# Set API parameter mapping based on API version
|
# 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"
|
proxy_name = "host"
|
||||||
else:
|
else:
|
||||||
proxy_name = "name"
|
proxy_name = "name"
|
||||||
@ -133,23 +155,21 @@ def main(arguments):
|
|||||||
netbox_devices = list(netbox.dcim.devices.filter(**nb_device_filter))
|
netbox_devices = list(netbox.dcim.devices.filter(**nb_device_filter))
|
||||||
netbox_vms = []
|
netbox_vms = []
|
||||||
if sync_vms:
|
if sync_vms:
|
||||||
netbox_vms = list(
|
netbox_vms = list(netbox.virtualization.virtual_machines.filter(**nb_vm_filter))
|
||||||
netbox.virtualization.virtual_machines.filter(**nb_vm_filter))
|
|
||||||
netbox_site_groups = convert_recordset((netbox.dcim.site_groups.all()))
|
netbox_site_groups = convert_recordset((netbox.dcim.site_groups.all()))
|
||||||
netbox_regions = convert_recordset(netbox.dcim.regions.all())
|
netbox_regions = convert_recordset(netbox.dcim.regions.all())
|
||||||
netbox_journals = netbox.extras.journal_entries
|
netbox_journals = netbox.extras.journal_entries
|
||||||
zabbix_groups = zabbix.hostgroup.get(output=['groupid', 'name'])
|
zabbix_groups = zabbix.hostgroup.get(output=["groupid", "name"])
|
||||||
zabbix_templates = zabbix.template.get(output=['templateid', 'name'])
|
zabbix_templates = zabbix.template.get(output=["templateid", "name"])
|
||||||
zabbix_proxies = zabbix.proxy.get(output=['proxyid', proxy_name])
|
zabbix_proxies = zabbix.proxy.get(output=["proxyid", proxy_name])
|
||||||
# Set empty list for proxy processing Zabbix <= 6
|
# Set empty list for proxy processing Zabbix <= 6
|
||||||
zabbix_proxygroups = []
|
zabbix_proxygroups = []
|
||||||
if str(zabbix.version).startswith('7'):
|
if str(zabbix.version).startswith("7"):
|
||||||
zabbix_proxygroups = zabbix.proxygroup.get(
|
zabbix_proxygroups = zabbix.proxygroup.get(output=["proxy_groupid", "name"])
|
||||||
output=["proxy_groupid", "name"])
|
|
||||||
# Sanitize proxy data
|
# Sanitize proxy data
|
||||||
if proxy_name == "host":
|
if proxy_name == "host":
|
||||||
for proxy in zabbix_proxies:
|
for proxy in zabbix_proxies:
|
||||||
proxy['name'] = proxy.pop('host')
|
proxy["name"] = proxy.pop("host")
|
||||||
# Prepare list of all proxy and proxy_groups
|
# Prepare list of all proxy and proxy_groups
|
||||||
zabbix_proxy_list = proxy_prepper(zabbix_proxies, zabbix_proxygroups)
|
zabbix_proxy_list = proxy_prepper(zabbix_proxies, zabbix_proxygroups)
|
||||||
|
|
||||||
@ -159,15 +179,15 @@ def main(arguments):
|
|||||||
# Go through all NetBox devices
|
# Go through all NetBox devices
|
||||||
for nb_vm in netbox_vms:
|
for nb_vm in netbox_vms:
|
||||||
try:
|
try:
|
||||||
vm = VirtualMachine(nb_vm, zabbix, netbox_journals, nb_version,
|
vm = VirtualMachine(
|
||||||
create_journal, logger)
|
nb_vm, zabbix, netbox_journals, nb_version, create_journal, logger
|
||||||
|
)
|
||||||
logger.debug(f"Host {vm.name}: Started operations on VM.")
|
logger.debug(f"Host {vm.name}: Started operations on VM.")
|
||||||
vm.set_vm_template()
|
vm.set_vm_template()
|
||||||
# Check if a valid template has been found for this VM.
|
# Check if a valid template has been found for this VM.
|
||||||
if not vm.zbx_template_names:
|
if not vm.zbx_template_names:
|
||||||
continue
|
continue
|
||||||
vm.set_hostgroup(vm_hostgroup_format,
|
vm.set_hostgroup(vm_hostgroup_format, netbox_site_groups, netbox_regions)
|
||||||
netbox_site_groups, netbox_regions)
|
|
||||||
# Check if a valid hostgroup has been found for this VM.
|
# Check if a valid hostgroup has been found for this VM.
|
||||||
if not vm.hostgroup:
|
if not vm.hostgroup:
|
||||||
continue
|
continue
|
||||||
@ -184,17 +204,23 @@ def main(arguments):
|
|||||||
continue
|
continue
|
||||||
# Device has been added to NetBox
|
# Device has been added to NetBox
|
||||||
# but is not in Activate state
|
# but is not in Activate state
|
||||||
logger.info(f"VM {vm.name}: skipping since this VM is "
|
logger.info(
|
||||||
f"not in the active state.")
|
f"VM {vm.name}: skipping since this VM is "
|
||||||
|
f"not in the active state."
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
# Check if the VM is in the disabled state
|
# Check if the VM is in the disabled state
|
||||||
if vm.status in zabbix_device_disable:
|
if vm.status in zabbix_device_disable:
|
||||||
vm.zabbix_state = 1
|
vm.zabbix_state = 1
|
||||||
# Check if VM is already in Zabbix
|
# Check if VM is already in Zabbix
|
||||||
if vm.zabbix_id:
|
if vm.zabbix_id:
|
||||||
vm.ConsistencyCheck(zabbix_groups, zabbix_templates,
|
vm.ConsistencyCheck(
|
||||||
zabbix_proxy_list, full_proxy_sync,
|
zabbix_groups,
|
||||||
create_hostgroups)
|
zabbix_templates,
|
||||||
|
zabbix_proxy_list,
|
||||||
|
full_proxy_sync,
|
||||||
|
create_hostgroups,
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
# Add hostgroup is config is set
|
# Add hostgroup is config is set
|
||||||
if create_hostgroups:
|
if create_hostgroups:
|
||||||
@ -205,24 +231,24 @@ def main(arguments):
|
|||||||
# Add new hostgroups to zabbix group list
|
# Add new hostgroups to zabbix group list
|
||||||
zabbix_groups.append(group)
|
zabbix_groups.append(group)
|
||||||
# Add VM to Zabbix
|
# Add VM to Zabbix
|
||||||
vm.createInZabbix(zabbix_groups, zabbix_templates,
|
vm.createInZabbix(zabbix_groups, zabbix_templates, zabbix_proxy_list)
|
||||||
zabbix_proxy_list)
|
|
||||||
except SyncError:
|
except SyncError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for nb_device in netbox_devices:
|
for nb_device in netbox_devices:
|
||||||
try:
|
try:
|
||||||
# Set device instance set data such as hostgroup and template information.
|
# Set device instance set data such as hostgroup and template information.
|
||||||
device = PhysicalDevice(nb_device, zabbix, netbox_journals, nb_version,
|
device = PhysicalDevice(
|
||||||
create_journal, logger)
|
nb_device, zabbix, netbox_journals, nb_version, create_journal, logger
|
||||||
|
)
|
||||||
logger.debug(f"Host {device.name}: started operations on device.")
|
logger.debug(f"Host {device.name}: started operations on device.")
|
||||||
device.set_template(templates_config_context,
|
device.set_template(
|
||||||
templates_config_context_overrule)
|
templates_config_context, templates_config_context_overrule
|
||||||
|
)
|
||||||
# Check if a valid template has been found for this VM.
|
# Check if a valid template has been found for this VM.
|
||||||
if not device.zbx_template_names:
|
if not device.zbx_template_names:
|
||||||
continue
|
continue
|
||||||
device.set_hostgroup(
|
device.set_hostgroup(hostgroup_format, netbox_site_groups, netbox_regions)
|
||||||
hostgroup_format, netbox_site_groups, netbox_regions)
|
|
||||||
# Check if a valid hostgroup has been found for this VM.
|
# Check if a valid hostgroup has been found for this VM.
|
||||||
if not device.hostgroup:
|
if not device.hostgroup:
|
||||||
continue
|
continue
|
||||||
@ -234,14 +260,15 @@ def main(arguments):
|
|||||||
if device.isCluster() and clustering:
|
if device.isCluster() and clustering:
|
||||||
# Check if device is primary or secondary
|
# Check if device is primary or secondary
|
||||||
if device.promoteMasterDevice():
|
if device.promoteMasterDevice():
|
||||||
e = (f"Device {device.name}: is "
|
e = f"Device {device.name}: is " f"part of cluster and primary."
|
||||||
f"part of cluster and primary.")
|
|
||||||
logger.info(e)
|
logger.info(e)
|
||||||
else:
|
else:
|
||||||
# Device is secondary in cluster.
|
# Device is secondary in cluster.
|
||||||
# Don't continue with this device.
|
# Don't continue with this device.
|
||||||
e = (f"Device {device.name}: is part of cluster "
|
e = (
|
||||||
f"but not primary. Skipping this host...")
|
f"Device {device.name}: is part of cluster "
|
||||||
|
f"but not primary. Skipping this host..."
|
||||||
|
)
|
||||||
logger.info(e)
|
logger.info(e)
|
||||||
continue
|
continue
|
||||||
# Checks if device is in cleanup state
|
# Checks if device is in cleanup state
|
||||||
@ -254,17 +281,23 @@ def main(arguments):
|
|||||||
continue
|
continue
|
||||||
# Device has been added to NetBox
|
# Device has been added to NetBox
|
||||||
# but is not in Activate state
|
# but is not in Activate state
|
||||||
logger.info(f"Device {device.name}: skipping since this device is "
|
logger.info(
|
||||||
f"not in the active state.")
|
f"Device {device.name}: skipping since this device is "
|
||||||
|
f"not in the active state."
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
# Check if the device is in the disabled state
|
# Check if the device is in the disabled state
|
||||||
if device.status in zabbix_device_disable:
|
if device.status in zabbix_device_disable:
|
||||||
device.zabbix_state = 1
|
device.zabbix_state = 1
|
||||||
# Check if device is already in Zabbix
|
# Check if device is already in Zabbix
|
||||||
if device.zabbix_id:
|
if device.zabbix_id:
|
||||||
device.ConsistencyCheck(zabbix_groups, zabbix_templates,
|
device.ConsistencyCheck(
|
||||||
zabbix_proxy_list, full_proxy_sync,
|
zabbix_groups,
|
||||||
create_hostgroups)
|
zabbix_templates,
|
||||||
|
zabbix_proxy_list,
|
||||||
|
full_proxy_sync,
|
||||||
|
create_hostgroups,
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
# Add hostgroup is config is set
|
# Add hostgroup is config is set
|
||||||
if create_hostgroups:
|
if create_hostgroups:
|
||||||
@ -275,17 +308,17 @@ def main(arguments):
|
|||||||
# Add new hostgroups to zabbix group list
|
# Add new hostgroups to zabbix group list
|
||||||
zabbix_groups.append(group)
|
zabbix_groups.append(group)
|
||||||
# Add device to Zabbix
|
# Add device to Zabbix
|
||||||
device.createInZabbix(zabbix_groups, zabbix_templates,
|
device.createInZabbix(zabbix_groups, zabbix_templates, zabbix_proxy_list)
|
||||||
zabbix_proxy_list)
|
|
||||||
except SyncError:
|
except SyncError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(
|
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()
|
args = parser.parse_args()
|
||||||
main(args)
|
main(args)
|
||||||
|
Loading…
Reference in New Issue
Block a user