From 8e8da8d49f86e4eddf8108ffdd00aa788ea81708 Mon Sep 17 00:00:00 2001 From: Donien <88634789+Donien@users.noreply.github.com> Date: Thu, 16 Jan 2025 18:31:55 +0100 Subject: [PATCH 1/7] Initial draft commit --- plugins/action/icinga2_zones_conf.py | 182 +++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 plugins/action/icinga2_zones_conf.py diff --git a/plugins/action/icinga2_zones_conf.py b/plugins/action/icinga2_zones_conf.py new file mode 100644 index 00000000..d9ea8b68 --- /dev/null +++ b/plugins/action/icinga2_zones_conf.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- + +# Make coding more python3-ish, this is required for contributions to Ansible +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.plugins.action import ActionBase +from datetime import datetime +from ansible.utils.vars import merge_hash + + + +def get_sub_hierarchy(hierarchy, name, groups, parent=None): + # Traverses a nested dictionary in search of a specific key (name) + # If found, returns sub-dictionary as value for key of name "name" + # If recursion was needed, result will be a dict with key equal to own parent key + # E.g. + # dict={ "master": { "europe": { "germany": { + # "berlin": None, + # "nuremberg": None + # }, + # "france": { + # "paris": None + # }, + # }, + # "usa": None + # } + # } + # Name="master" -> Returned: {'master': {'europe': {'germany': {'berlin': None, 'nuremberg': None}, 'france': {'paris': None}}, 'usa': None}} + # Name="germany" -> Returned: {'europe': {'germany': {'berlin': None, 'nuremberg': None}}} + + + top_level_keys = list(hierarchy.keys()) + + # Check if inventory name or any group name matches top level keys of dictionary + for possible_name in [name] + groups: + if possible_name in top_level_keys: + name = possible_name + + # If name is toplevel key, e.g. master + if name in top_level_keys: + if parent: + # Only return the relevant sub-tree of the hierarchy + hierarchy = {parent: {name: hierarchy[name]}} + return hierarchy + + # If name is subkey of toplevel key + for top_level_key in top_level_keys: + sub_hierarchy = hierarchy[top_level_key] + if isinstance(sub_hierarchy, dict): + new_hierarchy = get_sub_hierarchy(sub_hierarchy, name, groups, top_level_key) + if new_hierarchy: + return new_hierarchy + + # Return empty dict if name not found anywhere within hierarchy + return dict() + + + +def get_best_host_attr(inventory, name): + for host_option in [ + "ansible_fqdn", + "ansible_hostname", + "inventory_hostname", + ]: + if host_option in inventory["hostvars"][name]: + return inventory["hostvars"][name][host_option] + # Return inventory hostname by default + return name + + + +def get_endpoints_from_zones(zones, name, inventory): + # Return emtpy list if no zones are given + if not zones: + return list() + + endpoints = list() + + own_zone = [zone for zone in zones if name in zone["endpoints"]][0] + own_zone_name = own_zone["name"] + own_parent_zone_name = own_zone["parent"] if "parent" in own_zone else None + + for zone in zones: + for endpoint_name in zone["endpoints"]: + endpoint = dict() + endpoint["name"] = endpoint_name + + # If own parent + if zone["name"] == own_parent_zone_name: + # If connection to own parent + endpoint["host"] = get_best_host_attr(inventory, endpoint_name) + elif zone["name"] == own_zone_name and endpoint_name != name: + # If connection to HA partner + endpoint["host"] = get_best_host_attr(inventory, endpoint_name) + elif "parent" in zone and zone["parent"] == own_zone_name: + # If connection to direct children + endpoint["host"] = get_best_host_attr(inventory, endpoint_name) + + endpoints.append(endpoint) + + return endpoints + + + +def get_zones_from_hierarchy(hierarchy, groups, parent=None): + if not hierarchy: + return list() + + zone_list = list() + zone_name = list(hierarchy.keys())[0] + + this_zone = dict() + this_zone["name"] = zone_name + + if parent: + this_zone["parent"] = parent + + + # get_endpoints(name, inventory, groups) + endpoints = list() + if zone_name in groups: + for host in groups[zone_name]: + endpoints.append(host) + else: + endpoints.append(zone_name) + + this_zone["endpoints"] = endpoints + zone_list.append(this_zone) + + + if isinstance(hierarchy[zone_name], dict): + for key, value in hierarchy[zone_name].items(): + # Recursion step: combine current list (single zone) with each child zone + zone_list += get_zones_from_hierarchy({key: value}, groups, parent=zone_name) + + return zone_list + + + +class ActionModule(ActionBase): + def run(self, tmp=None, task_vars=None): + result = super(ActionModule, self).run(tmp, task_vars) + del tmp + + module_args = self._task.args.copy() + #module_return = self._execute_module( + # module_name="setup", + # module_args=module_args, + # task_vars=task_vars, tmp=tmp + #) + + #### Variables needed for processing + hierarchy = merge_hash(module_args.pop("hierarchy", False), dict()) + ansible_inventory_hostname = task_vars["inventory_hostname"] + ansible_groups = task_vars["groups"] + ansible_host_groups = list(task_vars["group_names"]) + + if "all" in ansible_host_groups: + ansible_host_groups.remove("all") + if "ungrouped" in ansible_host_groups: + ansible_host_groups.remove("ungrouped") + + + # Get sub portion of the given hierarchy starting at own parent, or self if no parent + sub_hierarchy = get_sub_hierarchy(hierarchy, ansible_inventory_hostname, ansible_host_groups) + + # Get all zones this node needs to know (parent and all (sub-)children) + icinga2_zones = get_zones_from_hierarchy(sub_hierarchy, ansible_groups) + + # Get all endpoints for each known zone + icinga2_endpoints = get_endpoints_from_zones(icinga2_zones, ansible_inventory_hostname, task_vars) + + # TO BE DONE: Global zones + # get them from another input instead of hierarchy (e.g. global_zones: ['director-global']) + # ... + + # Return results + result["icinga2_zones"] = icinga2_zones + result["icinga2_endpoints"] = icinga2_endpoints + + return result From 7b6445ab1a800f4112fad84e158eede58cd91d91 Mon Sep 17 00:00:00 2001 From: Donien <88634789+Donien@users.noreply.github.com> Date: Fri, 17 Jan 2025 22:27:57 +0100 Subject: [PATCH 2/7] Add global zones, tune endpoints --- plugins/action/icinga2_zones_conf.py | 48 ++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/plugins/action/icinga2_zones_conf.py b/plugins/action/icinga2_zones_conf.py index d9ea8b68..f0783a52 100644 --- a/plugins/action/icinga2_zones_conf.py +++ b/plugins/action/icinga2_zones_conf.py @@ -57,16 +57,26 @@ def get_sub_hierarchy(hierarchy, name, groups, parent=None): -def get_best_host_attr(inventory, name): +def get_best_endpoint_attrs(inventory, name, host_options=list(), port_variable=None): + # Return inventory hostname and port 5665 by default + attrs = dict() + attrs["host"] = name + attrs["port"] = "5665" + for host_option in [ - "ansible_fqdn", - "ansible_hostname", + #"ansible_fqdn", + "ansible_host", "inventory_hostname", ]: if host_option in inventory["hostvars"][name]: - return inventory["hostvars"][name][host_option] - # Return inventory hostname by default - return name + attrs["host"] = inventory["hostvars"][name][host_option] + break + + # WIP + if port_variable in inventory["hostvars"][name]: + attrs["port"] = inventory["hostvars"][name][port_variable] + + return attrs @@ -86,16 +96,17 @@ def get_endpoints_from_zones(zones, name, inventory): endpoint = dict() endpoint["name"] = endpoint_name - # If own parent - if zone["name"] == own_parent_zone_name: + if ( # If connection to own parent - endpoint["host"] = get_best_host_attr(inventory, endpoint_name) - elif zone["name"] == own_zone_name and endpoint_name != name: + (zone["name"] == own_parent_zone_name) or + # If connection to HA partner - endpoint["host"] = get_best_host_attr(inventory, endpoint_name) - elif "parent" in zone and zone["parent"] == own_zone_name: + (zone["name"] == own_zone_name and endpoint_name != name) or + # If connection to direct children - endpoint["host"] = get_best_host_attr(inventory, endpoint_name) + ("parent" in zone and zone["parent"] == own_zone_name) + ): + endpoint.update(get_best_endpoint_attrs(inventory, endpoint_name)) endpoints.append(endpoint) @@ -151,7 +162,8 @@ def run(self, tmp=None, task_vars=None): #) #### Variables needed for processing - hierarchy = merge_hash(module_args.pop("hierarchy", False), dict()) + hierarchy = merge_hash(module_args.pop("hierarchy", dict()), dict()) + global_zones = module_args.pop("global_zones", list()) ansible_inventory_hostname = task_vars["inventory_hostname"] ansible_groups = task_vars["groups"] ansible_host_groups = list(task_vars["group_names"]) @@ -171,6 +183,14 @@ def run(self, tmp=None, task_vars=None): # Get all endpoints for each known zone icinga2_endpoints = get_endpoints_from_zones(icinga2_zones, ansible_inventory_hostname, task_vars) + # Get all global zones + for zone in global_zones: + zone_object = { + "name": zone, + "global": True + } + icinga2_zones.append(zone_object) + # TO BE DONE: Global zones # get them from another input instead of hierarchy (e.g. global_zones: ['director-global']) # ... From e5ef25fa21efeade3d9f645eb764b4ee6b513f86 Mon Sep 17 00:00:00 2001 From: Donien <88634789+Donien@users.noreply.github.com> Date: Fri, 17 Jan 2025 22:28:23 +0100 Subject: [PATCH 3/7] Change api feature to work with new module --- roles/icinga2/tasks/features/api.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/roles/icinga2/tasks/features/api.yml b/roles/icinga2/tasks/features/api.yml index 9837b98e..3074392b 100644 --- a/roles/icinga2/tasks/features/api.yml +++ b/roles/icinga2/tasks/features/api.yml @@ -15,6 +15,27 @@ icinga2_ssl_remote_source: "{{ icinga2_dict_features.api.ssl_remote_source | default(false) }}" icinga2_ticket_salt: "{{ icinga2_dict_features.api.ticket_salt | default(omit) }}" +- name: Combine global zones into list + ansible.builtin.set_fact: + icinga2_global_zones: "{{ (icinga2_global_zones | default([])) + (icinga2_zones | selectattr('global', 'true') | map(attribute='name')) }}" + +- name: Build zones and endpoints from inventory + when: + - icinga2_zone_hierarchy is defined + icinga.icinga.icinga2_zones_conf: + hierarchy: "{{ icinga2_zone_hierarchy | default({}) }}" + global_zones: "{{ icinga2_global_zones }}" + register: "_zones_conf" + +- name: Overwrite some variables + when: + - icinga2_zone_hierarchy is defined + ansible.builtin.set_fact: + icinga2_zones: "{{ _zones_conf.icinga2_zones | default(icinga2_zones) }}" + icinga2_endpoints: "{{ _zones_conf.icinga2_endpoints | default(icinga2_endpoints) }}" + icinga2_ca_host: "{{ (_zones_conf.icinga2_endpoints | first).host | default('none') }}" + icinga2_ca_host_port: "{{ (_zones_conf.icinga2_zones | first).port | default(omit) }}" + - assert: that: ((icinga2_ssl_cacert is defined and icinga2_ssl_cert is defined and icinga2_ssl_key is defined) or (icinga2_ssl_cacert is undefined and icinga2_ssl_cert is undefined and icinga2_ssl_key is undefined and icinga2_ca_host is defined)) fail_msg: ca_host is mandatory or ssl_cacert/cert/key have to be set at the same time From 554287ea265f608b1e52cb8d6cbc33e235021656 Mon Sep 17 00:00:00 2001 From: Donien <88634789+Donien@users.noreply.github.com> Date: Mon, 20 Jan 2025 16:26:32 +0100 Subject: [PATCH 4/7] Add ability to use variable to set host attribute --- plugins/action/icinga2_zones_conf.py | 54 +++++++++++++++++++++------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/plugins/action/icinga2_zones_conf.py b/plugins/action/icinga2_zones_conf.py index f0783a52..13902bfd 100644 --- a/plugins/action/icinga2_zones_conf.py +++ b/plugins/action/icinga2_zones_conf.py @@ -63,7 +63,7 @@ def get_best_endpoint_attrs(inventory, name, host_options=list(), port_variable= attrs["host"] = name attrs["port"] = "5665" - for host_option in [ + for host_option in host_options + [ #"ansible_fqdn", "ansible_host", "inventory_hostname", @@ -80,7 +80,7 @@ def get_best_endpoint_attrs(inventory, name, host_options=list(), port_variable= -def get_endpoints_from_zones(zones, name, inventory): +def get_endpoints_from_zones(zones, name, inventory, upper_host_options=list(), middle_host_options=list(), lower_host_options=list(), port_variable=None): # Return emtpy list if no zones are given if not zones: return list() @@ -96,17 +96,26 @@ def get_endpoints_from_zones(zones, name, inventory): endpoint = dict() endpoint["name"] = endpoint_name - if ( - # If connection to own parent - (zone["name"] == own_parent_zone_name) or + # If connection to own parent + if zone["name"] == own_parent_zone_name: + host_attributes = get_best_endpoint_attrs(inventory, endpoint_name, upper_host_options, port_variable) - # If connection to HA partner - (zone["name"] == own_zone_name and endpoint_name != name) or + # If connection to HA partner + elif zone["name"] == own_zone_name and endpoint_name != name: + host_attributes = get_best_endpoint_attrs(inventory, endpoint_name, middle_host_options, port_variable) - # If connection to direct children - ("parent" in zone and zone["parent"] == own_zone_name) - ): - endpoint.update(get_best_endpoint_attrs(inventory, endpoint_name)) + # If connection to direct children + elif "parent" in zone and zone["parent"] == own_zone_name: + host_attributes = get_best_endpoint_attrs(inventory, endpoint_name, lower_host_options, port_variable) + print("HIER", endpoint_name, name) + print(host_attributes) + + # If no direct connection needed + else: + host_attributes = None + + if host_attributes: + endpoint.update(host_attributes) endpoints.append(endpoint) @@ -164,6 +173,20 @@ def run(self, tmp=None, task_vars=None): #### Variables needed for processing hierarchy = merge_hash(module_args.pop("hierarchy", dict()), dict()) global_zones = module_args.pop("global_zones", list()) + + # Get connection variables for host attribute + upper_host_variables = module_args.pop("upper", list()) + if isinstance(upper_host_variables, str): + upper_host_variables = [upper_host_variables] + + middle_host_variables = module_args.pop("middle", list()) + if isinstance(middle_host_variables, str): + middle_host_variables = [middle_host_variables] + + lower_host_variables = module_args.pop("lower", list()) + if isinstance(lower_host_variables, str): + lower_host_variables = [lower_host_variables] + ansible_inventory_hostname = task_vars["inventory_hostname"] ansible_groups = task_vars["groups"] ansible_host_groups = list(task_vars["group_names"]) @@ -181,7 +204,14 @@ def run(self, tmp=None, task_vars=None): icinga2_zones = get_zones_from_hierarchy(sub_hierarchy, ansible_groups) # Get all endpoints for each known zone - icinga2_endpoints = get_endpoints_from_zones(icinga2_zones, ansible_inventory_hostname, task_vars) + icinga2_endpoints = get_endpoints_from_zones( + icinga2_zones, + ansible_inventory_hostname, + task_vars, + upper_host_options=upper_host_variables, + middle_host_options=middle_host_variables, + lower_host_options=lower_host_variables + ) # Get all global zones for zone in global_zones: From c191a2cb28b1f3ee91ccadb85309ce8f20e2baf6 Mon Sep 17 00:00:00 2001 From: Donien <88634789+Donien@users.noreply.github.com> Date: Mon, 20 Jan 2025 16:27:35 +0100 Subject: [PATCH 5/7] Start adding unit tests --- tests/unittestpy3/test_icinga2_zones_conf.py | 103 +++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 tests/unittestpy3/test_icinga2_zones_conf.py diff --git a/tests/unittestpy3/test_icinga2_zones_conf.py b/tests/unittestpy3/test_icinga2_zones_conf.py new file mode 100644 index 00000000..f9945eab --- /dev/null +++ b/tests/unittestpy3/test_icinga2_zones_conf.py @@ -0,0 +1,103 @@ +#!/usr/bin/python3 + +import sys +sys.path.insert(0,'plugins/action') + +import unittest +from unittest.mock import patch, Mock, MagicMock, call + +import requests +from requests.exceptions import SSLError, RequestException +from ansible.parsing.yaml.objects import AnsibleSequence, AnsibleMapping + + +#from icinga2_zones_conf import ActionModule +from icinga2_zones_conf import get_sub_hierarchy +from icinga2_zones_conf import get_best_endpoint_attrs + + +class TestActionPlugin(unittest.TestCase): + def test_get_sub_hierarchy(self): + test_hierarchy = { + "master": { + "master-child": None, + "eu": { + "germany": { + "berlin": None, + "nuremberg": None + }, + "france": { + "paris": None, + } + }, + "us": { + "washington": None, + } + } + } + test_cases = [ + # name, groups, expected + ( "master", [], {"master": {"master-child": None, "eu": {"germany": {"berlin": None, "nuremberg": None}, "france": {"paris": None}}, "us": {"washington": None}}} ), + ( "master-child", [], {"master": {"master-child": None}} ), + ( "eu", [], {"master": {"eu": {"germany": {"berlin": None, "nuremberg": None}, "france": {"paris": None}}}} ), + ( "us", [], {"master": {"us": {"washington": None}}} ), + ( "germany", [], {"eu": {"germany": {"berlin": None, "nuremberg": None}}} ), + ( "berlin", [], {"germany": {"berlin": None}} ), + ( "nuremberg", [], {"germany": {"nuremberg": None}} ), + ( "washington", [], {"us": {"washington": None}} ), + + ( "master1", ["some-ansible-group", "master"], {"master": {"master-child": None, "eu": {"germany": {"berlin": None, "nuremberg": None}, "france": {"paris": None}}, "us": {"washington": None}}} ), + ( "master2", ["master"], {"master": {"master-child": None, "eu": {"germany": {"berlin": None, "nuremberg": None}, "france": {"paris": None}}, "us": {"washington": None}}} ), + ( "sat-ger-1", ["germany"], {"eu": {"germany": {"berlin": None, "nuremberg": None}}} ), + ( "sat-ger-2", ["germany"], {"eu": {"germany": {"berlin": None, "nuremberg": None}}} ), + ( "sat-ber-1", ["berlin"], {"germany": {"berlin": None}} ), + + ( "not-found", [], {} ), + + ] + + for name, groups, expected in test_cases: + self.assertEqual(get_sub_hierarchy(test_hierarchy, name, groups), expected) + + + def test_get_best_endpoint_attrs(self): + test_inventory = { + "hostvars": { + "host1": { + "inventory_hostname": "host1", + "ansible_host": "192.168.122.10", + "custom_host_var1": "10.0.1.10", + "custom_host_var2": "10.0.2.10", + }, + "host2": { + "inventory_hostname": "host2", + "ansible_host": "192.168.122.20", + "custom_host_var1": "10.0.1.20", + "custom_port_var": "6556", + }, + } + } + test_cases = [ + # name, host_options, port_variable, expected + ( "host1", [], None, {"host": "192.168.122.10", "port": "5665"} ), + ( "host1", ["custom_host_var1", "custom_host_var2"], None, {"host": "10.0.1.10", "port": "5665"} ), + ( "host1", ["custom_host_var2", "custom_host_var1"], None, {"host": "10.0.2.10", "port": "5665"} ), + ( "host1", ["var_does_not_exist"], None, {"host": "192.168.122.10", "port": "5665"} ), + ( "host1", [], "custom_port_var", {"host": "192.168.122.10", "port": "5665"} ), + + ( "host2", [], None, {"host": "192.168.122.20", "port": "5665"} ), + ( "host2", ["custom_host_var1", "custom_host_var2"], None, {"host": "10.0.1.20", "port": "5665"} ), + ( "host2", ["custom_host_var2", "custom_host_var1"], None, {"host": "10.0.1.20", "port": "5665"} ), + ( "host2", [], "custom_port_var", {"host": "192.168.122.20", "port": "6556"} ), + + ] + + for name, host_options, port_variable, expected in test_cases: + self.assertEqual(get_best_endpoint_attrs(test_inventory, name, host_options, port_variable), expected) + + + +## WIP +#def test_get_best_endpoint_attrs(inventory, name, host_options=list(), port_variable=None) +#def test_get_endpoints_from_zones(zones, name, inventory, upper_host_options=list(), middle_host_options=list(), lower_host_options=list(), port_variable=None) +#def test_get_zones_from_hierarchy(hierarchy, groups, parent=None) From 031b43f93fa8783e06adf481f45962aa30c2ea53 Mon Sep 17 00:00:00 2001 From: Donien <88634789+Donien@users.noreply.github.com> Date: Mon, 3 Feb 2025 15:41:19 +0100 Subject: [PATCH 6/7] More testing --- tests/unittestpy3/test_icinga2_zones_conf.py | 254 ++++++++++++++++++- 1 file changed, 250 insertions(+), 4 deletions(-) diff --git a/tests/unittestpy3/test_icinga2_zones_conf.py b/tests/unittestpy3/test_icinga2_zones_conf.py index f9945eab..f792520b 100644 --- a/tests/unittestpy3/test_icinga2_zones_conf.py +++ b/tests/unittestpy3/test_icinga2_zones_conf.py @@ -14,6 +14,8 @@ #from icinga2_zones_conf import ActionModule from icinga2_zones_conf import get_sub_hierarchy from icinga2_zones_conf import get_best_endpoint_attrs +from icinga2_zones_conf import get_zones_from_hierarchy +from icinga2_zones_conf import get_endpoints_from_zones class TestActionPlugin(unittest.TestCase): @@ -96,8 +98,252 @@ def test_get_best_endpoint_attrs(self): self.assertEqual(get_best_endpoint_attrs(test_inventory, name, host_options, port_variable), expected) + def test_get_zones_from_hierarchy(self): + test_cases = [ + # Hierarchy, ansible groups, expected + ( + # Hierarchy + {"master": None}, + # Ansible Groups + {"master": ["master1"]}, + # Expected list of zones + [{"name": "master", "endpoints": ["master1"]}] + ), + ( + {"master": None}, + {"master": ["master1", "master2"]}, + [{"name": "master", "endpoints": ["master1", "master2"]}] + ), + ( + {"inventory-name-master": None}, + {}, + [{"name": "inventory-name-master", "endpoints": ["inventory-name-master"]}] + ), + ( + {}, + {"master": ["master1", "master2"], "eu": ["eu1", "eu2"], "us": ["us1", "us2"]}, + [] + ), + ( + {"master": {"eu": None, "us": None}}, + {"master": ["master1", "master2"], "eu": ["eu1", "eu2"], "us": ["us1", "us2"]}, + [ + { + "name": "master", + "endpoints": [ + "master1", + "master2" + ] + }, + { + "name": "eu", + "parent": "master", + "endpoints": [ + "eu1", + "eu2" + ] + }, + { + "name": "us", + "parent": "master", + "endpoints": [ + "us1", + "us2" + ] + } + ] + ), + ( + {"master": {"eu": {"germany": {"berlin": None}}}}, + {"master": ["master1", "master2"], "eu": ["eu1", "eu2"], "germany": ["ger1", "ger2"], "berlin": ["ber1"]}, + [ + { + "name": "master", + "endpoints": [ + "master1", + "master2" + ] + }, + { + "name": "eu", + "parent": "master", + "endpoints": [ + "eu1", + "eu2" + ] + }, + { + "name": "germany", + "parent": "eu", + "endpoints": [ + "ger1", + "ger2" + ] + }, + { + "name": "berlin", + "parent": "germany", + "endpoints": [ + "ber1" + ] + } + ] + ), + ] + + for hierarchy, groups, expected in test_cases: + self.assertEqual(get_zones_from_hierarchy(hierarchy, groups), expected, "foo: " + str(get_zones_from_hierarchy(hierarchy, groups))) + + +#def get_endpoints_from_zones(zones, name, inventory, upper_host_options=list(), middle_host_options=list(), lower_host_options=list(), port_variable=None): + def test_get_endpoints_from_zones(self): + test_inventory = { + "hostvars": { + "master1": { + "possible_port": "6556", + }, + "master2": { + "possible_port": "6557", + }, + "eu1": { + }, + "ger1": { + } + } + } + test_cases = [ + # Parameter dict, expected + ( + { + "zones": [], + "name": "master1", + }, + [] + ), + ( + { + "zones": [ + { + "name": "master", + "endpoints": [ + "master1" + ] + }, + { + "name": "eu", + "endpoints": [ + "eu1" + ], + "parent": "master" + }, + { + "name": "germany", + "endpoints": [ + "ger1" + ], + "parent": "eu" + } + ], + "name": "master1", + }, + [{"name": "master1"}, {"host": "eu1", "name": "eu1", "port": "5665"}, {"name": "ger1"}] + ), + ( + { + "zones": [ + { + "name": "master", + "endpoints": [ + "master1" + ] + }, + { + "name": "eu", + "endpoints": [ + "eu1" + ], + "parent": "master" + }, + { + "name": "germany", + "endpoints": [ + "ger1" + ], + "parent": "eu" + } + ], + "name": "eu1", + }, + [ + {"host": "master1", "name": "master1", "port": "5665"}, + {"name": "eu1"}, + {"host": "ger1", "name": "ger1", "port": "5665"} + ] + ), + ( + { + "zones": [ + { + "name": "master", + "endpoints": [ + "master1" + ] + }, + { + "name": "eu", + "endpoints": [ + "eu1" + ], + "parent": "master" + }, + { + "name": "germany", + "endpoints": [ + "ger1" + ], + "parent": "eu" + } + ], + "name": "ger1", + }, + [ + {"name": "master1"}, + {"host": "eu1", "name": "eu1", "port": "5665"}, + {"name": "ger1"} + ] + ), + ( + { + "zones": [{"name": "master", "endpoints": ["master1", "master2"]}], + "name": "master1", + }, + [{"name": "master1"}, {"host": "master2", "name": "master2", "port": "5665"}] + ), + ( + { + "zones": [{"name": "master", "endpoints": ["master1", "master2"]}], + "name": "master2", + }, + [{"host": "master1", "name": "master1", "port": "5665"}, {"name": "master2"}, ] + ), + ( + { + "zones": [{"name": "master", "endpoints": ["master1", "master2"]}], + "name": "master1", + "port_variable": "possible_port", + }, + [{"name": "master1"}, {"host": "master2", "name": "master2", "port": "6557"}] + ), + ( + { + "zones": [{"name": "master", "endpoints": ["master1", "master2"]}], + "name": "master2", + "port_variable": "possible_port", + }, + [{"host": "master1", "name": "master1", "port": "6556"}, {"name": "master2"}, ] + ), + ] -## WIP -#def test_get_best_endpoint_attrs(inventory, name, host_options=list(), port_variable=None) -#def test_get_endpoints_from_zones(zones, name, inventory, upper_host_options=list(), middle_host_options=list(), lower_host_options=list(), port_variable=None) -#def test_get_zones_from_hierarchy(hierarchy, groups, parent=None) + for parameters, expected in test_cases: + self.assertEqual(get_endpoints_from_zones(inventory=test_inventory, **parameters), expected) + #self.assertEqual(get_endpoints_from_zones(zones, name, inventory, upper_host_options=list(), middle_host_options=list(), lower_host_options=list(), port_variable=None), expected) From c59f39d2356c1f9145a34d3e121aa8f8f8cce105 Mon Sep 17 00:00:00 2001 From: Donien <88634789+Donien@users.noreply.github.com> Date: Mon, 28 Jul 2025 17:41:19 +0200 Subject: [PATCH 7/7] Namespace change --- roles/icinga2/tasks/features/api.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/icinga2/tasks/features/api.yml b/roles/icinga2/tasks/features/api.yml index 3074392b..c2aa5a04 100644 --- a/roles/icinga2/tasks/features/api.yml +++ b/roles/icinga2/tasks/features/api.yml @@ -22,7 +22,7 @@ - name: Build zones and endpoints from inventory when: - icinga2_zone_hierarchy is defined - icinga.icinga.icinga2_zones_conf: + netways.icinga.icinga2_zones_conf: hierarchy: "{{ icinga2_zone_hierarchy | default({}) }}" global_zones: "{{ icinga2_global_zones }}" register: "_zones_conf"