diff --git a/modules/.device.py.swp b/modules/.device.py.swp new file mode 100644 index 0000000..62a997b Binary files /dev/null and b/modules/.device.py.swp differ diff --git a/modules/device.py b/modules/device.py index b8d038d..0d9bca9 100644 --- a/modules/device.py +++ b/modules/device.py @@ -6,6 +6,7 @@ from copy import deepcopy from logging import getLogger from os import sys from re import search +from operator import itemgetter from zabbix_utils import APIRequestError @@ -64,11 +65,11 @@ class PhysicalDevice: self.status = nb.status.label self.zabbix = zabbix self.zabbix_id = None - self.group_id = None + self.group_ids = [] self.nb_api_version = nb_version self.zbx_template_names = [] self.zbx_templates = [] - self.hostgroup = None + self.hostgroups = [] self.tenant = nb.tenant self.config_context = nb.config_context self.zbxproxy = None @@ -152,7 +153,10 @@ class PhysicalDevice: nb_regions=nb_regions, ) # Generate hostgroup based on hostgroup format - self.hostgroup = hg.generate(hg_format) + if isinstance(hg_format, list): + self.hostgroups = [hg.generate(f) for f in hg_format] + else: + self.hostgroups.append(hg.generate(hg_format)) def set_template(self, prefer_config_context, overrule_custom): """Set Template""" @@ -333,12 +337,16 @@ class PhysicalDevice: OUTPUT: True / False """ # Go through all groups - for group in groups: - if group["name"] == self.hostgroup: - self.group_id = group["groupid"] - e = f"Host {self.name}: matched group {group['name']}" - self.logger.debug(e) - return True + self.logger.debug(self.hostgroups) + + for hg in self.hostgroups: + for group in groups: + if group["name"] == hg: + self.group_ids.append({"groupid": group["groupid"]}) + e = f"Host {self.name}: matched group {group['name']}" + self.logger.debug(e) + if self.group_ids: + return True return False def cleanup(self): @@ -514,7 +522,8 @@ class PhysicalDevice: templateids.append({"templateid": template["templateid"]}) # Set interface, group and template configuration interfaces = self.setInterfaceDetails() - groups = [{"groupid": self.group_id}] + + groups = self.group_ids # Set Zabbix proxy if defined self.setProxy(proxies) # Set basic data for host creation @@ -567,25 +576,26 @@ class PhysicalDevice: """ final_data = [] # Check if the hostgroup is in a nested format and check each parent - for pos in range(len(self.hostgroup.split("/"))): - zabbix_hg = self.hostgroup.rsplit("/", pos)[0] - if self.lookupZabbixHostgroup(hostgroups, zabbix_hg): - # Hostgroup already exists - continue - # Create new group - try: - # API call to Zabbix - groupid = self.zabbix.hostgroup.create(name=zabbix_hg) - e = f"Hostgroup '{zabbix_hg}': created in Zabbix." - self.logger.info(e) - # Add group to final data - final_data.append( - {"groupid": groupid["groupids"][0], "name": zabbix_hg} - ) - except APIRequestError as e: - msg = f"Hostgroup '{zabbix_hg}': unable to create. Zabbix returned {str(e)}." - self.logger.error(msg) - raise SyncExternalError(msg) from e + for hostgroup in self.hostgroups: + for pos in range(len(hostgroup.split("/"))): + zabbix_hg = hostgroup.rsplit("/", pos)[0] + if self.lookupZabbixHostgroup(hostgroups, zabbix_hg): + # Hostgroup already exists + continue + # Create new group + try: + # API call to Zabbix + groupid = self.zabbix.hostgroup.create(name=zabbix_hg) + e = f"Hostgroup '{zabbix_hg}': created in Zabbix." + self.logger.info(e) + # Add group to final data + final_data.append( + {"groupid": groupid["groupids"][0], "name": zabbix_hg} + ) + except APIRequestError as e: + msg = f"Hostgroup '{zabbix_hg}': unable to create. Zabbix returned {str(e)}." + self.logger.error(msg) + raise SyncExternalError(msg) from e return final_data def lookupZabbixHostgroup(self, group_list, lookup_group): @@ -625,7 +635,7 @@ class PhysicalDevice: Checks if Zabbix object is still valid with NetBox parameters. """ # If group is found or if the hostgroup is nested - if not self.setZabbixGroupID(groups) or len(self.hostgroup.split("/")) > 1: + if not self.setZabbixGroupID(groups): # or len(self.hostgroups.split("/")) > 1: if create_hostgroups: # Script is allowed to create a new hostgroup new_groups = self.createZabbixHostgroup(groups) @@ -633,7 +643,7 @@ class PhysicalDevice: # Add all new groups to the list of groups groups.append(group) # check if the initial group was not already found (and this is a nested folder check) - if not self.group_id: + if not self.group_ids: # Function returns true / false but also sets GroupID if not self.setZabbixGroupID(groups) and not create_hostgroups: e = ( @@ -642,6 +652,9 @@ class PhysicalDevice: ) self.logger.warning(e) raise SyncInventoryError(e) + #if self.group_ids: + # self.group_ids.append(self.pri_group_id) + # Prepare templates and proxy config self.zbxTemplatePrepper(templates) self.setProxy(proxies) @@ -680,6 +693,7 @@ class PhysicalDevice: f"Received value: {host['host']}" ) self.updateZabbixHost(host=self.name) + # Execute check depending on wether the name is special or not if self.use_visible_name: if host["name"] == self.visible_name: @@ -709,18 +723,20 @@ class PhysicalDevice: group_dictname = "hostgroups" if str(self.zabbix.version).startswith(("6", "5")): group_dictname = "groups" - for group in host[group_dictname]: - if group["groupid"] == self.group_id: - self.logger.debug(f"Host {self.name}: hostgroup in-sync.") - break - self.logger.warning(f"Host {self.name}: hostgroup OUT of sync.") - self.updateZabbixHost(groups={"groupid": self.group_id}) + # Check if hostgroups match + if (sorted(host[group_dictname], key=itemgetter('groupid')) == + sorted(self.group_ids, key=itemgetter('groupid'))): + self.logger.debug(f"Host {self.name}: hostgroups in-sync.") + else: + self.logger.warning(f"Host {self.name}: hostgroups OUT of sync.") + self.updateZabbixHost(groups=self.group_ids) if int(host["status"]) == self.zabbix_state: self.logger.debug(f"Host {self.name}: status in-sync.") else: self.logger.warning(f"Host {self.name}: status OUT of sync.") self.updateZabbixHost(status=str(self.zabbix_state)) + # Check if a proxy has been defined if self.zbxproxy: # Check if proxy or proxy group is defined @@ -882,7 +898,7 @@ class PhysicalDevice: e = ( f"Host {self.name} has unsupported interface configuration." f" Host has total of {len(host['interfaces'])} interfaces. " - "Manual interfention required." + "Manual intervention required." ) self.logger.error(e) raise SyncInventoryError(e) diff --git a/modules/hostgroups.py b/modules/hostgroups.py index d1350bd..68b0bb1 100644 --- a/modules/hostgroups.py +++ b/modules/hostgroups.py @@ -91,7 +91,6 @@ class Hostgroup: if self.nb.cluster: format_options["cluster"] = self.nb.cluster.name format_options["cluster_type"] = self.nb.cluster.type.name - self.format_options = format_options def set_nesting( diff --git a/modules/virtual_machine.py b/modules/virtual_machine.py index 34e3394..8915832 100644 --- a/modules/virtual_machine.py +++ b/modules/virtual_machine.py @@ -58,7 +58,10 @@ class VirtualMachine(PhysicalDevice): nb_regions=nb_regions, ) # Generate hostgroup based on hostgroup format - self.hostgroup = hg.generate(hg_format) + if isinstance(hg_format, list): + self.hostgroups = [hg.generate(f) for f in hg_format] + else: + self.hostgroups.append(hg.generate(hg_format)) def set_vm_template(self): """Set Template for VMs. Overwrites default class diff --git a/netbox_zabbix_sync.py b/netbox_zabbix_sync.py index 79d8a20..08e3036 100755 --- a/netbox_zabbix_sync.py +++ b/netbox_zabbix_sync.py @@ -85,7 +85,13 @@ def main(arguments): # Set NetBox API netbox = api(netbox_host, token=netbox_token, threading=True) # Check if the provided Hostgroup layout is valid - hg_objects = hostgroup_format.split("/") + hg_objects = [] + if isinstance(hostgroup_format,list): + for l in hostgroup_format: + hg_objects = hg_objects + l.split("/") + else: + hg_objects = hostgroup_format.split("/") + hg_objects = sorted(set(hg_objects)) allowed_objects = [ "location", "role", @@ -116,7 +122,7 @@ def main(arguments): 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 '/'." + " use valid items and separate them with '/'." ) logger.error(e) raise HostgroupError(e) @@ -215,7 +221,7 @@ def main(arguments): create_hostgroups, ) continue - # Add hostgroup is config is set + # Add hostgroup if config is set if create_hostgroups: # Create new hostgroup. Potentially multiple groups if nested hostgroups = vm.createZabbixHostgroup(zabbix_groups) @@ -243,7 +249,7 @@ def main(arguments): continue 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: + if not device.hostgroups: continue device.set_inventory(nb_device) device.set_usermacros()