Working usermacros based on config context

This commit is contained in:
Raymond Kuiper 2025-02-14 08:28:10 +01:00
parent cebefd681e
commit 6d4e250b23
2 changed files with 74 additions and 17 deletions

View File

@ -5,6 +5,7 @@ Device specific handeling for NetBox to Zabbix
""" """
from os import sys from os import sys
from re import search from re import search
from copy import deepcopy
from logging import getLogger from logging import getLogger
from zabbix_utils import APIRequestError from zabbix_utils import APIRequestError
from modules.exceptions import (SyncInventoryError, TemplateError, SyncExternalError, from modules.exceptions import (SyncInventoryError, TemplateError, SyncExternalError,
@ -22,6 +23,7 @@ try:
inventory_sync, inventory_sync,
inventory_mode, inventory_mode,
device_inventory_map, device_inventory_map,
usermacro_sync,
device_usermacro_map device_usermacro_map
) )
except ModuleNotFoundError: except ModuleNotFoundError:
@ -372,17 +374,12 @@ class PhysicalDevice():
raise SyncInventoryError(message) from e raise SyncInventoryError(message) from e
def setUsermacros(self): def setUsermacros(self):
try: # Initiate Usermacros class
# Initiate interface class
macros = ZabbixUsermacros(self.nb.config_context, self._usermacro_map()) macros = ZabbixUsermacros(self.nb.config_context, self._usermacro_map())
if macros.sync == False: if macros.sync == False:
return {} return []
else: else:
return [{'macro': '{$USERMACRO}', 'value': '123', 'type': 0, 'description': 'just a test'}] return macros.generate()
except UsermacroError as e:
message = f"{self.name}: {e}"
self.logger.warning(message)
raise UsermacroError(message) from e
def setProxy(self, proxy_list): def setProxy(self, proxy_list):
""" """
@ -574,7 +571,6 @@ class PhysicalDevice():
selectInventory=list(self._inventory_map().values()), selectInventory=list(self._inventory_map().values()),
selectMacros=["macro","value","type","description"] selectMacros=["macro","value","type","description"]
) )
pprint(host)
if len(host) > 1: if len(host) > 1:
e = (f"Got {len(host)} results for Zabbix hosts " e = (f"Got {len(host)} results for Zabbix hosts "
f"with ID {self.zabbix_id} - hostname {self.name}.") f"with ID {self.zabbix_id} - hostname {self.name}.")
@ -696,6 +692,24 @@ class PhysicalDevice():
self.logger.warning(f"Host {self.name}: inventory OUT of sync.") self.logger.warning(f"Host {self.name}: inventory OUT of sync.")
self.updateZabbixHost(inventory=self.inventory) self.updateZabbixHost(inventory=self.inventory)
# Check host usermacros
if usermacro_sync:
macros_filtered = []
self.usermacros = self.setUsermacros()
# Do not re-sync secret usermacros unless sync is set to 'full'
if not str(usermacro_sync).lower() == "full":
for m in deepcopy(self.usermacros):
if m['type'] == str(1):
# Remove the value as the api doesn't return it
# this will allow us to only update usermacros that don't exist
m.pop('value')
macros_filtered.append(m)
if host['macros'] == self.usermacros or host['macros'] == macros_filtered:
self.logger.debug(f"Host {self.name}: usermacros in-sync.")
else:
self.logger.warning(f"Host {self.name}: usermacros OUT of sync.")
self.updateZabbixHost(macros=self.usermacros)
# If only 1 interface has been found # If only 1 interface has been found
# pylint: disable=too-many-nested-blocks # pylint: disable=too-many-nested-blocks
if len(host['interfaces']) == 1: if len(host['interfaces']) == 1:

View File

@ -2,11 +2,11 @@
""" """
All of the Zabbix Usermacro related configuration All of the Zabbix Usermacro related configuration
""" """
from re import match
from logging import getLogger from logging import getLogger
from zabbix_utils import APIRequestError from zabbix_utils import APIRequestError
from modules.exceptions import UsermacroError from modules.exceptions import UsermacroError
from pprint import pprint from pprint import pprint
try: try:
@ -37,11 +37,54 @@ class ZabbixUsermacros():
return self.__repr__() return self.__repr__()
def _setConfig(self): def _setConfig(self):
if str(usermacro_sync) == "full": if str(usermacro_sync).lower() == "full":
self.sync = True self.sync = True
self.force_sync = True self.force_sync = True
elif usermacro_sync: elif usermacro_sync:
self.sync = True self.sync = True
return True return True
def validate_macro(self, macro_name):
pattern = '\{\$[A-Z0-9\._]*(\:.*)?\}'
return match(pattern, macro_name)
def render_macro(self, macro_name, macro_properties):
macro={}
macrotypes={'text': 0, 'secret': 1, 'vault': 2}
if self.validate_macro(macro_name):
macro['macro'] = str(macro_name)
if isinstance(macro_properties, dict):
if not 'value' in macro_properties:
self.logger.error(f'Usermacro {macro_name} has no value, skipping.')
return False
else:
macro['value'] = macro_properties['value']
if 'type' in macro_properties and macro_properties['type'].lower() in macrotypes:
macro['type'] = str(macrotypes[macro_properties['type']])
else:
macro['type'] = str(0)
if 'description' in macro_properties and isinstance(macro_properties['description'], str):
macro['description'] = macro_properties['description']
else:
macro['description'] = ""
elif isinstance(macro_properties, str):
macro['value'] = macro_properties
macro['type'] = str(0)
macro['description'] = ""
else:
self.logger.error(f'Usermacro {macro_name} is not a valid usermacro name, skipping.')
return False
return macro
def generate(self):
macros=[]
if "zabbix" in self.context and "usermacros" in self.context['zabbix']:
for macro, properties in self.context['zabbix']['usermacros'].items():
m = self.render_macro(macro, properties)
pprint(m)
if m:
macros.append(m)
return macros