From d1ec1114ac6eebcf383b7c7394680e889d7d7e24 Mon Sep 17 00:00:00 2001 From: TheNetworkGuy Date: Wed, 24 Jul 2024 13:14:12 +0200 Subject: [PATCH] Fixes #70 --- README.md | 5 +++-- config.py.example | 9 +++++---- modules/device.py | 51 ++++++++++++++++++++++++++++------------------- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 853d7c6..3f158c3 100644 --- a/README.md +++ b/README.md @@ -172,8 +172,9 @@ You can modify this behaviour by changing the following list variables in the sc ### Zabbix Inventory This script allows you to enable the inventory on managed Zabbix hosts and sync NetBox device properties to the specified inventory fields. -To enable, set `inventory_sync` to `True`. -Set `inventory_automatic` to `False` to use manual inventory, or `True` for automatic. +To map Netbox information to Netbox inventory fields, set `inventory_sync` to `True`. + +You can set the inventory mode to "disabled", "manual" or "automatic" with the inventory_mode variable. See [Zabbix Manual](https://www.zabbix.com/documentation/current/en/manual/config/hosts/inventory#building-inventory) for more information about the modes. Use the `inventory_map` variable to map which NetBox properties are used in which Zabbix Inventory fields. diff --git a/config.py.example b/config.py.example index cfa7f6a..b856989 100644 --- a/config.py.example +++ b/config.py.example @@ -58,13 +58,14 @@ traverse_site_groups = False nb_device_filter = {"name__n": "null"} ## Inventory +# See https://www.zabbix.com/documentation/current/en/manual/config/hosts/inventory#building-inventory +# Choice between disabled, manual or automatic. +# Make sure to select at least manual or automatic in use with the inventory_sync function. +inventory_mode = "disabled" + # To allow syncing of NetBox device properties, set inventory_sync to True inventory_sync = False -# Set inventory_automatic to False to use manual inventory, True for automatic -# See https://www.zabbix.com/documentation/current/en/manual/config/hosts/inventory#building-inventory -inventory_automatic = True - # inventory_map is used to map NetBox properties to Zabbix Inventory fields. # For nested properties, you can use the '/' seperator. # For example, the following map will assign the custom field 'mycustomfield' to the 'alias' Zabbix inventory field: diff --git a/modules/device.py b/modules/device.py index 5b16419..49b046b 100644 --- a/modules/device.py +++ b/modules/device.py @@ -16,7 +16,7 @@ traverse_site_groups, traverse_regions, inventory_sync, - inventory_automatic, + inventory_mode, inventory_map ) except ModuleNotFoundError: @@ -196,12 +196,23 @@ def get_templates_context(self): def set_inventory(self, nbdevice): """ Set host inventory """ - self.inventory_mode = -1 + # Set inventory mode. Default is disabled (see class init function). + if inventory_mode == "disabled": + if inventory_sync: + self.logger.error(f"Device {self.name}: Unable to map Netbox inventory to Zabbix. " + "Inventory sync is enabled in config but inventory mode is disabled.") + return True + if inventory_mode == "manual": + self.inventory_mode = 0 + elif inventory_mode == "automatic": + self.inventory_mode = 1 + else: + self.logger.error(f"Device {self.name}: Specified value for inventory mode in" + f" config is not valid. Got value {inventory_mode}") + return False self.inventory = {} - if inventory_sync: - # Set inventory mode to automatic or manual - self.inventory_mode = 1 if inventory_automatic else 0 - + if inventory_sync and self.inventory_mode in [0,1]: + self.logger.debug(f"Device {self.name}: Starting inventory mapper") # Let's build an inventory dict for each property in the inventory_map for nb_inv_field, zbx_inv_field in inventory_map.items(): field_list = nb_inv_field.split("/") # convert str to list based on delimiter @@ -218,13 +229,15 @@ def set_inventory(self, nbdevice): self.inventory[zbx_inv_field] = str(value) elif not value: # empty value should just be an empty string for API compatibility - self.logger.debug(f"Inventory lookup for '{nb_inv_field}'" - " returned an empty value") + self.logger.debug(f"Device {self.name}: Netbox inventory lookup for " + f"'{nb_inv_field}' returned an empty value") self.inventory[zbx_inv_field] = "" else: # Value is not a string or numeral, probably not what the user expected. - self.logger.error(f"Inventory lookup for '{nb_inv_field}' returned" - " an unexpected type: it will be skipped.") + self.logger.error(f"Device {self.name}: Inventory lookup for '{nb_inv_field}'" + " returned an unexpected type: it will be skipped.") + self.logger.debug(f"Device {self.name}: Inventory mapping complete. " + f"Mapped {len(list(filter(None, self.inventory.values())))} field(s)") return True def isCluster(self): @@ -617,16 +630,14 @@ def ConsistencyCheck(self, groups, templates, proxies, proxy_power, create_hostg "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 - # actual inventory values - if str(host['inventory_mode']) == str(self.inventory_mode): - self.logger.debug(f"Device {self.name}: inventory_mode in-sync.") - else: - self.logger.warning(f"Device {self.name}: inventory_mode OUT of sync.") - self.updateZabbixHost(inventory_mode=str(self.inventory_mode)) - # Now we can check if inventory is in-sync. + # Check host inventory mode + if str(host['inventory_mode']) == str(self.inventory_mode): + self.logger.debug(f"Device {self.name}: inventory_mode in-sync.") + else: + self.logger.warning(f"Device {self.name}: inventory_mode OUT of sync.") + self.updateZabbixHost(inventory_mode=str(self.inventory_mode)) + if inventory_sync and self.inventory_mode in [0,1]: + # Check host inventory mapping if host['inventory'] == self.inventory: self.logger.debug(f"Device {self.name}: inventory in-sync.") else: