From d51be05d834881044e4bebcba0a40a38d917b1bd Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Sat, 17 May 2025 10:48:58 +0200 Subject: [PATCH] Added recursiv dependency resolution --- filter_plugins/group_domain_filters.py | 69 +++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/filter_plugins/group_domain_filters.py b/filter_plugins/group_domain_filters.py index 9b2f1a88..99d00bba 100644 --- a/filter_plugins/group_domain_filters.py +++ b/filter_plugins/group_domain_filters.py @@ -1,8 +1,15 @@ +import os +import yaml from ansible.errors import AnsibleFilterError class FilterModule(object): """ - Custom filters for conditional domain assignments + Custom filters for conditional domain assignments, handling both direct group matches + and recursive role dependency resolution. + + Determines if a given application_id (domain_key) should have its domain added by checking: + - If domain_key is explicitly listed in group_names, or + - If domain_key matches any application_id of roles reachable from active groups via dependencies. """ def filters(self): @@ -13,17 +20,67 @@ class FilterModule(object): @staticmethod def add_domain_if_group(domains_dict, domain_key, domain_value, group_names): """ - Add {domain_key: domain_value} to domains_dict - only if domain_key is in group_names. + Add {domain_key: domain_value} to domains_dict if either: + 1) domain_key is in group_names (direct inclusion), or + 2) domain_key is among collected application_id values of roles + reachable from any group in group_names via recursive dependencies. - Usage in Jinja: - {{ {} - | add_domain_if_group('akaunting', 'akaunting.' ~ primary_domain, group_names) }} + Parameters: + domains_dict: existing dict of domains + domain_key: name of the application to check + domain_value: domain or dict/list of domains to assign + group_names: list of active group (role/application) names """ try: result = dict(domains_dict) + + # Direct group match: if the application name itself is in group_names if domain_key in group_names: result[domain_key] = domain_value + return result + + # Setup roles directory path + plugin_dir = os.path.dirname(__file__) + project_root = os.path.abspath(os.path.join(plugin_dir, '..')) + roles_dir = os.path.join(project_root, 'roles') + + # Collect all roles reachable from the active groups + def collect_roles(role_name, collected): + if role_name in collected: + return + collected.add(role_name) + meta_path = os.path.join(roles_dir, role_name, 'meta', 'main.yml') + if os.path.isfile(meta_path): + with open(meta_path) as f: + meta = yaml.safe_load(f) or {} + for dep in meta.get('dependencies', []): + if isinstance(dep, str): + dep_name = dep + elif isinstance(dep, dict): + dep_name = dep.get('role') or dep.get('name') + else: + continue + collect_roles(dep_name, collected) + + included_roles = set() + for grp in group_names: + collect_roles(grp, included_roles) + + # Gather application_ids from each included role + app_ids = set() + for role in included_roles: + vars_main = os.path.join(roles_dir, role, 'vars', 'main.yml') + if os.path.isfile(vars_main): + with open(vars_main) as f: + vars_data = yaml.safe_load(f) or {} + app_id = vars_data.get('application_id') + if app_id: + app_ids.add(app_id) + + # Indirect inclusion: match by application_id + if domain_key in app_ids: + result[domain_key] = domain_value + return result except Exception as exc: raise AnsibleFilterError(f"add_domain_if_group failed: {exc}")