From 811c62a2a7bafe6d5a1b02aa9d5707981f77d2c6 Mon Sep 17 00:00:00 2001 From: pederhan Date: Fri, 27 Oct 2023 11:35:26 +0200 Subject: [PATCH] Check version before creating template groups --- README.md | 4 +- config.sample.toml | 2 +- zabbix_auto_config/models.py | 27 +++++++++++-- zabbix_auto_config/processing.py | 67 ++++++++++++++++++-------------- 4 files changed, 65 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index d089214..923c406 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # About -Zabbix-auto-config is an utility that aims to automatically configure hosts, host groups, host inventories and templates in the monitoring software [Zabbix](https://www.zabbix.com/). +Zabbix-auto-config is an utility that aims to automatically configure hosts, host groups, host inventories, template groups and templates in the monitoring software [Zabbix](https://www.zabbix.com/). Note: This is only tested with Zabbix 5.0 LTS. @@ -82,7 +82,7 @@ def collect(*args: Any, **kwargs: Any) -> List[Host]: if __name__ == "__main__": for host in collect(): - print(host.json()) + print(host.model_dump_json()) EOF cat > path/to/host_modifier_dir/mod.py << EOF from zabbix_auto_config.models import Host diff --git a/config.sample.toml b/config.sample.toml index 4be6512..e2ab418 100644 --- a/config.sample.toml +++ b/config.sample.toml @@ -21,7 +21,7 @@ managed_inventory = ["location"] #hostgroup_source_prefix = "Source-" #hostgroup_importance_prefix = "Importance-" #extra_siteadmin_hostgroup_prefixes = [] -templategroup_prefix = "Templates-" +#templategroup_prefix = "Templates-" [source_collectors.mysource] module_name = "mysource" diff --git a/zabbix_auto_config/models.py b/zabbix_auto_config/models.py index 6d6acde..7be9390 100644 --- a/zabbix_auto_config/models.py +++ b/zabbix_auto_config/models.py @@ -1,6 +1,8 @@ +from __future__ import annotations + import logging from pathlib import Path -from typing import Any, Dict, List, Optional, Set, Tuple, Union +from typing import Any, Dict, List, NamedTuple, Optional, Set, Tuple, Union from pydantic import BaseModel from pydantic import BaseModel as PydanticBaseModel @@ -40,6 +42,7 @@ class ZabbixSettings(ConfigBaseModel): username: str password: str dryrun: bool + create_templategroups: bool = True tags_prefix: str = "zac_" managed_inventory: List[str] = [] @@ -55,12 +58,13 @@ class ZabbixSettings(ConfigBaseModel): # Prefixes for extra host groups to create based on the host groups # in the siteadmin mapping. - # e.g. Siteadmin-foo -> Templates-foo if list is ["Templates-"] + # e.g. Siteadmin-foo -> Secondary-foo if list is ["Secondary-"] # The groups must have prefixes separated by a hyphen (-) in order # to replace them with any of these prefixes. - # These groups are not managed by ZAC beyond creating them. + # These groups are not managed by ZAC beyond their creation. extra_siteadmin_hostgroup_prefixes: Set[str] = set() + class ZacSettings(ConfigBaseModel): source_collector_dir: str host_modifier_dir: str @@ -215,3 +219,20 @@ def merge(self, other: "Host") -> None: self.proxy_pattern = sorted(list(proxy_patterns))[0] elif len(proxy_patterns) == 1: self.proxy_pattern = proxy_patterns.pop() + + +class ZabbixVersion(NamedTuple): + major: int + minor: int + patch: int + + @classmethod + def from_version_string(cls, version_string: str) -> ZabbixVersion: + parts = version_string.split(".") + if len(parts) != 3: + raise ValueError(f"Cannot parse Zabbix version string: {version_string}") + return cls( + major=int(parts[0]), + minor=int(parts[1]), + patch=int(parts[2]), + ) diff --git a/zabbix_auto_config/processing.py b/zabbix_auto_config/processing.py index a2974ab..7c3ad68 100644 --- a/zabbix_auto_config/processing.py +++ b/zabbix_auto_config/processing.py @@ -581,6 +581,9 @@ def __init__(self, name, state, db_uri, zabbix_config: models.ZabbixSettings): os.path.join(self.config.map_dir, "siteadmin_hostgroup_map.txt") ) + ver = self.api.apiinfo.version() + self.zabbix_version = models.ZabbixVersion.from_version_string(ver) + def work(self): start_time = time.time() logging.info("Zabbix update starting") @@ -889,8 +892,8 @@ def clear_templates(self, templates, host): logging.debug("DRYRUN: Clearing templates on host: '%s'", host["host"]) def set_templates(self, templates, host): - logging.debug("Setting templates on host: '%s'", host["host"]) if not self.config.dryrun: + logging.debug("Setting templates on host: '%s'", host["host"]) try: templates = [{"templateid": template_id} for _, template_id in templates.items()] self.api.host.update(hostid=host["hostid"], templates=templates) @@ -970,24 +973,27 @@ def set_hostgroups(self, hostgroups, host): else: logging.debug("DRYRUN: Setting hostgroups on host: '%s'", host["host"]) - def create_hostgroup(self, hostgroup_name): - if not self.config.dryrun: - logging.debug("Creating hostgroup: '%s'", hostgroup_name) - try: - result = self.api.hostgroup.create(name=hostgroup_name) - return result["groupids"][0] - except pyzabbix.ZabbixAPIException as e: - logging.error("Error when creating hostgroups '%s': %s", hostgroup_name, e.args) - else: + def create_hostgroup(self, hostgroup_name: str) -> Optional[str]: + if self.config.dryrun: logging.debug("DRYRUN: Creating hostgroup: '%s'", hostgroup_name) - return "-1" + return None + + logging.debug("Creating hostgroup: '%s'", hostgroup_name) + try: + result = self.api.hostgroup.create(name=hostgroup_name) + return result["groupids"][0] + except pyzabbix.ZabbixAPIException as e: + logging.error( + "Error when creating hostgroups '%s': %s", hostgroup_name, e.args + ) + return None def create_extra_hostgroups( self, existing_hostgroups: List[Dict[str, str]] ) -> None: """Creates additonal host groups based on the prefixes specified in the config file. These host groups are not assigned hosts by ZAC.""" - hostgroup_names = [h["name"] for h in existing_hostgroups] + hostgroup_names = set(h["name"] for h in existing_hostgroups) for prefix in self.config.extra_siteadmin_hostgroup_prefixes: mapping = utils.mapping_values_with_prefix( @@ -1001,30 +1007,33 @@ def create_extra_hostgroups( self.create_hostgroup(hostgroup) def create_templategroup(self, templategroup_name: str) -> Optional[str]: - if not self.config.dryrun: - logging.debug("Creating template group: '%s'", templategroup_name) - try: - result = self.api.templategroup.create(name=templategroup_name) - return result["groupids"][0] - except pyzabbix.ZabbixAPIException as e: - logging.error( - "Error when creating template group '%s': %s", - templategroup_name, - e.args, - ) - return None - else: + if self.config.dryrun: logging.debug("DRYRUN: Creating template group: '%s'", templategroup_name) - return "-1" + return None + + logging.debug("Creating template group: '%s'", templategroup_name) + try: + result = self.api.templategroup.create(name=templategroup_name) + return result["groupids"][0] + except pyzabbix.ZabbixAPIException as e: + logging.error( + "Error when creating template group '%s': %s", + templategroup_name, + e.args, + ) + return None def create_templategroups(self) -> None: - """>=6.4. ONLY: Creates template groups for each host group in + """>=6.4 ONLY: Creates template groups for each host group in the mapping file.""" + if self.zabbix_version < (6, 4, 0) or not self.config.create_templategroups: + return + tgroups = self.api.templategroup.get(output=["name", "groupid"]) - templategroup_names = [h["name"] for h in tgroups] + templategroup_names = set(h["name"] for h in tgroups) mapping = utils.mapping_values_with_prefix( - self.siteadmin_hostgroup_map, # this is copied in the function + self.siteadmin_hostgroup_map, prefix=self.config.templategroup_prefix, ) for templategroups in mapping.values():