#jinja2: trim_blocks: True, lstrip_blocks: True {% macro render_dstnat_rule(ifaces, proto, port, target_ip, item_name) %} {% set lines = [] %} {% set active_ifaces = ifaces if (ifaces is iterable and ifaces is not string) else [ifaces] %} {% for current_iface in active_ifaces %} {% set comment_str = ' comment "' ~ current_iface ~ ' -> ' ~ item_name ~ '"' %} {% set rule_line = 'iifname "' ~ current_iface ~ '" ' ~ proto ~ ' dport ' ~ port ~ ' counter dnat ip to ' ~ target_ip ~ ':' ~ port ~ comment_str %} {% set _ = lines.append(rule_line) %} {% endfor %} {{ lines | join('\n') }} {% endmacro %} {% filter regex_replace('\n[ \t]*\n+', '\n') %} {% for item in groups[nft_managed_group] | sort %} {% set client = hostvars[item] %} {% if 'nft_dst' in client and client.nft_dst is not none %} {% set target_ip = client.container_ip | default(client.ansible_host | default(item)) %} {% set raw_expose = client.nft_dst %} {% set exposes = raw_expose if (raw_expose is iterable and raw_expose is not string and raw_expose is not mapping) else [raw_expose] %} {% for expose in exposes %} {% set protos = expose.proto if (expose.proto is defined and expose.proto is iterable and expose.proto is not string) else [expose.proto | default('tcp')] %} {% set ports = expose.port if (expose.port is defined and expose.port is iterable and expose.port is not string) else [expose.port] %} {% set ifaces = expose.iface %} {% for p in protos | sort %} {% for port in ports | sort %} {{ render_dstnat_rule(ifaces, p, port, target_ip, item) }} {% endfor %} {% endfor %} {% endfor %} {% endif %} {% endfor %} {% endfilter %}