mirror of
https://github.com/TheNetworkGuy/netbox-zabbix-sync.git
synced 2025-07-16 12:12:57 -06:00
First working version of clustered IP monitoring
This commit is contained in:
parent
a0ea21d731
commit
f13b86e2e0
23
README.md
23
README.md
@ -70,18 +70,26 @@ ZABBIX_TOKEN=othersecrettoken
|
||||
### Netbox custom fields
|
||||
Use the following custom fields in Netbox (if you are using config context for the template information then the zabbix_template field is not required):
|
||||
```
|
||||
* Type: Integer
|
||||
* Name: zabbix_hostid
|
||||
* Type: Integer
|
||||
* Required: False
|
||||
* Default: null
|
||||
* Object: dcim > device
|
||||
* Content types: DCIM > Device, DCIM > Virtual Chassis (optional)
|
||||
```
|
||||
```
|
||||
* Type: Text
|
||||
* Name: zabbix_template
|
||||
* Type: Text
|
||||
* Required: False
|
||||
* Default: null
|
||||
* Object: dcim > device_type
|
||||
* Content types: DCIM > Device Type
|
||||
```
|
||||
```
|
||||
* Name: primary_ip
|
||||
* Type: Object
|
||||
* Object type: IPAM > IP Address
|
||||
* Required: False
|
||||
* Default: null
|
||||
* Content types: DCIM > Virtual Chassis
|
||||
```
|
||||
You can make the `zabbix_hostid` field hidden or read-only to prevent human intervention.
|
||||
|
||||
@ -191,6 +199,13 @@ See `config.py.example` for an extensive example map.
|
||||
Any Zabix Inventory fields that are not included in the map will not be touched by the script,
|
||||
so you can safely add manual values or use items to automatically add values to other fields.
|
||||
|
||||
### Clustering
|
||||
When `clustering` is set to `True`, the script will monitor devices within a a Virtual Chassis through the master device.
|
||||
If needed, when `clusterip` is set to `True`, the script will try to use the custom field name defined in `clusterip_cf` on the Virtual Chassis
|
||||
as the primary IP for the Master device. This is only true when the master device has no primary ip set.
|
||||
|
||||
Setting this up allows you to use FHRP group assigned floating IPs to monitor your clusters which can be useful for a variety of vendors.
|
||||
|
||||
### Template source
|
||||
You can either use a Netbox device type custom field or Netbox config context for the Zabbix template information.
|
||||
|
||||
|
@ -15,6 +15,11 @@ device_cf = "zabbix_hostid"
|
||||
## Enable clustering of devices with virtual chassis setup
|
||||
clustering = False
|
||||
|
||||
# Allow monitoring on shared cluster IP if no primary IP has been set on the master device.
|
||||
# clusterip_cf specifies which custom field contains the IP address object in the Virtual Chassis.
|
||||
clusterip = False
|
||||
clusterip_cf = "primary_ip"
|
||||
|
||||
## Enable hostgroup generation. Requires permissions in Zabbix
|
||||
create_hostgroups = True
|
||||
|
||||
|
@ -13,6 +13,7 @@ from modules.tools import build_path
|
||||
try:
|
||||
from config import (
|
||||
template_cf, device_cf,
|
||||
clustering, clusterip, clusterip_cf,
|
||||
traverse_site_groups,
|
||||
traverse_regions,
|
||||
inventory_sync,
|
||||
@ -31,7 +32,7 @@ class NetworkDevice():
|
||||
INPUT: (Netbox device class, ZabbixAPI class, journal flag, NB journal class)
|
||||
"""
|
||||
|
||||
def __init__(self, nb, zabbix, nb_journal_class, nb_version, journal=None, logger=None):
|
||||
def __init__(self, nb, zabbix, nb_journal_class, nb_version, nb_vcs, journal=None, logger=None):
|
||||
self.nb = nb
|
||||
self.id = nb.id
|
||||
self.name = nb.name
|
||||
@ -53,18 +54,27 @@ class NetworkDevice():
|
||||
self.inventory_mode = -1
|
||||
self.inventory = {}
|
||||
self.logger = logger if logger else getLogger(__name__)
|
||||
self._setBasics()
|
||||
self._setBasics(nb_vcs)
|
||||
|
||||
def _setBasics(self):
|
||||
def _setBasics(self,nb_vcs):
|
||||
"""
|
||||
Sets basic information like IP address.
|
||||
"""
|
||||
# Return error if device does not have primary IP.
|
||||
self.ip = None
|
||||
if self.nb.primary_ip:
|
||||
self.cidr = self.nb.primary_ip.address
|
||||
self.ip = self.cidr.split("/")[0]
|
||||
else:
|
||||
e = f"Device {self.name}: no primary IP."
|
||||
elif bool(self.nb.virtual_chassis) and clustering and clusterip:
|
||||
devcluster = next((vc for vc in nb_vcs if vc['id'] == self.nb.virtual_chassis.id), None)
|
||||
if (devcluster and clusterip_cf in devcluster['custom_fields'] and
|
||||
devcluster['custom_fields'][clusterip_cf]):
|
||||
self.ip = devcluster['custom_fields'][clusterip_cf]['address'].split("/")[0]
|
||||
self.logger.debug(f"Device {self.name} is cluster member, "
|
||||
f"using primary cluster ip address {self.ip}.")
|
||||
|
||||
if not self.ip:
|
||||
# Return error if device does not have primary IP.
|
||||
e = f"Device {self.name} no primary IP, skipping this device."
|
||||
self.logger.info(e)
|
||||
raise SyncInventoryError(e)
|
||||
|
||||
@ -262,7 +272,7 @@ class NetworkDevice():
|
||||
raise SyncInventoryError(e)
|
||||
return self.nb.virtual_chassis.master.id
|
||||
|
||||
def promoteMasterDevice(self):
|
||||
def promoteMasterDevice(self,vcs):
|
||||
"""
|
||||
If device is Primary in cluster,
|
||||
promote device name to the cluster name.
|
||||
|
@ -19,7 +19,8 @@ try:
|
||||
zabbix_device_removal,
|
||||
zabbix_device_disable,
|
||||
hostgroup_format,
|
||||
nb_device_filter
|
||||
nb_device_filter,
|
||||
device_cf
|
||||
)
|
||||
except ModuleNotFoundError:
|
||||
print("Configuration file config.py not found in main directory."
|
||||
@ -107,6 +108,7 @@ def main(arguments):
|
||||
# Get all Zabbix and Netbox data
|
||||
netbox_devices = netbox.dcim.devices.filter(**nb_device_filter)
|
||||
netbox_site_groups = convert_recordset((netbox.dcim.site_groups.all()))
|
||||
netbox_virtual_chassis = convert_recordset((netbox.dcim.virtual_chassis.all()))
|
||||
netbox_regions = convert_recordset(netbox.dcim.regions.all())
|
||||
netbox_journals = netbox.extras.journal_entries
|
||||
zabbix_groups = zabbix.hostgroup.get(output=['groupid', 'name'])
|
||||
@ -130,21 +132,44 @@ def main(arguments):
|
||||
for nb_device in netbox_devices:
|
||||
try:
|
||||
# Set device instance set data such as hostgroup and template information.
|
||||
vcobj = None
|
||||
device = NetworkDevice(nb_device, zabbix, netbox_journals, nb_version,
|
||||
create_journal, logger)
|
||||
netbox_virtual_chassis, create_journal, logger)
|
||||
device.set_hostgroup(hostgroup_format,netbox_site_groups,netbox_regions)
|
||||
device.set_template(templates_config_context, templates_config_context_overrule)
|
||||
device.set_inventory(nb_device)
|
||||
# Checks if device is part of cluster.
|
||||
# Requires clustering variable
|
||||
if device.isCluster() and clustering:
|
||||
vcobj = netbox.dcim.virtual_chassis.get(id=device.nb.virtual_chassis.id)
|
||||
# Check if device is primary or secondary
|
||||
if device.promoteMasterDevice():
|
||||
if device.promoteMasterDevice(netbox_virtual_chassis):
|
||||
e = (f"Device {device.name}: is "
|
||||
f"part of cluster and primary.")
|
||||
logger.info(e)
|
||||
# If the device has a Zabbix host ID, make sure to assign it
|
||||
# to the Virtual Chassis if that is not yet the case.
|
||||
if device.zabbix_id and not vcobj.custom_fields[device_cf]:
|
||||
logger.debug(f"Assigning Zabbix host id {device.zabbix_id}"
|
||||
f" to Virtual Chassis {device.nb.virtual_chassis['name']}.")
|
||||
vcobj.custom_fields[device_cf] = int(device.zabbix_id)
|
||||
vcobj.save()
|
||||
# If the device does not have a Zabbix host ID, use the Virtual Cluster Zabbix ID
|
||||
elif vcobj.custom_fields[device_cf] and not device.zabbix_id:
|
||||
logger.debug(f"Assigning Zabbix host id {vcobj.custom_fields[device_cf]}"
|
||||
f" to device {device.nb.name} based on cluster membership.")
|
||||
device.zabbix_id = int(vcobj.custom_fields[device_cf])
|
||||
device.nb.custom_fields[device_cf] = device.zabbix_id
|
||||
device.nb.save()
|
||||
else:
|
||||
# Device is secondary in cluster.
|
||||
# if the device has a Zabbix host ID but is no longer master of the Virtual Chassis,
|
||||
# make sure to cleanup the host ID.
|
||||
if vcobj.custom_fields[device_cf] and device.zabbix_id:
|
||||
logger.debug(f"Device {device.name} cleanup old Zabbix host ID"
|
||||
"{device.zabbix_id} artefact in NetBox.")
|
||||
device.nb.custom_fields[device_cf] = None
|
||||
device.nb.save()
|
||||
# Device is not primary in cluster.
|
||||
# Don't continue with this device.
|
||||
e = (f"Device {device.name}: is part of cluster "
|
||||
f"but not primary. Skipping this host...")
|
||||
@ -183,6 +208,12 @@ def main(arguments):
|
||||
# Add device to Zabbix
|
||||
device.createInZabbix(zabbix_groups, zabbix_templates,
|
||||
zabbix_proxy_list)
|
||||
# Make sure to save hostid in Virtual Chassis as well
|
||||
if device.isCluster() and clustering and device.zabbix_id:
|
||||
logger.debug(f"Assigning Zabbix host id {device.zabbix_id}"
|
||||
f" to Virtual Cluster {vcobj.name}")
|
||||
vcobj.custom_fields[device_cf] = int(device.zabbix_id)
|
||||
vcobj.save()
|
||||
except SyncError:
|
||||
pass
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user